Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt
This commit is contained in:
commit
7340d029ae
|
@ -11,7 +11,7 @@ defaults:
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
env:
|
env:
|
||||||
BUILD_TYPE: Release
|
BUILD_TYPE: Debug
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
@ -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
|
||||||
|
|
Binary file not shown.
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -135,7 +135,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 | | | | | | | |
|
||||||
|
|
|
@ -32,6 +32,8 @@ these fields are 0 in format versions prior to 100 (0.6pre1).
|
||||||
|
|
||||||
the format versions are:
|
the format versions are:
|
||||||
|
|
||||||
|
- 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 +400,9 @@ 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
|
||||||
```
|
```
|
||||||
|
|
||||||
# patchbay
|
# patchbay
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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 "dev138"
|
||||||
#define DIV_ENGINE_VERSION 136
|
#define DIV_ENGINE_VERSION 138
|
||||||
// for imports
|
// for imports
|
||||||
#define DIV_VERSION_MOD 0xff01
|
#define DIV_VERSION_MOD 0xff01
|
||||||
#define DIV_VERSION_FC 0xff02
|
#define DIV_VERSION_FC 0xff02
|
||||||
|
|
|
@ -1716,6 +1716,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
|
||||||
|
@ -2221,6 +2224,13 @@ 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// read system flags
|
// read system flags
|
||||||
if (ds.version>=119) {
|
if (ds.version>=119) {
|
||||||
logD("reading chip flags...");
|
logD("reading chip flags...");
|
||||||
|
@ -2574,6 +2584,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();
|
||||||
|
@ -4489,6 +4525,12 @@ 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);
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -382,53 +382,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) {
|
int DivPlatformArcade::dispatch(DivCommand c) {
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
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);
|
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 (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));
|
|
||||||
}
|
|
||||||
chan[c.chan].insChanged=false;
|
chan[c.chan].insChanged=false;
|
||||||
|
|
||||||
if (c.value!=DIV_NOTE_NULL) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
|
@ -521,6 +525,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 +809,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];
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -83,6 +83,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 +103,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 +119,11 @@ class DivPlatformFMBase: public DivDispatch {
|
||||||
|
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
DivPlatformFMBase():DivDispatch(),
|
DivPlatformFMBase():
|
||||||
lastBusy(0),
|
DivDispatch(),
|
||||||
delay(0) {}
|
lastBusy(0),
|
||||||
|
delay(0),
|
||||||
|
flushFirst(false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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,23 +141,26 @@ 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()) {
|
||||||
delay=0;
|
if (--delay<0) {
|
||||||
QueuedWrite& w=writes.front();
|
delay=0;
|
||||||
if (w.addrOrVal) {
|
QueuedWrite& w=writes.front();
|
||||||
OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
|
if (w.addrOrVal) {
|
||||||
//printf("write: %x = %.2x\n",w.addr,w.val);
|
//logV("%.3x = %.2x",w.addr,w.val);
|
||||||
lastBusy=0;
|
OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
|
||||||
regPool[w.addr&0x1ff]=w.val;
|
lastBusy=0;
|
||||||
writes.pop_front();
|
regPool[w.addr&0x1ff]=w.val;
|
||||||
} else {
|
writes.pop_front();
|
||||||
lastBusy++;
|
} else {
|
||||||
if (fm.write_busy==0) {
|
lastBusy++;
|
||||||
//printf("busycounter: %d\n",lastBusy);
|
if (fm.write_busy==0) {
|
||||||
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];
|
||||||
|
@ -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) {
|
||||||
|
@ -389,6 +394,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,6 +463,10 @@ 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];
|
||||||
}
|
}
|
||||||
|
@ -556,6 +569,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: {
|
||||||
|
@ -641,49 +695,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) {
|
||||||
|
@ -866,6 +883,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;
|
||||||
|
@ -1120,16 +1142,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) {
|
||||||
chan[i].keyOn=true;
|
if (i<5 || !chan[i].dacMode) {
|
||||||
chan[i].freqChanged=true;
|
chan[i].keyOn=true;
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
immWrite(0x2b,0x00);
|
||||||
|
//rWrite(0x2a,0x00);
|
||||||
if (chan[5].dacMode) {
|
if (chan[5].dacMode) {
|
||||||
chan[5].dacSample=-1;
|
chan[5].dacSample=-1;
|
||||||
chan[6].dacSample=-1;
|
chan[6].dacSample=-1;
|
||||||
rWrite(0x2b,0x80);
|
|
||||||
}
|
}
|
||||||
immWrite(0x22,lfoValue);
|
immWrite(0x22,lfoValue);
|
||||||
|
flushFirst=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformGenesis::toggleRegisterDump(bool enable) {
|
void DivPlatformGenesis::toggleRegisterDump(bool enable) {
|
||||||
|
@ -1156,6 +1182,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);
|
||||||
|
@ -1183,6 +1213,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;
|
||||||
|
@ -1219,6 +1250,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) {
|
||||||
|
@ -1285,6 +1319,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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -746,6 +746,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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -326,6 +326,9 @@ void DivPlatformMSM6295::notifyInsChange(int ins) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformMSM6295::notifyInsDeletion(void* ins) {
|
void DivPlatformMSM6295::notifyInsDeletion(void* ins) {
|
||||||
|
for (int i=0; i<4; i++) {
|
||||||
|
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const void* DivPlatformMSM6295::getSampleMem(int index) {
|
const void* DivPlatformMSM6295::getSampleMem(int index) {
|
||||||
|
|
|
@ -689,6 +689,112 @@ void DivPlatformOPL::muteChannel(int ch, bool mute) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformOPL::commitState(int ch, DivInstrument* ins) {
|
||||||
|
if (chan[ch].insChanged) {
|
||||||
|
if (ch>melodicChans && ins->type==DIV_INS_OPL_DRUMS) {
|
||||||
|
for (int i=0; i<4; i++) {
|
||||||
|
chan[melodicChans+i+1].state.alg=ins->fm.alg;
|
||||||
|
chan[melodicChans+i+1].state.fb=ins->fm.fb;
|
||||||
|
chan[melodicChans+i+1].state.opllPreset=ins->fm.opllPreset;
|
||||||
|
chan[melodicChans+i+1].state.fixedDrums=ins->fm.fixedDrums;
|
||||||
|
chan[melodicChans+i+1].state.kickFreq=ins->fm.kickFreq;
|
||||||
|
chan[melodicChans+i+1].state.snareHatFreq=ins->fm.snareHatFreq;
|
||||||
|
chan[melodicChans+i+1].state.tomTopFreq=ins->fm.tomTopFreq;
|
||||||
|
chan[melodicChans+i+1].state.op[0]=ins->fm.op[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
chan[ch].state=ins->fm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan[ch].insChanged) {
|
||||||
|
if (ch>melodicChans && ins->type==DIV_INS_OPL_DRUMS) {
|
||||||
|
for (int i=0; i<4; i++) {
|
||||||
|
int ch=melodicChans+1+i;
|
||||||
|
unsigned char slot=slots[0][ch];
|
||||||
|
if (slot==255) continue;
|
||||||
|
unsigned short baseAddr=slotMap[slot];
|
||||||
|
DivInstrumentFM::Operator& op=chan[ch].state.op[0];
|
||||||
|
chan[ch].fourOp=false;
|
||||||
|
|
||||||
|
if (isMuted[ch]) {
|
||||||
|
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||||
|
} else {
|
||||||
|
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG_BROKEN(63-op.tl,chan[ch].outVol&0x3f,63))|(op.ksl<<6));
|
||||||
|
}
|
||||||
|
|
||||||
|
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||||
|
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
|
||||||
|
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
|
||||||
|
if (oplType>1) {
|
||||||
|
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMuted[ch]) {
|
||||||
|
oldWrites[chanMap[ch]+ADDR_LR_FB_ALG]=-1;
|
||||||
|
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1));
|
||||||
|
} else {
|
||||||
|
oldWrites[chanMap[ch]+ADDR_LR_FB_ALG]=-1;
|
||||||
|
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1)|((chan[ch].pan&15)<<4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int ops=(slots[3][ch]!=255 && chan[ch].state.ops==4 && oplType==3)?4:2;
|
||||||
|
chan[ch].fourOp=(ops==4);
|
||||||
|
if (chan[ch].fourOp) {
|
||||||
|
/*
|
||||||
|
if (chan[ch+1].active) {
|
||||||
|
chan[ch+1].keyOff=true;
|
||||||
|
chan[ch+1].keyOn=false;
|
||||||
|
chan[ch+1].active=false;
|
||||||
|
}*/
|
||||||
|
chan[ch+1].insChanged=true;
|
||||||
|
chan[ch+1].macroInit(NULL);
|
||||||
|
}
|
||||||
|
update4OpMask=true;
|
||||||
|
for (int i=0; i<ops; i++) {
|
||||||
|
unsigned char slot=slots[i][ch];
|
||||||
|
if (slot==255) continue;
|
||||||
|
unsigned short baseAddr=slotMap[slot];
|
||||||
|
DivInstrumentFM::Operator& op=chan[ch].state.op[(ops==4)?orderedOpsL[i]:i];
|
||||||
|
|
||||||
|
if (isMuted[ch]) {
|
||||||
|
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||||
|
} else {
|
||||||
|
if (KVSL(ch,i) || ch>melodicChans) {
|
||||||
|
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG_BROKEN(63-op.tl,chan[ch].outVol&0x3f,63))|(op.ksl<<6));
|
||||||
|
} else {
|
||||||
|
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||||
|
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
|
||||||
|
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
|
||||||
|
if (oplType>1) {
|
||||||
|
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMuted[ch]) {
|
||||||
|
oldWrites[chanMap[ch]+ADDR_LR_FB_ALG]=-1;
|
||||||
|
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1));
|
||||||
|
if (ops==4) {
|
||||||
|
oldWrites[chanMap[ch+1]+ADDR_LR_FB_ALG]=-1;
|
||||||
|
rWrite(chanMap[ch+1]+ADDR_LR_FB_ALG,((chan[ch].state.alg>>1)&1)|(chan[ch].state.fb<<1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
oldWrites[chanMap[ch]+ADDR_LR_FB_ALG]=-1;
|
||||||
|
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1)|((chan[ch].pan&15)<<4));
|
||||||
|
if (ops==4) {
|
||||||
|
oldWrites[chanMap[ch+1]+ADDR_LR_FB_ALG]=-1;
|
||||||
|
rWrite(chanMap[ch+1]+ADDR_LR_FB_ALG,((chan[ch].state.alg>>1)&1)|(chan[ch].state.fb<<1)|((chan[ch].pan&15)<<4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int DivPlatformOPL::dispatch(DivCommand c) {
|
int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
if (c.chan>=totalChans && c.chan!=adpcmChan) return 0;
|
if (c.chan>=totalChans && c.chan!=adpcmChan) return 0;
|
||||||
// ineffective in 4-op mode
|
// ineffective in 4-op mode
|
||||||
|
@ -771,114 +877,12 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,c.chan>melodicChans?DIV_INS_OPL_DRUMS:DIV_INS_OPL);
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,c.chan>melodicChans?DIV_INS_OPL_DRUMS:DIV_INS_OPL);
|
||||||
|
|
||||||
if (chan[c.chan].insChanged) {
|
|
||||||
if (c.chan>melodicChans && ins->type==DIV_INS_OPL_DRUMS) {
|
|
||||||
for (int i=0; i<4; i++) {
|
|
||||||
chan[melodicChans+i+1].state.alg=ins->fm.alg;
|
|
||||||
chan[melodicChans+i+1].state.fb=ins->fm.fb;
|
|
||||||
chan[melodicChans+i+1].state.opllPreset=ins->fm.opllPreset;
|
|
||||||
chan[melodicChans+i+1].state.fixedDrums=ins->fm.fixedDrums;
|
|
||||||
chan[melodicChans+i+1].state.kickFreq=ins->fm.kickFreq;
|
|
||||||
chan[melodicChans+i+1].state.snareHatFreq=ins->fm.snareHatFreq;
|
|
||||||
chan[melodicChans+i+1].state.tomTopFreq=ins->fm.tomTopFreq;
|
|
||||||
chan[melodicChans+i+1].state.op[0]=ins->fm.op[i];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
chan[c.chan].state=ins->fm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
if (chan[c.chan].insChanged) {
|
|
||||||
if (c.chan>melodicChans && ins->type==DIV_INS_OPL_DRUMS) {
|
|
||||||
for (int i=0; i<4; i++) {
|
|
||||||
int ch=melodicChans+1+i;
|
|
||||||
unsigned char slot=slots[0][ch];
|
|
||||||
if (slot==255) continue;
|
|
||||||
unsigned short baseAddr=slotMap[slot];
|
|
||||||
DivInstrumentFM::Operator& op=chan[ch].state.op[0];
|
|
||||||
chan[ch].fourOp=false;
|
|
||||||
|
|
||||||
if (isMuted[ch]) {
|
|
||||||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
|
||||||
} else {
|
|
||||||
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG_BROKEN(63-op.tl,chan[ch].outVol&0x3f,63))|(op.ksl<<6));
|
|
||||||
}
|
|
||||||
|
|
||||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
|
||||||
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
|
|
||||||
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
|
|
||||||
if (oplType>1) {
|
|
||||||
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isMuted[ch]) {
|
|
||||||
oldWrites[chanMap[ch]+ADDR_LR_FB_ALG]=-1;
|
|
||||||
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1));
|
|
||||||
} else {
|
|
||||||
oldWrites[chanMap[ch]+ADDR_LR_FB_ALG]=-1;
|
|
||||||
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1)|((chan[ch].pan&15)<<4));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
|
||||||
chan[c.chan].fourOp=(ops==4);
|
|
||||||
if (chan[c.chan].fourOp) {
|
|
||||||
/*
|
|
||||||
if (chan[c.chan+1].active) {
|
|
||||||
chan[c.chan+1].keyOff=true;
|
|
||||||
chan[c.chan+1].keyOn=false;
|
|
||||||
chan[c.chan+1].active=false;
|
|
||||||
}*/
|
|
||||||
chan[c.chan+1].insChanged=true;
|
|
||||||
chan[c.chan+1].macroInit(NULL);
|
|
||||||
}
|
|
||||||
update4OpMask=true;
|
|
||||||
for (int i=0; i<ops; i++) {
|
|
||||||
unsigned char slot=slots[i][c.chan];
|
|
||||||
if (slot==255) continue;
|
|
||||||
unsigned short baseAddr=slotMap[slot];
|
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[i]:i];
|
|
||||||
|
|
||||||
if (isMuted[c.chan]) {
|
|
||||||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
|
||||||
} else {
|
|
||||||
if (KVSL(c.chan,i) || c.chan>melodicChans) {
|
|
||||||
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG_BROKEN(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6));
|
|
||||||
} else {
|
|
||||||
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
|
||||||
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
|
|
||||||
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
|
|
||||||
if (oplType>1) {
|
|
||||||
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isMuted[c.chan]) {
|
|
||||||
oldWrites[chanMap[c.chan]+ADDR_LR_FB_ALG]=-1;
|
|
||||||
rWrite(chanMap[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&1)|(chan[c.chan].state.fb<<1));
|
|
||||||
if (ops==4) {
|
|
||||||
oldWrites[chanMap[c.chan+1]+ADDR_LR_FB_ALG]=-1;
|
|
||||||
rWrite(chanMap[c.chan+1]+ADDR_LR_FB_ALG,((chan[c.chan].state.alg>>1)&1)|(chan[c.chan].state.fb<<1));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
oldWrites[chanMap[c.chan]+ADDR_LR_FB_ALG]=-1;
|
|
||||||
rWrite(chanMap[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&1)|(chan[c.chan].state.fb<<1)|((chan[c.chan].pan&15)<<4));
|
|
||||||
if (ops==4) {
|
|
||||||
oldWrites[chanMap[c.chan+1]+ADDR_LR_FB_ALG]=-1;
|
|
||||||
rWrite(chanMap[c.chan+1]+ADDR_LR_FB_ALG,((chan[c.chan].state.alg>>1)&1)|(chan[c.chan].state.fb<<1)|((chan[c.chan].pan&15)<<4));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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) {
|
||||||
|
@ -1075,6 +1079,11 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
iface.sampleBank=sampleBank;
|
iface.sampleBank=sampleBank;
|
||||||
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_FM);
|
||||||
|
commitState(c.chan,ins);
|
||||||
|
chan[c.chan].insChanged=false;
|
||||||
|
}
|
||||||
chan[c.chan].baseFreq=(c.chan==adpcmChan)?(NOTE_ADPCMB(c.value)):(NOTE_FREQUENCY(c.value));
|
chan[c.chan].baseFreq=(c.chan==adpcmChan)?(NOTE_ADPCMB(c.value)):(NOTE_FREQUENCY(c.value));
|
||||||
chan[c.chan].note=c.value;
|
chan[c.chan].note=c.value;
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
|
@ -1640,6 +1649,9 @@ void DivPlatformOPL::notifyInsChange(int ins) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformOPL::notifyInsDeletion(void* ins) {
|
void DivPlatformOPL::notifyInsDeletion(void* ins) {
|
||||||
|
for (int i=0; i<totalChans; i++) {
|
||||||
|
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformOPL::poke(unsigned int addr, unsigned short val) {
|
void DivPlatformOPL::poke(unsigned int addr, unsigned short val) {
|
||||||
|
|
|
@ -100,6 +100,7 @@ class DivPlatformOPL: public DivDispatch {
|
||||||
int octave(int freq);
|
int octave(int freq);
|
||||||
int toFreq(int freq);
|
int toFreq(int freq);
|
||||||
double NOTE_ADPCMB(int note);
|
double NOTE_ADPCMB(int note);
|
||||||
|
void commitState(int ch, DivInstrument* ins);
|
||||||
|
|
||||||
friend void putDispatchChip(void*,int);
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "opll.h"
|
#include "opll.h"
|
||||||
#include "../engine.h"
|
#include "../engine.h"
|
||||||
|
#include "../../ta-log.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
@ -331,6 +332,55 @@ void DivPlatformOPLL::muteChannel(int ch, bool mute) {
|
||||||
isMuted[ch]=mute;
|
isMuted[ch]=mute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformOPLL::commitState(int ch, DivInstrument* ins) {
|
||||||
|
if (chan[ch].insChanged) {
|
||||||
|
chan[ch].state=ins->fm;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan[ch].insChanged) {
|
||||||
|
// update custom preset
|
||||||
|
if (chan[ch].state.opllPreset==0) {
|
||||||
|
DivInstrumentFM::Operator& mod=chan[ch].state.op[0];
|
||||||
|
DivInstrumentFM::Operator& car=chan[ch].state.op[1];
|
||||||
|
rWrite(0x00,(mod.am<<7)|(mod.vib<<6)|((mod.ssgEnv&8)<<2)|(mod.ksr<<4)|(mod.mult));
|
||||||
|
rWrite(0x01,(car.am<<7)|(car.vib<<6)|((car.ssgEnv&8)<<2)|(car.ksr<<4)|(car.mult));
|
||||||
|
rWrite(0x02,(mod.ksl<<6)|(mod.tl&63));
|
||||||
|
rWrite(0x03,(car.ksl<<6)|((chan[ch].state.fms&1)<<4)|((chan[ch].state.ams&1)<<3)|chan[ch].state.fb);
|
||||||
|
rWrite(0x04,(mod.ar<<4)|(mod.dr));
|
||||||
|
rWrite(0x05,(car.ar<<4)|(car.dr));
|
||||||
|
rWrite(0x06,(mod.sl<<4)|(mod.rr));
|
||||||
|
rWrite(0x07,(car.sl<<4)|(car.rr));
|
||||||
|
lastCustomMemory=ch;
|
||||||
|
}
|
||||||
|
if (chan[ch].state.opllPreset==16) { // compatible drums mode
|
||||||
|
if (ch>=6) {
|
||||||
|
drums=true;
|
||||||
|
immWrite(0x16,0x20);
|
||||||
|
immWrite(0x26,0x05);
|
||||||
|
immWrite(0x16,0x20);
|
||||||
|
immWrite(0x26,0x05);
|
||||||
|
immWrite(0x17,0x50);
|
||||||
|
immWrite(0x27,0x05);
|
||||||
|
immWrite(0x17,0x50);
|
||||||
|
immWrite(0x27,0x05);
|
||||||
|
immWrite(0x18,0xC0);
|
||||||
|
immWrite(0x28,0x01);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ch>=6) {
|
||||||
|
if (drums) {
|
||||||
|
drums=false;
|
||||||
|
immWrite(0x0e,0);
|
||||||
|
drumState=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ch<9) {
|
||||||
|
rWrite(0x30+ch,((15-VOL_SCALE_LOG_BROKEN(chan[ch].outVol,15-chan[ch].state.op[1].tl,15))&15)|(chan[ch].state.opllPreset<<4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int DivPlatformOPLL::dispatch(DivCommand c) {
|
int DivPlatformOPLL::dispatch(DivCommand c) {
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
|
@ -375,49 +425,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chan[c.chan].insChanged) {
|
commitState(c.chan,ins);
|
||||||
// update custom preset
|
|
||||||
if (chan[c.chan].state.opllPreset==0) {
|
|
||||||
DivInstrumentFM::Operator& mod=chan[c.chan].state.op[0];
|
|
||||||
DivInstrumentFM::Operator& car=chan[c.chan].state.op[1];
|
|
||||||
rWrite(0x00,(mod.am<<7)|(mod.vib<<6)|((mod.ssgEnv&8)<<2)|(mod.ksr<<4)|(mod.mult));
|
|
||||||
rWrite(0x01,(car.am<<7)|(car.vib<<6)|((car.ssgEnv&8)<<2)|(car.ksr<<4)|(car.mult));
|
|
||||||
rWrite(0x02,(mod.ksl<<6)|(mod.tl&63));
|
|
||||||
rWrite(0x03,(car.ksl<<6)|((chan[c.chan].state.fms&1)<<4)|((chan[c.chan].state.ams&1)<<3)|chan[c.chan].state.fb);
|
|
||||||
rWrite(0x04,(mod.ar<<4)|(mod.dr));
|
|
||||||
rWrite(0x05,(car.ar<<4)|(car.dr));
|
|
||||||
rWrite(0x06,(mod.sl<<4)|(mod.rr));
|
|
||||||
rWrite(0x07,(car.sl<<4)|(car.rr));
|
|
||||||
lastCustomMemory=c.chan;
|
|
||||||
}
|
|
||||||
if (chan[c.chan].state.opllPreset==16) { // compatible drums mode
|
|
||||||
if (c.chan>=6) {
|
|
||||||
drums=true;
|
|
||||||
immWrite(0x16,0x20);
|
|
||||||
immWrite(0x26,0x05);
|
|
||||||
immWrite(0x16,0x20);
|
|
||||||
immWrite(0x26,0x05);
|
|
||||||
immWrite(0x17,0x50);
|
|
||||||
immWrite(0x27,0x05);
|
|
||||||
immWrite(0x17,0x50);
|
|
||||||
immWrite(0x27,0x05);
|
|
||||||
immWrite(0x18,0xC0);
|
|
||||||
immWrite(0x28,0x01);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (c.chan>=6) {
|
|
||||||
if (drums) {
|
|
||||||
drums=false;
|
|
||||||
immWrite(0x0e,0);
|
|
||||||
drumState=0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (c.chan<9) {
|
|
||||||
rWrite(0x30+c.chan,((15-VOL_SCALE_LOG_BROKEN(chan[c.chan].outVol,15-chan[c.chan].state.op[1].tl,15))&15)|(chan[c.chan].state.opllPreset<<4));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
chan[c.chan].insChanged=false;
|
chan[c.chan].insChanged=false;
|
||||||
|
|
||||||
if (c.value!=DIV_NOTE_NULL) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
|
@ -541,6 +549,13 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
case DIV_CMD_LEGATO: {
|
case DIV_CMD_LEGATO: {
|
||||||
if (c.chan>=9 && !properDrums) return 0;
|
if (c.chan>=9 && !properDrums) return 0;
|
||||||
|
if (c.chan<6 || (!drums && !properDrums)) {
|
||||||
|
if (chan[c.chan].insChanged) {
|
||||||
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPLL);
|
||||||
|
commitState(c.chan,ins);
|
||||||
|
chan[c.chan].insChanged=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||||
chan[c.chan].note=c.value;
|
chan[c.chan].note=c.value;
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
|
@ -940,6 +955,9 @@ void DivPlatformOPLL::notifyInsChange(int ins) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformOPLL::notifyInsDeletion(void* ins) {
|
void DivPlatformOPLL::notifyInsDeletion(void* ins) {
|
||||||
|
for (int i=0; i<11; i++) {
|
||||||
|
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformOPLL::poke(unsigned int addr, unsigned short val) {
|
void DivPlatformOPLL::poke(unsigned int addr, unsigned short val) {
|
||||||
|
@ -958,6 +976,10 @@ void DivPlatformOPLL::setYMFM(bool use) {
|
||||||
useYMFM=use;
|
useYMFM=use;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float DivPlatformOPLL::getPostAmp() {
|
||||||
|
return 1.5f;
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformOPLL::setFlags(const DivConfig& flags) {
|
void DivPlatformOPLL::setFlags(const DivConfig& flags) {
|
||||||
int clockSel=flags.getInt("clockSel",0);
|
int clockSel=flags.getInt("clockSel",0);
|
||||||
if (clockSel==3) {
|
if (clockSel==3) {
|
||||||
|
|
|
@ -73,6 +73,7 @@ class DivPlatformOPLL: public DivDispatch {
|
||||||
|
|
||||||
int octave(int freq);
|
int octave(int freq);
|
||||||
int toFreq(int freq);
|
int toFreq(int freq);
|
||||||
|
void commitState(int ch, DivInstrument* ins);
|
||||||
|
|
||||||
friend void putDispatchChip(void*,int);
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
@ -95,6 +96,7 @@ class DivPlatformOPLL: public DivDispatch {
|
||||||
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 setVRC7(bool vrc);
|
void setVRC7(bool vrc);
|
||||||
void setProperDrums(bool pd);
|
void setProperDrums(bool pd);
|
||||||
|
|
|
@ -606,7 +606,7 @@ void DivPlatformQSound::forceIns() {
|
||||||
for (int i=0; i<19; i++) {
|
for (int i=0; i<19; i++) {
|
||||||
chan[i].insChanged=true;
|
chan[i].insChanged=true;
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
chan[i].sample=-1;
|
//chan[i].sample=-1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -645,7 +645,7 @@ bool DivPlatformQSound::keyOffAffectsArp(int ch) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformQSound::notifyInsChange(int ins) {
|
void DivPlatformQSound::notifyInsChange(int ins) {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<19; i++) {
|
||||||
if (chan[i].ins==ins) {
|
if (chan[i].ins==ins) {
|
||||||
chan[i].insChanged=true;
|
chan[i].insChanged=true;
|
||||||
}
|
}
|
||||||
|
@ -657,7 +657,7 @@ void DivPlatformQSound::notifyWaveChange(int wave) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformQSound::notifyInsDeletion(void* ins) {
|
void DivPlatformQSound::notifyInsDeletion(void* ins) {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<19; i++) {
|
||||||
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -406,6 +406,12 @@ void DivPlatformSegaPCM::notifyInsChange(int ins) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformSegaPCM::notifyInsDeletion(void* ins) {
|
||||||
|
for (int i=0; i<16; i++) {
|
||||||
|
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void* DivPlatformSegaPCM::getChanState(int ch) {
|
void* DivPlatformSegaPCM::getChanState(int ch) {
|
||||||
return &chan[ch];
|
return &chan[ch];
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,6 +89,7 @@ class DivPlatformSegaPCM: public DivDispatch {
|
||||||
void tick(bool sysTick=true);
|
void tick(bool sysTick=true);
|
||||||
void muteChannel(int ch, bool mute);
|
void muteChannel(int ch, bool mute);
|
||||||
void notifyInsChange(int ins);
|
void notifyInsChange(int ins);
|
||||||
|
void notifyInsDeletion(void* ins);
|
||||||
void renderSamples(int chipID);
|
void renderSamples(int chipID);
|
||||||
void setFlags(const DivConfig& flags);
|
void setFlags(const DivConfig& flags);
|
||||||
int getOutputCount();
|
int getOutputCount();
|
||||||
|
|
|
@ -39,6 +39,10 @@ const char** DivPlatformSMS::getRegisterSheet() {
|
||||||
return stereo?regCheatSheetGG:regCheatSheetSN;
|
return stereo?regCheatSheetGG:regCheatSheetSN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float DivPlatformSMS::getPostAmp() {
|
||||||
|
return 1.5f;
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformSMS::acquire_nuked(short** buf, size_t len) {
|
void DivPlatformSMS::acquire_nuked(short** buf, size_t len) {
|
||||||
int oL=0;
|
int oL=0;
|
||||||
int oR=0;
|
int oR=0;
|
||||||
|
|
|
@ -81,6 +81,7 @@ class DivPlatformSMS: public DivDispatch {
|
||||||
int getOutputCount();
|
int getOutputCount();
|
||||||
bool keyOffAffectsArp(int ch);
|
bool keyOffAffectsArp(int ch);
|
||||||
bool keyOffAffectsPorta(int ch);
|
bool keyOffAffectsPorta(int ch);
|
||||||
|
float getPostAmp();
|
||||||
int getPortaFloor(int ch);
|
int getPortaFloor(int ch);
|
||||||
void setFlags(const DivConfig& flags);
|
void setFlags(const DivConfig& flags);
|
||||||
void notifyInsDeletion(void* ins);
|
void notifyInsDeletion(void* ins);
|
||||||
|
|
|
@ -135,7 +135,7 @@ void DivPlatformTIA::tick(bool sysTick) {
|
||||||
int bf=chan[i].baseFreq;
|
int bf=chan[i].baseFreq;
|
||||||
if (!parent->song.oldArpStrategy) {
|
if (!parent->song.oldArpStrategy) {
|
||||||
if (!chan[i].fixedArp) {
|
if (!chan[i].fixedArp) {
|
||||||
bf+=chan[i].baseFreq+chan[i].arpOff;
|
bf+=chan[i].arpOff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chan[i].freq=dealWithFreq(chan[i].shape,bf,chan[i].pitch)+chan[i].pitch2;
|
chan[i].freq=dealWithFreq(chan[i].shape,bf,chan[i].pitch)+chan[i].pitch2;
|
||||||
|
|
|
@ -350,56 +350,60 @@ void DivPlatformTX81Z::muteChannel(int ch, bool mute) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformTX81Z::commitState(int ch, DivInstrument* ins) {
|
||||||
|
if (chan[ch].insChanged) {
|
||||||
|
chan[ch].state=ins->fm;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)|((op.egt?(op.dt&7):dtTable[op.dt&7])<<4));
|
||||||
|
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.egt<<5)|(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));
|
||||||
|
rWrite(baseAddr+ADDR_WS_FINE,(op.dvb&15)|(op.ws<<4));
|
||||||
|
rWrite(baseAddr+ADDR_EGS_REV,(op.dam&7)|(op.ksl<<6));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
//rWrite(chanOffs[ch]+ADDR_FMS_AMS,0x84|((chan[ch].state.fms2&7)<<4)|(chan[ch].state.ams2&3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int DivPlatformTX81Z::dispatch(DivCommand c) {
|
int DivPlatformTX81Z::dispatch(DivCommand c) {
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPZ);
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPZ);
|
||||||
|
|
||||||
if (chan[c.chan].insChanged) {
|
|
||||||
chan[c.chan].state=ins->fm;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)|((op.egt?(op.dt&7):dtTable[op.dt&7])<<4));
|
|
||||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.egt<<5)|(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));
|
|
||||||
rWrite(baseAddr+ADDR_WS_FINE,(op.dvb&15)|(op.ws<<4));
|
|
||||||
rWrite(baseAddr+ADDR_EGS_REV,(op.dam&7)|(op.ksl<<6));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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));
|
|
||||||
//rWrite(chanOffs[c.chan]+ADDR_FMS_AMS,0x84|((chan[c.chan].state.fms2&7)<<4)|(chan[c.chan].state.ams2&3));
|
|
||||||
}
|
|
||||||
chan[c.chan].insChanged=false;
|
chan[c.chan].insChanged=false;
|
||||||
|
|
||||||
if (c.value!=DIV_NOTE_NULL) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
|
@ -498,6 +502,11 @@ int DivPlatformTX81Z::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_OPZ);
|
||||||
|
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;
|
||||||
|
@ -873,6 +882,12 @@ void DivPlatformTX81Z::notifyInsChange(int ins) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformTX81Z::notifyInsDeletion(void* ins) {
|
||||||
|
for (int i=0; i<8; i++) {
|
||||||
|
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void* DivPlatformTX81Z::getChanState(int ch) {
|
void* DivPlatformTX81Z::getChanState(int ch) {
|
||||||
return &chan[ch];
|
return &chan[ch];
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@ class DivPlatformTX81Z: public DivPlatformOPM {
|
||||||
|
|
||||||
int octave(int freq);
|
int octave(int freq);
|
||||||
int toFreq(int freq);
|
int toFreq(int freq);
|
||||||
|
void commitState(int ch, DivInstrument* ins);
|
||||||
|
|
||||||
friend void putDispatchChip(void*,int);
|
friend void putDispatchChip(void*,int);
|
||||||
public:
|
public:
|
||||||
|
@ -72,6 +73,7 @@ class DivPlatformTX81Z: public DivPlatformOPM {
|
||||||
void tick(bool sysTick=true);
|
void tick(bool sysTick=true);
|
||||||
void muteChannel(int ch, bool mute);
|
void muteChannel(int ch, bool mute);
|
||||||
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 poke(unsigned int addr, unsigned short val);
|
void poke(unsigned int addr, unsigned short val);
|
||||||
|
|
|
@ -411,7 +411,7 @@ int DivPlatformVERA::getOutputCount() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformVERA::notifyInsDeletion(void* ins) {
|
void DivPlatformVERA::notifyInsDeletion(void* ins) {
|
||||||
for (int i=0; i<2; i++) {
|
for (int i=0; i<17; i++) {
|
||||||
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -903,6 +903,10 @@ bool DivPlatformX1_010::keyOffAffectsArp(int ch) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float DivPlatformX1_010::getPostAmp() {
|
||||||
|
return 4.0f;
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformX1_010::notifyWaveChange(int wave) {
|
void DivPlatformX1_010::notifyWaveChange(int wave) {
|
||||||
for (int i=0; i<16; i++) {
|
for (int i=0; i<16; i++) {
|
||||||
if (chan[i].wave==wave) {
|
if (chan[i].wave==wave) {
|
||||||
|
|
|
@ -140,6 +140,7 @@ class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf {
|
||||||
void muteChannel(int ch, bool mute);
|
void muteChannel(int ch, bool mute);
|
||||||
int getOutputCount();
|
int getOutputCount();
|
||||||
bool keyOffAffectsArp(int ch);
|
bool keyOffAffectsArp(int ch);
|
||||||
|
float getPostAmp();
|
||||||
void setFlags(const DivConfig& flags);
|
void setFlags(const DivConfig& flags);
|
||||||
void notifyWaveChange(int wave);
|
void notifyWaveChange(int wave);
|
||||||
void notifyInsDeletion(void* ins);
|
void notifyInsDeletion(void* ins);
|
||||||
|
|
|
@ -474,6 +474,46 @@ void DivPlatformYM2203::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformYM2203::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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int DivPlatformYM2203::dispatch(DivCommand c) {
|
int DivPlatformYM2203::dispatch(DivCommand c) {
|
||||||
if (c.chan>2) {
|
if (c.chan>2) {
|
||||||
c.chan-=3;
|
c.chan-=3;
|
||||||
|
@ -489,43 +529,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chan[c.chan].insChanged) {
|
commitState(c.chan,ins);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
chan[c.chan].insChanged=false;
|
chan[c.chan].insChanged=false;
|
||||||
|
|
||||||
if (c.value!=DIV_NOTE_NULL) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
|
@ -616,6 +620,11 @@ int DivPlatformYM2203::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_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].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
break;
|
break;
|
||||||
|
@ -986,6 +995,9 @@ void DivPlatformYM2203::notifyInsChange(int ins) {
|
||||||
|
|
||||||
void DivPlatformYM2203::notifyInsDeletion(void* ins) {
|
void DivPlatformYM2203::notifyInsDeletion(void* ins) {
|
||||||
ay->notifyInsDeletion(ins);
|
ay->notifyInsDeletion(ins);
|
||||||
|
for (int i=0; i<3; i++) {
|
||||||
|
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2203::setSkipRegisterWrites(bool value) {
|
void DivPlatformYM2203::setSkipRegisterWrites(bool value) {
|
||||||
|
|
|
@ -55,6 +55,8 @@ class DivPlatformYM2203: public DivPlatformOPN {
|
||||||
|
|
||||||
friend void putDispatchChip(void*,int);
|
friend void putDispatchChip(void*,int);
|
||||||
|
|
||||||
|
inline void commitState(int ch, DivInstrument* ins);
|
||||||
|
|
||||||
void acquire_combo(short** buf, size_t len);
|
void acquire_combo(short** buf, size_t len);
|
||||||
void acquire_ymfm(short** buf, size_t len);
|
void acquire_ymfm(short** buf, size_t len);
|
||||||
|
|
||||||
|
@ -73,7 +75,7 @@ class DivPlatformYM2203: public DivPlatformOPN {
|
||||||
int getOutputCount();
|
int getOutputCount();
|
||||||
bool keyOffAffectsArp(int ch);
|
bool keyOffAffectsArp(int ch);
|
||||||
void notifyInsChange(int ins);
|
void notifyInsChange(int ins);
|
||||||
void notifyInsDeletion(void* ins);
|
virtual void notifyInsDeletion(void* ins);
|
||||||
void setSkipRegisterWrites(bool val);
|
void setSkipRegisterWrites(bool val);
|
||||||
void poke(unsigned int addr, unsigned short val);
|
void poke(unsigned int addr, unsigned short val);
|
||||||
void poke(std::vector<DivRegWrite>& wlist);
|
void poke(std::vector<DivRegWrite>& wlist);
|
||||||
|
|
|
@ -641,6 +641,13 @@ void DivPlatformYM2203Ext::notifyInsChange(int ins) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformYM2203Ext::notifyInsDeletion(void* ins) {
|
||||||
|
DivPlatformYM2203::notifyInsDeletion(ins);
|
||||||
|
for (int i=0; i<4; i++) {
|
||||||
|
opChan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int DivPlatformYM2203Ext::init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) {
|
int DivPlatformYM2203Ext::init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) {
|
||||||
DivPlatformYM2203::init(parent,channels,sugRate,flags);
|
DivPlatformYM2203::init(parent,channels,sugRate,flags);
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
|
|
|
@ -39,6 +39,7 @@ class DivPlatformYM2203Ext: public DivPlatformYM2203 {
|
||||||
void muteChannel(int ch, bool mute);
|
void muteChannel(int ch, bool mute);
|
||||||
bool keyOffAffectsArp(int ch);
|
bool keyOffAffectsArp(int ch);
|
||||||
void notifyInsChange(int ins);
|
void notifyInsChange(int ins);
|
||||||
|
void notifyInsDeletion(void* ins);
|
||||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||||
void quit();
|
void quit();
|
||||||
~DivPlatformYM2203Ext();
|
~DivPlatformYM2203Ext();
|
||||||
|
|
|
@ -545,6 +545,10 @@ void DivPlatformYM2608::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,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.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;
|
||||||
|
@ -785,6 +789,43 @@ void DivPlatformYM2608::tick(bool sysTick) {
|
||||||
ay->getRegisterWrites().clear();
|
ay->getRegisterWrites().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformYM2608::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);
|
||||||
|
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,(isMuted[ch]?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int DivPlatformYM2608::dispatch(DivCommand c) {
|
int DivPlatformYM2608::dispatch(DivCommand c) {
|
||||||
if (c.chan>5 && c.chan<9) {
|
if (c.chan>5 && c.chan<9) {
|
||||||
c.chan-=6;
|
c.chan-=6;
|
||||||
|
@ -898,40 +939,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chan[c.chan].insChanged) {
|
commitState(c.chan,ins);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
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,(isMuted[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) {
|
||||||
|
@ -1059,6 +1067,13 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_LEGATO: {
|
case DIV_CMD_LEGATO: {
|
||||||
if (c.chan==15 && !chan[c.chan].furnacePCM) break;
|
if (c.chan==15 && !chan[c.chan].furnacePCM) break;
|
||||||
|
if (c.chan<=psgChanOffs) {
|
||||||
|
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_OPNB(c.chan,c.value);
|
chan[c.chan].baseFreq=NOTE_OPNB(c.chan,c.value);
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
break;
|
break;
|
||||||
|
@ -1454,6 +1469,12 @@ void DivPlatformYM2608::notifyInsChange(int ins) {
|
||||||
|
|
||||||
void DivPlatformYM2608::notifyInsDeletion(void* ins) {
|
void DivPlatformYM2608::notifyInsDeletion(void* ins) {
|
||||||
ay->notifyInsDeletion(ins);
|
ay->notifyInsDeletion(ins);
|
||||||
|
for (int i=0; i<psgChanOffs; i++) {
|
||||||
|
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
|
}
|
||||||
|
for (int i=adpcmAChanOffs; i<chanNum; i++) {
|
||||||
|
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2608::setSkipRegisterWrites(bool value) {
|
void DivPlatformYM2608::setSkipRegisterWrites(bool value) {
|
||||||
|
|
|
@ -70,6 +70,8 @@ class DivPlatformYM2608: public DivPlatformOPN {
|
||||||
|
|
||||||
friend void putDispatchChip(void*,int);
|
friend void putDispatchChip(void*,int);
|
||||||
|
|
||||||
|
inline void commitState(int ch, DivInstrument* ins);
|
||||||
|
|
||||||
void acquire_combo(short** buf, size_t len);
|
void acquire_combo(short** buf, size_t len);
|
||||||
void acquire_ymfm(short** buf, size_t len);
|
void acquire_ymfm(short** buf, size_t len);
|
||||||
|
|
||||||
|
@ -88,7 +90,7 @@ class DivPlatformYM2608: public DivPlatformOPN {
|
||||||
int getOutputCount();
|
int getOutputCount();
|
||||||
bool keyOffAffectsArp(int ch);
|
bool keyOffAffectsArp(int ch);
|
||||||
void notifyInsChange(int ins);
|
void notifyInsChange(int ins);
|
||||||
void notifyInsDeletion(void* ins);
|
virtual void notifyInsDeletion(void* ins);
|
||||||
void setSkipRegisterWrites(bool val);
|
void setSkipRegisterWrites(bool val);
|
||||||
void poke(unsigned int addr, unsigned short val);
|
void poke(unsigned int addr, unsigned short val);
|
||||||
void poke(std::vector<DivRegWrite>& wlist);
|
void poke(std::vector<DivRegWrite>& wlist);
|
||||||
|
|
|
@ -679,6 +679,13 @@ void DivPlatformYM2608Ext::notifyInsChange(int ins) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformYM2608Ext::notifyInsDeletion(void* ins) {
|
||||||
|
DivPlatformYM2608::notifyInsDeletion(ins);
|
||||||
|
for (int i=0; i<4; i++) {
|
||||||
|
opChan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int DivPlatformYM2608Ext::init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) {
|
int DivPlatformYM2608Ext::init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) {
|
||||||
DivPlatformYM2608::init(parent,channels,sugRate,flags);
|
DivPlatformYM2608::init(parent,channels,sugRate,flags);
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
|
|
|
@ -39,6 +39,7 @@ class DivPlatformYM2608Ext: public DivPlatformYM2608 {
|
||||||
void muteChannel(int ch, bool mute);
|
void muteChannel(int ch, bool mute);
|
||||||
bool keyOffAffectsArp(int ch);
|
bool keyOffAffectsArp(int ch);
|
||||||
void notifyInsChange(int ins);
|
void notifyInsChange(int ins);
|
||||||
|
void notifyInsDeletion(void* ins);
|
||||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||||
void quit();
|
void quit();
|
||||||
~DivPlatformYM2608Ext();
|
~DivPlatformYM2608Ext();
|
||||||
|
|
|
@ -478,6 +478,10 @@ void DivPlatformYM2610::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,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.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;
|
||||||
|
@ -720,6 +724,43 @@ void DivPlatformYM2610::tick(bool sysTick) {
|
||||||
ay->getRegisterWrites().clear();
|
ay->getRegisterWrites().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformYM2610::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);
|
||||||
|
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,(isMuted[ch]?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int DivPlatformYM2610::dispatch(DivCommand c) {
|
int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||||
if (c.chan>=psgChanOffs && c.chan<adpcmAChanOffs) {
|
if (c.chan>=psgChanOffs && c.chan<adpcmAChanOffs) {
|
||||||
c.chan-=psgChanOffs;
|
c.chan-=psgChanOffs;
|
||||||
|
@ -874,40 +915,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chan[c.chan].insChanged) {
|
commitState(c.chan,ins);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
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,(isMuted[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) {
|
||||||
|
@ -1035,6 +1043,13 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_LEGATO: {
|
case DIV_CMD_LEGATO: {
|
||||||
if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break;
|
if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break;
|
||||||
|
if (c.chan<=psgChanOffs) {
|
||||||
|
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_OPNB(c.chan,c.value);
|
chan[c.chan].baseFreq=NOTE_OPNB(c.chan,c.value);
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
break;
|
break;
|
||||||
|
@ -1402,6 +1417,12 @@ void DivPlatformYM2610::notifyInsChange(int ins) {
|
||||||
|
|
||||||
void DivPlatformYM2610::notifyInsDeletion(void* ins) {
|
void DivPlatformYM2610::notifyInsDeletion(void* ins) {
|
||||||
ay->notifyInsDeletion(ins);
|
ay->notifyInsDeletion(ins);
|
||||||
|
for (int i=0; i<psgChanOffs; i++) {
|
||||||
|
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
|
}
|
||||||
|
for (int i=adpcmAChanOffs; i<chanNum; i++) {
|
||||||
|
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2610::setSkipRegisterWrites(bool value) {
|
void DivPlatformYM2610::setSkipRegisterWrites(bool value) {
|
||||||
|
|
|
@ -38,6 +38,8 @@ class DivPlatformYM2610: public DivPlatformYM2610Base {
|
||||||
|
|
||||||
friend void putDispatchChip(void*,int);
|
friend void putDispatchChip(void*,int);
|
||||||
|
|
||||||
|
void commitState(int ch, DivInstrument* ins);
|
||||||
|
|
||||||
void acquire_combo(short** buf, size_t len);
|
void acquire_combo(short** buf, size_t len);
|
||||||
void acquire_ymfm(short** buf, size_t len);
|
void acquire_ymfm(short** buf, size_t len);
|
||||||
|
|
||||||
|
@ -56,7 +58,7 @@ class DivPlatformYM2610: public DivPlatformYM2610Base {
|
||||||
int getOutputCount();
|
int getOutputCount();
|
||||||
bool keyOffAffectsArp(int ch);
|
bool keyOffAffectsArp(int ch);
|
||||||
void notifyInsChange(int ins);
|
void notifyInsChange(int ins);
|
||||||
void notifyInsDeletion(void* ins);
|
virtual void notifyInsDeletion(void* ins);
|
||||||
void setSkipRegisterWrites(bool val);
|
void setSkipRegisterWrites(bool val);
|
||||||
void poke(unsigned int addr, unsigned short val);
|
void poke(unsigned int addr, unsigned short val);
|
||||||
void poke(std::vector<DivRegWrite>& wlist);
|
void poke(std::vector<DivRegWrite>& wlist);
|
||||||
|
|
|
@ -545,6 +545,10 @@ void DivPlatformYM2610B::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,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.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;
|
||||||
|
@ -787,6 +791,43 @@ void DivPlatformYM2610B::tick(bool sysTick) {
|
||||||
ay->getRegisterWrites().clear();
|
ay->getRegisterWrites().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformYM2610B::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);
|
||||||
|
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,(isMuted[ch]?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int DivPlatformYM2610B::dispatch(DivCommand c) {
|
int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||||
if (c.chan>=psgChanOffs && c.chan<adpcmAChanOffs) {
|
if (c.chan>=psgChanOffs && c.chan<adpcmAChanOffs) {
|
||||||
c.chan-=psgChanOffs;
|
c.chan-=psgChanOffs;
|
||||||
|
@ -941,40 +982,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chan[c.chan].insChanged) {
|
commitState(c.chan,ins);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
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,(isMuted[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) {
|
||||||
|
@ -1102,6 +1110,13 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_LEGATO: {
|
case DIV_CMD_LEGATO: {
|
||||||
if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break;
|
if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break;
|
||||||
|
if (c.chan<=psgChanOffs) {
|
||||||
|
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_OPNB(c.chan,c.value);
|
chan[c.chan].baseFreq=NOTE_OPNB(c.chan,c.value);
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
break;
|
break;
|
||||||
|
@ -1473,6 +1488,12 @@ void DivPlatformYM2610B::notifyInsChange(int ins) {
|
||||||
|
|
||||||
void DivPlatformYM2610B::notifyInsDeletion(void* ins) {
|
void DivPlatformYM2610B::notifyInsDeletion(void* ins) {
|
||||||
ay->notifyInsDeletion(ins);
|
ay->notifyInsDeletion(ins);
|
||||||
|
for (int i=0; i<psgChanOffs; i++) {
|
||||||
|
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
|
}
|
||||||
|
for (int i=adpcmAChanOffs; i<chanNum; i++) {
|
||||||
|
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2610B::setSkipRegisterWrites(bool value) {
|
void DivPlatformYM2610B::setSkipRegisterWrites(bool value) {
|
||||||
|
|
|
@ -34,6 +34,8 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base {
|
||||||
|
|
||||||
friend void putDispatchChip(void*,int);
|
friend void putDispatchChip(void*,int);
|
||||||
|
|
||||||
|
void commitState(int ch, DivInstrument* ins);
|
||||||
|
|
||||||
void acquire_combo(short** buf, size_t len);
|
void acquire_combo(short** buf, size_t len);
|
||||||
void acquire_ymfm(short** buf, size_t len);
|
void acquire_ymfm(short** buf, size_t len);
|
||||||
|
|
||||||
|
@ -52,7 +54,7 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base {
|
||||||
int getOutputCount();
|
int getOutputCount();
|
||||||
bool keyOffAffectsArp(int ch);
|
bool keyOffAffectsArp(int ch);
|
||||||
void notifyInsChange(int ins);
|
void notifyInsChange(int ins);
|
||||||
void notifyInsDeletion(void* ins);
|
virtual void notifyInsDeletion(void* ins);
|
||||||
void setSkipRegisterWrites(bool val);
|
void setSkipRegisterWrites(bool val);
|
||||||
void poke(unsigned int addr, unsigned short val);
|
void poke(unsigned int addr, unsigned short val);
|
||||||
void poke(std::vector<DivRegWrite>& wlist);
|
void poke(std::vector<DivRegWrite>& wlist);
|
||||||
|
|
|
@ -670,6 +670,13 @@ void DivPlatformYM2610BExt::notifyInsChange(int ins) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformYM2610BExt::notifyInsDeletion(void* ins) {
|
||||||
|
DivPlatformYM2610B::notifyInsDeletion(ins);
|
||||||
|
for (int i=0; i<4; i++) {
|
||||||
|
opChan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int DivPlatformYM2610BExt::init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) {
|
int DivPlatformYM2610BExt::init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) {
|
||||||
DivPlatformYM2610B::init(parent,channels,sugRate,flags);
|
DivPlatformYM2610B::init(parent,channels,sugRate,flags);
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
|
|
|
@ -39,6 +39,7 @@ class DivPlatformYM2610BExt: public DivPlatformYM2610B {
|
||||||
void muteChannel(int ch, bool mute);
|
void muteChannel(int ch, bool mute);
|
||||||
bool keyOffAffectsArp(int ch);
|
bool keyOffAffectsArp(int ch);
|
||||||
void notifyInsChange(int ins);
|
void notifyInsChange(int ins);
|
||||||
|
void notifyInsDeletion(void* ins);
|
||||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||||
void quit();
|
void quit();
|
||||||
~DivPlatformYM2610BExt();
|
~DivPlatformYM2610BExt();
|
||||||
|
|
|
@ -670,6 +670,13 @@ void DivPlatformYM2610Ext::notifyInsChange(int ins) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformYM2610Ext::notifyInsDeletion(void* ins) {
|
||||||
|
DivPlatformYM2610::notifyInsDeletion(ins);
|
||||||
|
for (int i=0; i<4; i++) {
|
||||||
|
opChan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int DivPlatformYM2610Ext::init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) {
|
int DivPlatformYM2610Ext::init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) {
|
||||||
DivPlatformYM2610::init(parent,channels,sugRate,flags);
|
DivPlatformYM2610::init(parent,channels,sugRate,flags);
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
|
|
|
@ -39,6 +39,7 @@ class DivPlatformYM2610Ext: public DivPlatformYM2610 {
|
||||||
void muteChannel(int ch, bool mute);
|
void muteChannel(int ch, bool mute);
|
||||||
bool keyOffAffectsArp(int ch);
|
bool keyOffAffectsArp(int ch);
|
||||||
void notifyInsChange(int ins);
|
void notifyInsChange(int ins);
|
||||||
|
void notifyInsDeletion(void* ins);
|
||||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||||
void quit();
|
void quit();
|
||||||
~DivPlatformYM2610Ext();
|
~DivPlatformYM2610Ext();
|
||||||
|
|
|
@ -908,7 +908,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
||||||
chan[i].vibratoPos=0;
|
chan[i].vibratoPos=0;
|
||||||
}
|
}
|
||||||
dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(((chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15)));
|
dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(((chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15)));
|
||||||
if (chan[i].legato) {
|
if (chan[i].legato && (!chan[i].inPorta || song.brokenPortaLegato)) {
|
||||||
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
|
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
|
||||||
dispatchCmd(DivCommand(DIV_CMD_HINT_LEGATO,i,chan[i].note));
|
dispatchCmd(DivCommand(DIV_CMD_HINT_LEGATO,i,chan[i].note));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -330,6 +330,7 @@ struct DivSong {
|
||||||
bool autoSystem;
|
bool autoSystem;
|
||||||
bool oldArpStrategy;
|
bool oldArpStrategy;
|
||||||
bool patchbayAuto;
|
bool patchbayAuto;
|
||||||
|
bool brokenPortaLegato;
|
||||||
|
|
||||||
std::vector<DivInstrument*> ins;
|
std::vector<DivInstrument*> ins;
|
||||||
std::vector<DivWavetable*> wave;
|
std::vector<DivWavetable*> wave;
|
||||||
|
@ -439,7 +440,8 @@ struct DivSong {
|
||||||
disableSampleMacro(false),
|
disableSampleMacro(false),
|
||||||
autoSystem(true),
|
autoSystem(true),
|
||||||
oldArpStrategy(false),
|
oldArpStrategy(false),
|
||||||
patchbayAuto(true) {
|
patchbayAuto(true),
|
||||||
|
brokenPortaLegato(false) {
|
||||||
for (int i=0; i<DIV_MAX_CHIPS; i++) {
|
for (int i=0; i<DIV_MAX_CHIPS; i++) {
|
||||||
system[i]=DIV_SYSTEM_NULL;
|
system[i]=DIV_SYSTEM_NULL;
|
||||||
systemVol[i]=1.0;
|
systemVol[i]=1.0;
|
||||||
|
|
|
@ -1086,7 +1086,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
case DIV_SYSTEM_SMS:
|
case DIV_SYSTEM_SMS:
|
||||||
if (!hasSN) {
|
if (!hasSN) {
|
||||||
hasSN=disCont[i].dispatch->chipClock;
|
hasSN=disCont[i].dispatch->chipClock;
|
||||||
CHIP_VOL(0,2.0);
|
CHIP_VOL(0,4.0);
|
||||||
willExport[i]=true;
|
willExport[i]=true;
|
||||||
switch (song.systemFlags[i].getInt("chipType",0)) {
|
switch (song.systemFlags[i].getInt("chipType",0)) {
|
||||||
case 1: // real SN
|
case 1: // real SN
|
||||||
|
@ -1105,7 +1105,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
} else if (!(hasSN&0x40000000)) {
|
} else if (!(hasSN&0x40000000)) {
|
||||||
isSecond[i]=true;
|
isSecond[i]=true;
|
||||||
willExport[i]=true;
|
willExport[i]=true;
|
||||||
CHIP_VOL_SECOND(0,2.0);
|
CHIP_VOL_SECOND(0,4.0);
|
||||||
hasSN|=0x40000000;
|
hasSN|=0x40000000;
|
||||||
howManyChips++;
|
howManyChips++;
|
||||||
}
|
}
|
||||||
|
@ -1170,12 +1170,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
case DIV_SYSTEM_X1_010:
|
case DIV_SYSTEM_X1_010:
|
||||||
if (!hasX1) {
|
if (!hasX1) {
|
||||||
hasX1=disCont[i].dispatch->chipClock;
|
hasX1=disCont[i].dispatch->chipClock;
|
||||||
CHIP_VOL(38,0.5);
|
CHIP_VOL(38,2.0);
|
||||||
willExport[i]=true;
|
willExport[i]=true;
|
||||||
writeX1010[0]=disCont[i].dispatch;
|
writeX1010[0]=disCont[i].dispatch;
|
||||||
} else if (!(hasX1&0x40000000)) {
|
} else if (!(hasX1&0x40000000)) {
|
||||||
isSecond[i]=true;
|
isSecond[i]=true;
|
||||||
CHIP_VOL_SECOND(38,0.5);
|
CHIP_VOL_SECOND(38,2.0);
|
||||||
willExport[i]=true;
|
willExport[i]=true;
|
||||||
writeX1010[1]=disCont[i].dispatch;
|
writeX1010[1]=disCont[i].dispatch;
|
||||||
hasX1|=0x40000000;
|
hasX1|=0x40000000;
|
||||||
|
@ -1272,12 +1272,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
case DIV_SYSTEM_YM2612_DUALPCM_EXT:
|
case DIV_SYSTEM_YM2612_DUALPCM_EXT:
|
||||||
if (!hasOPN2) {
|
if (!hasOPN2) {
|
||||||
hasOPN2=disCont[i].dispatch->chipClock;
|
hasOPN2=disCont[i].dispatch->chipClock;
|
||||||
CHIP_VOL(2,0.8);
|
CHIP_VOL(2,1.6);
|
||||||
willExport[i]=true;
|
willExport[i]=true;
|
||||||
writeDACSamples=true;
|
writeDACSamples=true;
|
||||||
} else if (!(hasOPN2&0x40000000)) {
|
} else if (!(hasOPN2&0x40000000)) {
|
||||||
isSecond[i]=true;
|
isSecond[i]=true;
|
||||||
CHIP_VOL_SECOND(2,0.8);
|
CHIP_VOL_SECOND(2,1.6);
|
||||||
willExport[i]=true;
|
willExport[i]=true;
|
||||||
hasOPN2|=0x40000000;
|
hasOPN2|=0x40000000;
|
||||||
howManyChips++;
|
howManyChips++;
|
||||||
|
@ -1336,11 +1336,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
case DIV_SYSTEM_VRC7:
|
case DIV_SYSTEM_VRC7:
|
||||||
if (!hasOPLL) {
|
if (!hasOPLL) {
|
||||||
hasOPLL=disCont[i].dispatch->chipClock;
|
hasOPLL=disCont[i].dispatch->chipClock;
|
||||||
CHIP_VOL(1,1.6);
|
CHIP_VOL(1,3.2);
|
||||||
willExport[i]=true;
|
willExport[i]=true;
|
||||||
} else if (!(hasOPLL&0x40000000)) {
|
} else if (!(hasOPLL&0x40000000)) {
|
||||||
isSecond[i]=true;
|
isSecond[i]=true;
|
||||||
CHIP_VOL_SECOND(1,1.6);
|
CHIP_VOL_SECOND(1,3.2);
|
||||||
willExport[i]=true;
|
willExport[i]=true;
|
||||||
hasOPLL|=0x40000000;
|
hasOPLL|=0x40000000;
|
||||||
howManyChips++;
|
howManyChips++;
|
||||||
|
|
|
@ -69,6 +69,7 @@ const char* aboutLine[]={
|
||||||
"brickblock369",
|
"brickblock369",
|
||||||
"Burnt Fishy",
|
"Burnt Fishy",
|
||||||
"CaptainMalware",
|
"CaptainMalware",
|
||||||
|
"Clingojam",
|
||||||
"DeMOSic",
|
"DeMOSic",
|
||||||
"DevEd",
|
"DevEd",
|
||||||
"Dippy",
|
"Dippy",
|
||||||
|
|
|
@ -214,7 +214,7 @@ void FurnaceGUI::drawCompatFlags() {
|
||||||
e->song.delayBehavior=2;
|
e->song.delayBehavior=2;
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::SetTooltip("no checks (like FamiTracker)");
|
ImGui::SetTooltip("no checks");
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Text("Simultaneous jump (0B+0D) treatment:");
|
ImGui::Text("Simultaneous jump (0B+0D) treatment:");
|
||||||
|
@ -293,6 +293,10 @@ void FurnaceGUI::drawCompatFlags() {
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::SetTooltip("behavior changed in 0.6pre2");
|
ImGui::SetTooltip("behavior changed in 0.6pre2");
|
||||||
}
|
}
|
||||||
|
ImGui::Checkbox("Broken portamento during legato",&e->song.brokenPortaLegato);
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip("behavior changed in 0.6pre4");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_COMPAT_FLAGS;
|
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_COMPAT_FLAGS;
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
|
@ -163,7 +163,7 @@ void FurnaceGUI::doAction(int what) {
|
||||||
case GUI_ACTION_TX81Z_REQUEST: {
|
case GUI_ACTION_TX81Z_REQUEST: {
|
||||||
TAMidiMessage msg;
|
TAMidiMessage msg;
|
||||||
msg.type=TA_MIDI_SYSEX;
|
msg.type=TA_MIDI_SYSEX;
|
||||||
msg.sysExData.reset(new unsigned char[15]);
|
msg.sysExData.reset(new unsigned char[15],std::default_delete<unsigned char[]>());
|
||||||
msg.sysExLen=15;
|
msg.sysExLen=15;
|
||||||
memcpy(msg.sysExData.get(),avRequest,15);
|
memcpy(msg.sysExData.get(),avRequest,15);
|
||||||
if (!e->sendMidiMessage(msg)) {
|
if (!e->sendMidiMessage(msg)) {
|
||||||
|
|
|
@ -506,7 +506,9 @@ void FurnaceGUI::drawMobileControls() {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Button("Legacy .dmf");
|
ImGui::Button("Legacy .dmf");
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Button("Export Audio");
|
if (ImGui::Button("Export Audio")) {
|
||||||
|
openFileDialog(GUI_FILE_EXPORT_AUDIO_ONE);
|
||||||
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Export VGM")) {
|
if (ImGui::Button("Export VGM")) {
|
||||||
openFileDialog(GUI_FILE_EXPORT_VGM);
|
openFileDialog(GUI_FILE_EXPORT_VGM);
|
||||||
|
|
|
@ -1000,6 +1000,9 @@ float FurnaceGUI::calcBPM(int s1, int s2, float hz, int vN, int vD) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FurnaceGUI::play(int row) {
|
void FurnaceGUI::play(int row) {
|
||||||
|
memset(chanOscVol,0,DIV_MAX_CHANS*sizeof(float));
|
||||||
|
memset(chanOscPitch,0,DIV_MAX_CHANS*sizeof(float));
|
||||||
|
memset(chanOscBright,0,DIV_MAX_CHANS*sizeof(float));
|
||||||
e->walkSong(loopOrder,loopRow,loopEnd);
|
e->walkSong(loopOrder,loopRow,loopEnd);
|
||||||
memset(lastIns,-1,sizeof(int)*DIV_MAX_CHANS);
|
memset(lastIns,-1,sizeof(int)*DIV_MAX_CHANS);
|
||||||
if (!followPattern) e->setOrder(curOrder);
|
if (!followPattern) e->setOrder(curOrder);
|
||||||
|
@ -1026,6 +1029,9 @@ void FurnaceGUI::stop() {
|
||||||
curNibble=false;
|
curNibble=false;
|
||||||
orderNibble=false;
|
orderNibble=false;
|
||||||
activeNotes.clear();
|
activeNotes.clear();
|
||||||
|
memset(chanOscVol,0,DIV_MAX_CHANS*sizeof(float));
|
||||||
|
memset(chanOscPitch,0,DIV_MAX_CHANS*sizeof(float));
|
||||||
|
memset(chanOscBright,0,DIV_MAX_CHANS*sizeof(float));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FurnaceGUI::previewNote(int refChan, int note, bool autoNote) {
|
void FurnaceGUI::previewNote(int refChan, int note, bool autoNote) {
|
||||||
|
@ -3132,6 +3138,14 @@ bool FurnaceGUI::loop() {
|
||||||
break;
|
break;
|
||||||
case SDL_DISPLAYEVENT: {
|
case SDL_DISPLAYEVENT: {
|
||||||
switch (ev.display.event) {
|
switch (ev.display.event) {
|
||||||
|
case SDL_DISPLAYEVENT_CONNECTED:
|
||||||
|
logD("display %d connected!",ev.display.display);
|
||||||
|
updateWindow=true;
|
||||||
|
break;
|
||||||
|
case SDL_DISPLAYEVENT_DISCONNECTED:
|
||||||
|
logD("display %d disconnected!",ev.display.display);
|
||||||
|
updateWindow=true;
|
||||||
|
break;
|
||||||
case SDL_DISPLAYEVENT_ORIENTATION:
|
case SDL_DISPLAYEVENT_ORIENTATION:
|
||||||
logD("display oriented to %d",ev.display.data1);
|
logD("display oriented to %d",ev.display.data1);
|
||||||
updateWindow=true;
|
updateWindow=true;
|
||||||
|
|
|
@ -1295,6 +1295,7 @@ class FurnaceGUI {
|
||||||
double exportFadeOut;
|
double exportFadeOut;
|
||||||
int macroLayout;
|
int macroLayout;
|
||||||
float doubleClickTime;
|
float doubleClickTime;
|
||||||
|
int oneDigitEffects;
|
||||||
unsigned int maxUndoSteps;
|
unsigned int maxUndoSteps;
|
||||||
String mainFontPath;
|
String mainFontPath;
|
||||||
String patFontPath;
|
String patFontPath;
|
||||||
|
@ -1430,6 +1431,7 @@ class FurnaceGUI {
|
||||||
exportFadeOut(0.0),
|
exportFadeOut(0.0),
|
||||||
macroLayout(0),
|
macroLayout(0),
|
||||||
doubleClickTime(0.3f),
|
doubleClickTime(0.3f),
|
||||||
|
oneDigitEffects(0),
|
||||||
maxUndoSteps(100),
|
maxUndoSteps(100),
|
||||||
mainFontPath(""),
|
mainFontPath(""),
|
||||||
patFontPath(""),
|
patFontPath(""),
|
||||||
|
|
|
@ -3796,6 +3796,9 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ins->type==DIV_INS_FM) {
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc("LFO Speed",&ins->std.ex3Macro,0,8,96,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||||
|
}
|
||||||
if (ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) {
|
if (ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) {
|
||||||
macroList.push_back(FurnaceGUIMacroDesc("AM Depth",&ins->std.ex1Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER]));
|
macroList.push_back(FurnaceGUIMacroDesc("AM Depth",&ins->std.ex1Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||||
macroList.push_back(FurnaceGUIMacroDesc("PM Depth",&ins->std.ex2Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER]));
|
macroList.push_back(FurnaceGUIMacroDesc("PM Depth",&ins->std.ex2Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||||
|
|
|
@ -287,10 +287,14 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
||||||
if (pat->data[i][index]>0xff) {
|
if (pat->data[i][index]>0xff) {
|
||||||
snprintf(id,63,"??##PE%d_%d_%d",k,i,j);
|
snprintf(id,63,"??##PE%d_%d_%d",k,i,j);
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]);
|
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]);
|
||||||
} else {
|
} else if (pat->data[i][index]>0x10 || settings.oneDigitEffects==0) {
|
||||||
const unsigned char data=pat->data[i][index];
|
const unsigned char data=pat->data[i][index];
|
||||||
snprintf(id,63,"%.2X##PE%d_%d_%d",data,k,i,j);
|
snprintf(id,63,"%.2X##PE%d_%d_%d",data,k,i,j);
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[fxColors[data]]);
|
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[fxColors[data]]);
|
||||||
|
} else {
|
||||||
|
const unsigned char data=pat->data[i][index];
|
||||||
|
snprintf(id,63," %.1X##PE%d_%d_%d",data,k,i,j);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[fxColors[data]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::SameLine(0.0f,0.0f);
|
ImGui::SameLine(0.0f,0.0f);
|
||||||
|
|
|
@ -1602,6 +1602,11 @@ void FurnaceGUI::drawSettings() {
|
||||||
settings.germanNotation=germanNotationB;
|
settings.germanNotation=germanNotationB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool oneDigitEffectsB=settings.oneDigitEffects;
|
||||||
|
if (ImGui::Checkbox("Single-digit effects for 00-0F",&oneDigitEffectsB)) {
|
||||||
|
settings.oneDigitEffects=oneDigitEffectsB;
|
||||||
|
}
|
||||||
|
|
||||||
bool centerPatternB=settings.centerPattern;
|
bool centerPatternB=settings.centerPattern;
|
||||||
if (ImGui::Checkbox("Center pattern view",¢erPatternB)) {
|
if (ImGui::Checkbox("Center pattern view",¢erPatternB)) {
|
||||||
settings.centerPattern=centerPatternB;
|
settings.centerPattern=centerPatternB;
|
||||||
|
@ -2565,6 +2570,7 @@ void FurnaceGUI::syncSettings() {
|
||||||
settings.exportFadeOut=e->getConfDouble("exportFadeOut",0.0);
|
settings.exportFadeOut=e->getConfDouble("exportFadeOut",0.0);
|
||||||
settings.macroLayout=e->getConfInt("macroLayout",0);
|
settings.macroLayout=e->getConfInt("macroLayout",0);
|
||||||
settings.doubleClickTime=e->getConfFloat("doubleClickTime",0.3f);
|
settings.doubleClickTime=e->getConfFloat("doubleClickTime",0.3f);
|
||||||
|
settings.oneDigitEffects=e->getConfInt("oneDigitEffects",0);
|
||||||
|
|
||||||
clampSetting(settings.mainFontSize,2,96);
|
clampSetting(settings.mainFontSize,2,96);
|
||||||
clampSetting(settings.patFontSize,2,96);
|
clampSetting(settings.patFontSize,2,96);
|
||||||
|
@ -2676,6 +2682,7 @@ void FurnaceGUI::syncSettings() {
|
||||||
clampSetting(settings.persistFadeOut,0,1);
|
clampSetting(settings.persistFadeOut,0,1);
|
||||||
clampSetting(settings.macroLayout,0,4);
|
clampSetting(settings.macroLayout,0,4);
|
||||||
clampSetting(settings.doubleClickTime,0.02,1.0);
|
clampSetting(settings.doubleClickTime,0.02,1.0);
|
||||||
|
clampSetting(settings.oneDigitEffects,0,1);
|
||||||
|
|
||||||
if (settings.exportLoops<0.0) settings.exportLoops=0.0;
|
if (settings.exportLoops<0.0) settings.exportLoops=0.0;
|
||||||
if (settings.exportFadeOut<0.0) settings.exportFadeOut=0.0;
|
if (settings.exportFadeOut<0.0) settings.exportFadeOut=0.0;
|
||||||
|
@ -2880,6 +2887,7 @@ void FurnaceGUI::commitSettings() {
|
||||||
e->setConf("exportFadeOut",settings.exportFadeOut);
|
e->setConf("exportFadeOut",settings.exportFadeOut);
|
||||||
e->setConf("macroLayout",settings.macroLayout);
|
e->setConf("macroLayout",settings.macroLayout);
|
||||||
e->setConf("doubleClickTime",settings.doubleClickTime);
|
e->setConf("doubleClickTime",settings.doubleClickTime);
|
||||||
|
e->setConf("oneDigitEffects",settings.oneDigitEffects);
|
||||||
|
|
||||||
// colors
|
// colors
|
||||||
for (int i=0; i<GUI_COLOR_MAX; i++) {
|
for (int i=0; i<GUI_COLOR_MAX; i++) {
|
||||||
|
|
Loading…
Reference in New Issue