Merge remote-tracking branch 'origin/master' into Mikey_VGM

This commit is contained in:
Waldemar Pawlaszek 2023-01-18 10:21:13 +01:00
commit b42dd554f2
36 changed files with 247 additions and 83 deletions

View file

@ -11,7 +11,7 @@ defaults:
shell: bash
env:
BUILD_TYPE: Release
BUILD_TYPE: Debug
jobs:
build:

BIN
demos/snes/amalgam.fur Normal file

Binary file not shown.

View file

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

Binary file not shown.

View file

@ -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 | |
1 | | AMD | AMD | | | Duty | | FilterMode | Envelope | EnvMode | WaveLen | Mod Depth | Cutoff | Filter K1 | ClockDiv | EchoFeedback | Special | GroupAtk |
2 | | PMD | PMD | | Envelope | Envelope | | Resonance | | Envelope | WaveUpdate | Mod Speed | Resonance | Filter K2 | | Echo Length | Gain | GroupDec |
3 | | LFO Speed | LFO Speed | | AutoEnvNum | AutoEnvNum | | Special | | AutoEnvNum | WaveLoad W | | Control | Env Count | | | | Noise |
3 | LFOSpd | LFO Speed | LFO Speed | | AutoEnvNum | AutoEnvNum | | Special | | AutoEnvNum | WaveLoad W | | Control | Env Count | | | | Noise |
A | ALG | ALG | ALG | | AutoEnvDen | AutoEnvDen | | | | AutoEnvDen | WaveLoad P | | | Control | | | | |
B | FB | FB | FB | | | Noise AND | | | | | WaveLoad L | | | | | | | |
C | FMS | FMS | FMS | | | Noise OR | | | | | WaveLoad T | | | | | | | |
@ -144,4 +144,4 @@ ex | FM | OPM | OPZ | OPLL | AY-3-8910 | AY8930 | Lynx
5 | | | AMD2 | | | | | | | | | | | EnvRampR | | | | |
6 | | | PMD2 | | | | | | | | | | | EnvRampK1 | | | | |
7 | | | LFO2Speed | | | | | | | | | | | EnvRampK2 | | | | |
8 | | | LFO2Shape | | | | | | | | | | | Env Mode | | | | |
8 | | | LFO2Shape | | | | | | | | | | | Env Mode | | | | |

View file

@ -32,6 +32,8 @@ these fields are 0 in format versions prior to 100 (0.6pre1).
the format versions are:
- 138: Furnace dev138
- 137: Furnace dev137
- 136: Furnace dev136
- 135: Furnace dev135
- 134: Furnace dev134
@ -398,6 +400,9 @@ size | description
4?? | patchbay
| - see next section for more details.
1 | automatic patchbay (>=136)
--- | **a couple more compat flags** (>=138)
1 | broken portamento during legato
7 | reserved
```
# patchbay

View file

@ -58,7 +58,7 @@ bool TAMidiInRtMidi::gather() {
if (m.type!=TA_MIDI_SYSEX && msg.size()>1) {
memcpy(m.data,msg.data()+1,MIN(msg.size()-1,7));
} else if (m.type==TA_MIDI_SYSEX) {
m.sysExData.reset(new unsigned char[msg.size()]);
m.sysExData=std::shared_ptr<unsigned char>(new unsigned char[msg.size()],std::default_delete<unsigned char[]>());
m.sysExLen=msg.size();
logD("got a SysEx of length %ld!",msg.size());
memcpy(m.sysExData.get(),msg.data(),msg.size());

View file

@ -47,8 +47,8 @@
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
#define BUSY_END isBusy.unlock(); softLocked=false;
#define DIV_VERSION "dev136"
#define DIV_ENGINE_VERSION 136
#define DIV_VERSION "dev138"
#define DIV_ENGINE_VERSION 138
// for imports
#define DIV_VERSION_MOD 0xff01
#define DIV_VERSION_FC 0xff02

View file

@ -1716,6 +1716,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
if (ds.version<130) {
ds.oldArpStrategy=true;
}
if (ds.version<138) {
ds.brokenPortaLegato=true;
}
ds.isDMF=false;
reader.readS(); // reserved
@ -2221,6 +2224,13 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
if (ds.version>=136) song.patchbayAuto=reader.readC();
if (ds.version>=138) {
ds.brokenPortaLegato=reader.readC();
for (int i=0; i<7; i++) {
reader.readC();
}
}
// read system flags
if (ds.version>=119) {
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();
BUSY_BEGIN_SOFT;
saveLock.lock();
@ -4489,6 +4525,12 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
}
w->writeC(song.patchbayAuto);
// even more compat flags
w->writeC(song.brokenPortaLegato);
for (int i=0; i<7; i++) {
w->writeC(0);
}
blockEndSeek=w->tell();
w->seek(blockStartSeek,SEEK_SET);
w->writeI(blockEndSeek-blockStartSeek-4);

View file

@ -83,6 +83,7 @@ class DivPlatformFMBase: public DivDispatch {
unsigned char lastBusy;
int delay;
bool flushFirst;
unsigned char regPool[512];
short oldWrites[512];
@ -102,7 +103,7 @@ class DivPlatformFMBase: public DivDispatch {
}
}
inline void urgentWrite(unsigned short a, unsigned char v) {
if (!skipRegisterWrites) {
if (!skipRegisterWrites && !flushFirst) {
if (writes.empty()) {
writes.push_back(QueuedWrite(a,v));
} else if (writes.size()>16 || writes.front().addrOrVal) {
@ -118,9 +119,11 @@ class DivPlatformFMBase: public DivDispatch {
friend void putDispatchChan(void*,int,int);
DivPlatformFMBase():DivDispatch(),
lastBusy(0),
delay(0) {}
DivPlatformFMBase():
DivDispatch(),
lastBusy(0),
delay(0),
flushFirst(false) {}
};
#endif

View file

@ -34,7 +34,7 @@ void DivYM2612Interface::ymfm_set_timer(uint32_t tnum, int32_t duration_in_clock
} else if (tnum==0) {
countA=duration_in_clocks;
}
logV("ymfm_set_timer(%d,%d)",tnum,duration_in_clocks);
//logV("ymfm_set_timer(%d,%d)",tnum,duration_in_clocks);
}
void DivYM2612Interface::clock() {
@ -141,23 +141,26 @@ void DivPlatformGenesis::acquire_nuked(short** buf, size_t len) {
os[0]=0; os[1]=0;
for (int i=0; i<6; i++) {
if (!writes.empty() && --delay<0) {
delay=0;
QueuedWrite& w=writes.front();
if (w.addrOrVal) {
OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
//printf("write: %x = %.2x\n",w.addr,w.val);
lastBusy=0;
regPool[w.addr&0x1ff]=w.val;
writes.pop_front();
} else {
lastBusy++;
if (fm.write_busy==0) {
//printf("busycounter: %d\n",lastBusy);
OPN2_Write(&fm,0x0+((w.addr>>8)<<1),w.addr);
w.addrOrVal=true;
if (!writes.empty()) {
if (--delay<0) {
delay=0;
QueuedWrite& w=writes.front();
if (w.addrOrVal) {
//logV("%.3x = %.2x",w.addr,w.val);
OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
lastBusy=0;
regPool[w.addr&0x1ff]=w.val;
writes.pop_front();
} else {
lastBusy++;
if (fm.write_busy==0) {
OPN2_Write(&fm,0x0+((w.addr>>8)<<1),w.addr);
w.addrOrVal=true;
}
}
}
} else {
flushFirst=false;
}
OPN2_Clock(&fm,o); os[0]+=o[0]; os[1]+=o[1];
@ -207,6 +210,8 @@ void DivPlatformGenesis::acquire_ymfm(short** buf, size_t len) {
regPool[w.addr&0x1ff]=w.val;
writes.pop_front();
lastBusy=1;
} else {
flushFirst=false;
}
if (ladder) {
@ -389,6 +394,10 @@ void DivPlatformGenesis::tick(bool sysTick) {
chan[i].state.ams=chan[i].std.ams.val;
rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
}
if (chan[i].std.ex3.had) {
lfoValue=(chan[i].std.ex3.val>7)?0:(8|(chan[i].std.ex3.val&7));
rWrite(0x22,lfoValue);
}
if (chan[i].std.ex4.had && chan[i].active) {
chan[i].opMask=chan[i].std.ex4.val&15;
chan[i].opMaskChanged=true;
@ -454,6 +463,10 @@ void DivPlatformGenesis::tick(bool sysTick) {
for (int i=0; i<512; i++) {
if (pendingWrites[i]!=oldWrites[i]) {
if (i==0x2b && pendingWrites[i]!=0 && !parent->song.brokenDACMode) {
if (chan[5].keyOn) chan[5].keyOn=false;
chan[5].keyOff=true;
}
immWrite(i,pendingWrites[i]&0xff);
oldWrites[i]=pendingWrites[i];
}
@ -586,7 +599,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
}
}
if (c.chan>=5 && chan[c.chan].dacMode) {
if (skipRegisterWrites) break;
//if (skipRegisterWrites) break;
if (ins->type==DIV_INS_AMIGA) { // Furnace mode
if (c.value!=DIV_NOTE_NULL) chan[c.chan].dacSample=ins->amiga.getSample(c.value);
if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) {
@ -1117,14 +1130,20 @@ void DivPlatformGenesis::forceIns() {
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
if (chan[i].active) {
chan[i].keyOn=true;
chan[i].freqChanged=true;
if (i<5 || !chan[i].dacMode) {
chan[i].keyOn=true;
chan[i].freqChanged=true;
}
}
}
immWrite(0x2b,0x00);
//rWrite(0x2a,0x00);
if (chan[5].dacMode) {
rWrite(0x2b,0x80);
chan[5].dacSample=-1;
chan[6].dacSample=-1;
}
immWrite(0x22,lfoValue);
flushFirst=true;
}
void DivPlatformGenesis::toggleRegisterDump(bool enable) {
@ -1151,6 +1170,10 @@ int DivPlatformGenesis::getRegisterPoolSize() {
return 512;
}
float DivPlatformGenesis::getPostAmp() {
return 2.0f;
}
void DivPlatformGenesis::reset() {
while (!writes.empty()) writes.pop_front();
memset(regPool,0,512);
@ -1178,6 +1201,7 @@ void DivPlatformGenesis::reset() {
lfoValue=8;
softPCMTimer=0;
extMode=false;
flushFirst=false;
if (softPCM) {
chan[5].dacMode=true;
@ -1280,6 +1304,7 @@ int DivPlatformGenesis::init(DivEngine* p, int channels, int sugRate, const DivC
dumpWrites=false;
ladder=false;
skipRegisterWrites=false;
flushFirst=false;
for (int i=0; i<10; i++) {
isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer;

View file

@ -114,6 +114,7 @@ class DivPlatformGenesis: public DivPlatformOPN {
void setYMFM(bool use);
bool keyOffAffectsArp(int ch);
bool keyOffAffectsPorta(int ch);
float getPostAmp();
void toggleRegisterDump(bool enable);
void setFlags(const DivConfig& flags);
void notifyInsChange(int ins);

View file

@ -677,6 +677,8 @@ void DivPlatformGenesisExt::forceIns() {
}
}
if (chan[5].dacMode) {
chan[5].dacSample=-1;
chan[6].dacSample=-1;
rWrite(0x2b,0x80);
}
immWrite(0x22,lfoValue);

View file

@ -958,6 +958,10 @@ void DivPlatformOPLL::setYMFM(bool use) {
useYMFM=use;
}
float DivPlatformOPLL::getPostAmp() {
return 1.5f;
}
void DivPlatformOPLL::setFlags(const DivConfig& flags) {
int clockSel=flags.getInt("clockSel",0);
if (clockSel==3) {

View file

@ -95,6 +95,7 @@ class DivPlatformOPLL: public DivDispatch {
void setYMFM(bool use);
bool keyOffAffectsArp(int ch);
bool keyOffAffectsPorta(int ch);
float getPostAmp();
void toggleRegisterDump(bool enable);
void setVRC7(bool vrc);
void setProperDrums(bool pd);

View file

@ -39,6 +39,10 @@ const char** DivPlatformSMS::getRegisterSheet() {
return stereo?regCheatSheetGG:regCheatSheetSN;
}
float DivPlatformSMS::getPostAmp() {
return 1.5f;
}
void DivPlatformSMS::acquire_nuked(short** buf, size_t len) {
int oL=0;
int oR=0;

View file

@ -81,6 +81,7 @@ class DivPlatformSMS: public DivDispatch {
int getOutputCount();
bool keyOffAffectsArp(int ch);
bool keyOffAffectsPorta(int ch);
float getPostAmp();
int getPortaFloor(int ch);
void setFlags(const DivConfig& flags);
void notifyInsDeletion(void* ins);

View file

@ -135,7 +135,7 @@ void DivPlatformTIA::tick(bool sysTick) {
int bf=chan[i].baseFreq;
if (!parent->song.oldArpStrategy) {
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;

View file

@ -903,6 +903,10 @@ bool DivPlatformX1_010::keyOffAffectsArp(int ch) {
return true;
}
float DivPlatformX1_010::getPostAmp() {
return 4.0f;
}
void DivPlatformX1_010::notifyWaveChange(int wave) {
for (int i=0; i<16; i++) {
if (chan[i].wave==wave) {

View file

@ -140,6 +140,7 @@ class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf {
void muteChannel(int ch, bool mute);
int getOutputCount();
bool keyOffAffectsArp(int ch);
float getPostAmp();
void setFlags(const DivConfig& flags);
void notifyWaveChange(int wave);
void notifyInsDeletion(void* ins);

View file

@ -545,6 +545,10 @@ void DivPlatformYM2608::tick(bool sysTick) {
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));
}
if (chan[i].std.ex3.had) {
lfoValue=(chan[i].std.ex3.val>7)?0:(8|(chan[i].std.ex3.val&7));
rWrite(0x22,lfoValue);
}
if (chan[i].std.ex4.had && chan[i].active) {
chan[i].opMask=chan[i].std.ex4.val&15;
chan[i].opMaskChanged=true;

View file

@ -478,6 +478,10 @@ void DivPlatformYM2610::tick(bool sysTick) {
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));
}
if (chan[i].std.ex3.had) {
lfoValue=(chan[i].std.ex3.val>7)?0:(8|(chan[i].std.ex3.val&7));
rWrite(0x22,lfoValue);
}
if (chan[i].std.ex4.had && chan[i].active) {
chan[i].opMask=chan[i].std.ex4.val&15;
chan[i].opMaskChanged=true;

View file

@ -545,6 +545,10 @@ void DivPlatformYM2610B::tick(bool sysTick) {
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));
}
if (chan[i].std.ex3.had) {
lfoValue=(chan[i].std.ex3.val>7)?0:(8|(chan[i].std.ex3.val&7));
rWrite(0x22,lfoValue);
}
if (chan[i].std.ex4.had && chan[i].active) {
chan[i].opMask=chan[i].std.ex4.val&15;
chan[i].opMaskChanged=true;

View file

@ -896,7 +896,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
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)));
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_HINT_LEGATO,i,chan[i].note));
} else {

View file

@ -827,18 +827,15 @@ bool DivSample::resampleBlep(double r) {
unsigned int posInt=0;
double factor=r/(double)rate;
float* sincITable=DivFilterTables::getSincIntegralTable();
float s[16];
memset(s,0,16*sizeof(float));
float* floatData=new float[finalCount];
memset(floatData,0,finalCount*sizeof(float));
if (depth==DIV_SAMPLE_DEPTH_16BIT) {
memset(data16,0,finalCount*sizeof(short));
for (int i=0; i<finalCount; i++) {
if (posInt<samples) {
int result=data16[i]+oldData16[posInt];
if (result<-32768) result=-32768;
if (result>32767) result=32767;
data16[i]=result;
data16[i]=oldData16[posInt];
}
posFrac+=1.0;
@ -853,28 +850,25 @@ bool DivSample::resampleBlep(double r) {
for (int j=0; j<8; j++) {
if (i-j>0) {
float result=data16[i-j]+t1[j]*-delta;
if (result<-32768) result=-32768;
if (result>32767) result=32767;
data16[i-j]=result;
floatData[i-j]+=t1[j]*-delta;
}
if (i+j+1<finalCount) {
float result=data16[i+j+1]+t2[j]*delta;
if (result<-32768) result=-32768;
if (result>32767) result=32767;
data16[i+j+1]=result;
floatData[i+j+1]+=t2[j]*delta;
}
}
}
}
for (int i=0; i<finalCount; i++) {
float result=floatData[i]+data16[i];
if (result<-32768) result=-32768;
if (result>32767) result=32767;
data16[i]=round(result);
}
} else if (depth==DIV_SAMPLE_DEPTH_8BIT) {
memset(data8,0,finalCount);
for (int i=0; i<finalCount; i++) {
if (posInt<samples) {
int result=data8[i]+oldData8[posInt];
if (result<-128) result=-128;
if (result>127) result=127;
data8[i]=result;
data8[i]=oldData8[posInt];
}
posFrac+=1.0;
@ -889,21 +883,22 @@ bool DivSample::resampleBlep(double r) {
for (int j=0; j<8; j++) {
if (i-j>0) {
float result=data8[i-j]+t1[j]*-delta;
if (result<-128) result=-128;
if (result>127) result=127;
data8[i-j]=result;
floatData[i-j]+=t1[j]*-delta;
}
if (i+j+1<finalCount) {
float result=data8[i+j+1]+t2[j]*delta;
if (result<-128) result=-128;
if (result>127) result=127;
data8[i+j+1]=result;
floatData[i+j+1]+=t2[j]*delta;
}
}
}
}
for (int i=0; i<finalCount; i++) {
float result=floatData[i]+data16[i];
if (result<-128) result=-128;
if (result>127) result=127;
data16[i]=round(result);
}
}
delete[] floatData;
RESAMPLE_END;
return true;

View file

@ -330,6 +330,7 @@ struct DivSong {
bool autoSystem;
bool oldArpStrategy;
bool patchbayAuto;
bool brokenPortaLegato;
std::vector<DivInstrument*> ins;
std::vector<DivWavetable*> wave;
@ -439,7 +440,8 @@ struct DivSong {
disableSampleMacro(false),
autoSystem(true),
oldArpStrategy(false),
patchbayAuto(true) {
patchbayAuto(true),
brokenPortaLegato(false) {
for (int i=0; i<DIV_MAX_CHIPS; i++) {
system[i]=DIV_SYSTEM_NULL;
systemVol[i]=1.0;

View file

@ -1046,7 +1046,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_SMS:
if (!hasSN) {
hasSN=disCont[i].dispatch->chipClock;
CHIP_VOL(0,2.0);
CHIP_VOL(0,4.0);
willExport[i]=true;
switch (song.systemFlags[i].getInt("chipType",0)) {
case 1: // real SN
@ -1065,7 +1065,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
} else if (!(hasSN&0x40000000)) {
isSecond[i]=true;
willExport[i]=true;
CHIP_VOL_SECOND(0,2.0);
CHIP_VOL_SECOND(0,4.0);
hasSN|=0x40000000;
howManyChips++;
}
@ -1130,12 +1130,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_X1_010:
if (!hasX1) {
hasX1=disCont[i].dispatch->chipClock;
CHIP_VOL(38,0.5);
CHIP_VOL(38,2.0);
willExport[i]=true;
writeX1010[0]=disCont[i].dispatch;
} else if (!(hasX1&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(38,0.5);
CHIP_VOL_SECOND(38,2.0);
willExport[i]=true;
writeX1010[1]=disCont[i].dispatch;
hasX1|=0x40000000;
@ -1232,12 +1232,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_YM2612_DUALPCM_EXT:
if (!hasOPN2) {
hasOPN2=disCont[i].dispatch->chipClock;
CHIP_VOL(2,0.8);
CHIP_VOL(2,1.6);
willExport[i]=true;
writeDACSamples=true;
} else if (!(hasOPN2&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(2,0.8);
CHIP_VOL_SECOND(2,1.6);
willExport[i]=true;
hasOPN2|=0x40000000;
howManyChips++;
@ -1296,11 +1296,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_VRC7:
if (!hasOPLL) {
hasOPLL=disCont[i].dispatch->chipClock;
CHIP_VOL(1,1.6);
CHIP_VOL(1,3.2);
willExport[i]=true;
} else if (!(hasOPLL&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(1,1.6);
CHIP_VOL_SECOND(1,3.2);
willExport[i]=true;
hasOPLL|=0x40000000;
howManyChips++;

View file

@ -69,6 +69,7 @@ const char* aboutLine[]={
"brickblock369",
"Burnt Fishy",
"CaptainMalware",
"Clingojam",
"DeMOSic",
"DevEd",
"Dippy",

View file

@ -214,7 +214,7 @@ void FurnaceGUI::drawCompatFlags() {
e->song.delayBehavior=2;
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("no checks (like FamiTracker)");
ImGui::SetTooltip("no checks");
}
ImGui::Text("Simultaneous jump (0B+0D) treatment:");
@ -293,6 +293,10 @@ void FurnaceGUI::drawCompatFlags() {
if (ImGui::IsItemHovered()) {
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;
ImGui::End();

View file

@ -163,7 +163,7 @@ void FurnaceGUI::doAction(int what) {
case GUI_ACTION_TX81Z_REQUEST: {
TAMidiMessage msg;
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;
memcpy(msg.sysExData.get(),avRequest,15);
if (!e->sendMidiMessage(msg)) {

View file

@ -506,7 +506,9 @@ void FurnaceGUI::drawMobileControls() {
ImGui::SameLine();
ImGui::Button("Legacy .dmf");
ImGui::SameLine();
ImGui::Button("Export Audio");
if (ImGui::Button("Export Audio")) {
openFileDialog(GUI_FILE_EXPORT_AUDIO_ONE);
}
ImGui::SameLine();
if (ImGui::Button("Export VGM")) {
openFileDialog(GUI_FILE_EXPORT_VGM);

View file

@ -3132,6 +3132,14 @@ bool FurnaceGUI::loop() {
break;
case SDL_DISPLAYEVENT: {
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:
logD("display oriented to %d",ev.display.data1);
updateWindow=true;

View file

@ -1295,6 +1295,7 @@ class FurnaceGUI {
double exportFadeOut;
int macroLayout;
float doubleClickTime;
int oneDigitEffects;
unsigned int maxUndoSteps;
String mainFontPath;
String patFontPath;
@ -1430,6 +1431,7 @@ class FurnaceGUI {
exportFadeOut(0.0),
macroLayout(0),
doubleClickTime(0.3f),
oneDigitEffects(0),
maxUndoSteps(100),
mainFontPath(""),
patFontPath(""),

View file

@ -352,6 +352,10 @@ const int detuneUnmap[2][11]={
{0, 0, 0, 3, 4, 5, 6, 7, 2, 1, 0}
};
const int kslMap[4]={
0, 2, 1, 3
};
// do not change these!
// anything other than a checkbox will look ugly!
//
@ -2778,7 +2782,11 @@ void FurnaceGUI::drawInsEdit() {
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) {
P(CWVSliderScalar("##RS",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE));
} else {
P(CWVSliderScalar("##KSL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE));
int ksl=ins->type==DIV_INS_OPLL?op.ksl:kslMap[op.ksl&3];
if (CWVSliderInt("##KSL",ImVec2(20.0f*dpiScale,sliderHeight),&ksl,0,3)) {
op.ksl=(ins->type==DIV_INS_OPLL?ksl:kslMap[ksl&3]);
PARAMETER;
}
}
if (ins->type==DIV_INS_OPZ) {
@ -3226,7 +3234,7 @@ void FurnaceGUI::drawInsEdit() {
break;
case DIV_INS_OPL:
case DIV_INS_OPL_DRUMS:
case DIV_INS_OPL_DRUMS: {
// waveform
drawWaveform(op.ws&7,ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight));
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -3268,9 +3276,14 @@ void FurnaceGUI::drawInsEdit() {
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_KSL));
P(CWSliderScalar("##KSL",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE,tempID)); rightClickable
int ksl=kslMap[op.ksl&3];
if (CWSliderInt("##KSL",&ksl,0,3,tempID)) {
op.ksl=kslMap[ksl&3];
PARAMETER;
} rightClickable
break;
}
case DIV_INS_OPZ: {
// waveform
drawWaveform(op.ws&7,ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight));
@ -3613,7 +3626,11 @@ void FurnaceGUI::drawInsEdit() {
ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_RS));
} else {
P(CWSliderScalar("##KSL",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE)); rightClickable
int ksl=ins->type==DIV_INS_OPLL?op.ksl:kslMap[op.ksl&3];
if (CWSliderInt("##KSL",&ksl,0,3)) {
op.ksl=(ins->type==DIV_INS_OPLL?ksl:kslMap[ksl&3]);
PARAMETER;
} rightClickable
ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_KSL));
}
@ -3779,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) {
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]));

View file

@ -287,10 +287,14 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
if (pat->data[i][index]>0xff) {
snprintf(id,63,"??##PE%d_%d_%d",k,i,j);
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];
snprintf(id,63,"%.2X##PE%d_%d_%d",data,k,i,j);
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);

View file

@ -1602,6 +1602,11 @@ void FurnaceGUI::drawSettings() {
settings.germanNotation=germanNotationB;
}
bool oneDigitEffectsB=settings.oneDigitEffects;
if (ImGui::Checkbox("Single-digit effects for 00-0F",&oneDigitEffectsB)) {
settings.oneDigitEffects=oneDigitEffectsB;
}
bool centerPatternB=settings.centerPattern;
if (ImGui::Checkbox("Center pattern view",&centerPatternB)) {
settings.centerPattern=centerPatternB;
@ -2565,6 +2570,7 @@ void FurnaceGUI::syncSettings() {
settings.exportFadeOut=e->getConfDouble("exportFadeOut",0.0);
settings.macroLayout=e->getConfInt("macroLayout",0);
settings.doubleClickTime=e->getConfFloat("doubleClickTime",0.3f);
settings.oneDigitEffects=e->getConfInt("oneDigitEffects",0);
clampSetting(settings.mainFontSize,2,96);
clampSetting(settings.patFontSize,2,96);
@ -2676,6 +2682,7 @@ void FurnaceGUI::syncSettings() {
clampSetting(settings.persistFadeOut,0,1);
clampSetting(settings.macroLayout,0,4);
clampSetting(settings.doubleClickTime,0.02,1.0);
clampSetting(settings.oneDigitEffects,0,1);
if (settings.exportLoops<0.0) settings.exportLoops=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("macroLayout",settings.macroLayout);
e->setConf("doubleClickTime",settings.doubleClickTime);
e->setConf("oneDigitEffects",settings.oneDigitEffects);
// colors
for (int i=0; i<GUI_COLOR_MAX; i++) {