Merge branch 'master' of https://github.com/tildearrow/furnace into ymf289b

This commit is contained in:
cam900 2023-01-16 10:17:19 +09:00
commit 371c82338f
18 changed files with 270 additions and 93 deletions

View file

@ -11,7 +11,7 @@ defaults:
shell: bash
env:
BUILD_TYPE: Debug
BUILD_TYPE: Release
jobs:
build:
@ -20,11 +20,11 @@ jobs:
config:
- { name: 'Windows MSVC x86', os: windows-latest, compiler: msvc, arch: x86 }
- { name: 'Windows MSVC x86_64', os: windows-latest, compiler: msvc, arch: x86_64 }
##- { name: 'Windows MinGW x86', os: ubuntu-20.04, compiler: mingw, arch: x86 }
##- { name: 'Windows MinGW x86_64', os: ubuntu-20.04, compiler: mingw, arch: x86_64 }
- { name: 'Windows MinGW x86', os: ubuntu-20.04, compiler: mingw, arch: x86 }
- { name: 'Windows MinGW x86_64', os: ubuntu-20.04, compiler: mingw, arch: x86_64 }
- { name: 'macOS x86_64', os: macos-latest, arch: x86_64 }
- { name: 'macOS ARM', os: macos-latest, arch: arm64 }
##- { name: 'Linux x86_64', os: ubuntu-18.04, arch: x86_64 }
- { name: 'Linux x86_64', os: ubuntu-18.04, arch: x86_64 }
#- { name: 'Linux ARM', os: ubuntu-18.04, arch: armhf }
fail-fast: false

Binary file not shown.

Binary file not shown.

View file

@ -442,7 +442,7 @@ class DivEngine {
void processRow(int i, bool afterDelay);
void nextOrder();
void nextRow();
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, bool directStream);
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, bool directStream);
// returns true if end of song.
bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);

View file

@ -586,7 +586,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) {
@ -1122,6 +1122,8 @@ void DivPlatformGenesis::forceIns() {
}
}
if (chan[5].dacMode) {
chan[5].dacSample=-1;
chan[6].dacSample=-1;
rWrite(0x2b,0x80);
}
immWrite(0x22,lfoValue);

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

@ -1518,7 +1518,7 @@ DivMacroInt* DivPlatformOPL::getChanMacroInt(int ch) {
}
DivDispatchOscBuffer* DivPlatformOPL::getOscBuffer(int ch) {
if (ch>=18) return NULL;
if (ch>=totalChans) return NULL;
if (oplType==3 && ch<12) {
if (chan[ch&(~1)].fourOp) {
if (ch&1) {

View file

@ -17,13 +17,13 @@
void SoundUnit::NextSample(short* l, short* r) {
// run channels
for (int i=0; i<8; i++) {
if (chan[i].vol==0 && !chan[i].flags.swvol) {
if (chan[i].vol==0 && !chan[i].flags1.swvol) {
fns[i]=0;
continue;
}
if (chan[i].flags.pcm) {
if (chan[i].flags0.pcm) {
ns[i]=pcm[chan[i].pcmpos];
} else switch (chan[i].flags.shape) {
} else switch (chan[i].flags0.shape) {
case 0:
ns[i]=(((cycle[i]>>15)&127)>chan[i].duty)*127;
break;
@ -47,11 +47,11 @@ void SoundUnit::NextSample(short* l, short* r) {
break;
}
if (chan[i].flags.ring) {
if (chan[i].flags0.ring) {
ns[i]=(ns[i]*ns[(i+1)&7])>>7;
}
if (chan[i].flags.pcm) {
if (chan[i].flags0.pcm) {
if (chan[i].freq>0x8000) {
pcmdec[i]+=0x8000;
} else {
@ -62,18 +62,18 @@ void SoundUnit::NextSample(short* l, short* r) {
if (chan[i].pcmpos<chan[i].pcmbnd) {
chan[i].pcmpos++;
if (chan[i].pcmpos==chan[i].pcmbnd) {
if (chan[i].flags.pcmloop) {
if (chan[i].flags1.pcmloop) {
chan[i].pcmpos=chan[i].pcmrst;
}
}
chan[i].pcmpos&=(pcmSize-1);
} else if (chan[i].flags.pcmloop) {
} else if (chan[i].flags1.pcmloop) {
chan[i].pcmpos=chan[i].pcmrst;
}
}
} else {
ocycle[i]=cycle[i];
if (chan[i].flags.shape==5) {
if (chan[i].flags0.shape==5) {
switch ((chan[i].duty>>4)&3) {
case 0:
cycle[i]+=chan[i].freq*1-(chan[i].freq>>3);
@ -92,7 +92,7 @@ void SoundUnit::NextSample(short* l, short* r) {
cycle[i]+=chan[i].freq;
}
if ((cycle[i]&0xf80000)!=(ocycle[i]&0xf80000)) {
if (chan[i].flags.shape==4) {
if (chan[i].flags0.shape==4) {
lfsr[i]=(lfsr[i]>>1|(((lfsr[i]) ^ (lfsr[i] >> 2) ^ (lfsr[i] >> 3) ^ (lfsr[i] >> 5) ) & 1)<<31);
} else {
switch ((chan[i].duty>>4)&3) {
@ -114,7 +114,7 @@ void SoundUnit::NextSample(short* l, short* r) {
}
}
}
if (chan[i].flags.restim) {
if (chan[i].flags1.restim) {
if (--rcycle[i]<=0) {
cycle[i]=0;
rcycle[i]=chan[i].restimer;
@ -122,19 +122,18 @@ void SoundUnit::NextSample(short* l, short* r) {
}
}
}
fns[i]=ns[i]*chan[i].vol*(chan[i].flags.pcm?4:2);
if (chan[i].flags.fmode!=0) {
fns[i]=ns[i]*chan[i].vol*(chan[i].flags0.pcm?4:2);
if (chan[i].flags0.fmode!=0) {
int ff=chan[i].cutoff;
nslow[i]=nslow[i]+(((ff)*nsband[i])>>16);
nshigh[i]=fns[i]-nslow[i]-(((256-chan[i].reson)*nsband[i])>>8);
nsband[i]=(((ff)*nshigh[i])>>16)+nsband[i];
fns[i]=(((chan[i].flags.fmode&1)?(nslow[i]):(0))+((chan[i].flags.fmode&2)?(nshigh[i]):(0))+((chan[i].flags.fmode&4)?(nsband[i]):(0)));
fns[i]=(((chan[i].flags0.fmode&1)?(nslow[i]):(0))+((chan[i].flags0.fmode&2)?(nshigh[i]):(0))+((chan[i].flags0.fmode&4)?(nsband[i]):(0)));
}
nsL[i]=(fns[i]*SCpantabL[(unsigned char)chan[i].pan])>>8;
nsR[i]=(fns[i]*SCpantabR[(unsigned char)chan[i].pan])>>8;
oldfreq[i]=chan[i].freq;
oldflags[i]=chan[i].flags.flags;
if (chan[i].flags.swvol) {
if (chan[i].flags1.swvol) {
if (--swvolt[i]<=0) {
swvolt[i]=chan[i].swvol.speed;
if (chan[i].swvol.dir) {
@ -174,7 +173,7 @@ void SoundUnit::NextSample(short* l, short* r) {
}
}
}
if (chan[i].flags.swfreq) {
if (chan[i].flags1.swfreq) {
if (--swfreqt[i]<=0) {
swfreqt[i]=chan[i].swfreq.speed;
if (chan[i].swfreq.dir) {
@ -198,7 +197,7 @@ void SoundUnit::NextSample(short* l, short* r) {
}
}
}
if (chan[i].flags.swcut) {
if (chan[i].flags1.swcut) {
if (--swcutt[i]<=0) {
swcutt[i]=chan[i].swcut.speed;
if (chan[i].swcut.dir) {
@ -222,11 +221,11 @@ void SoundUnit::NextSample(short* l, short* r) {
}
}
}
if (chan[i].flags.resosc) {
if (chan[i].flags1.resosc) {
cycle[i]=0;
rcycle[i]=chan[i].restimer;
ocycle[i]=0;
chan[i].flags.resosc=0;
chan[i].flags1.resosc=0;
}
if (muted[i]) {
nsL[i]=0;
@ -377,7 +376,6 @@ void SoundUnit::Reset() {
swcutt[i]=1;
lfsr[i]=0xaaaa;
oldfreq[i]=0;
oldflags[i]=0;
pcmdec[i]=0;
}
dsCounterL=0;

View file

@ -25,7 +25,6 @@ class SoundUnit {
signed char ilFeedback0;
signed char ilFeedback1;
unsigned short oldfreq[8];
unsigned short oldflags[8];
unsigned int pcmSize;
bool dsOut;
short dsCounterL, dsCounterR;
@ -44,12 +43,17 @@ class SoundUnit {
signed char vol;
signed char pan;
union {
unsigned short flags;
unsigned char val;
struct {
unsigned char shape: 3;
unsigned char pcm: 1;
unsigned char ring: 1;
unsigned char fmode: 3;
};
} flags0;
union {
unsigned char val;
struct {
unsigned char resosc: 1;
unsigned char resfilt: 1;
unsigned char pcmloop: 1;
@ -59,7 +63,7 @@ class SoundUnit {
unsigned char swcut: 1;
unsigned char padding: 1;
};
} flags;
} flags1;
unsigned short cutoff;
unsigned char duty;
unsigned char reson;

View file

@ -22,6 +22,7 @@
#include <math.h>
#define rWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);}}
#define postWrite(a,v) postDACWrites.emplace(a,v);
#define CHIP_DIVIDER 32
@ -186,7 +187,7 @@ void DivPlatformSwan::tick(bool sysTick) {
}
}
dacRate=((double)chipClock/2)/MAX(1,off*chan[i].freq);
if (dumpWrites) addWrite(0xffff0001,dacRate);
if (dumpWrites) postWrite(0xffff0001,dacRate);
}
if (chan[i].freq>2048) chan[i].freq=2048;
if (chan[i].freq<1) chan[i].freq=1;
@ -217,6 +218,12 @@ void DivPlatformSwan::tick(bool sysTick) {
}
}
rWrite(0x10,sndCtrl);
while (!postDACWrites.empty()) {
const DivRegWrite& w=postDACWrites.back();
if (dumpWrites) addWrite(w.addr,w.val);
postDACWrites.pop();
}
}
int DivPlatformSwan::dispatch(DivCommand c) {
@ -237,11 +244,11 @@ int DivPlatformSwan::dispatch(DivCommand c) {
if (c.value!=DIV_NOTE_NULL) dacSample=ins->amiga.getSample(c.value);
if (dacSample<0 || dacSample>=parent->song.sampleLen) {
dacSample=-1;
if (dumpWrites) addWrite(0xffff0002,0);
if (dumpWrites) postWrite(0xffff0002,0);
break;
} else {
if (dumpWrites) {
addWrite(0xffff0000,dacSample);
postWrite(0xffff0000,dacSample);
}
}
if (c.value!=DIV_NOTE_NULL) {
@ -260,14 +267,14 @@ int DivPlatformSwan::dispatch(DivCommand c) {
dacSample=12*sampleBank+chan[1].note%12;
if (dacSample>=parent->song.sampleLen) {
dacSample=-1;
if (dumpWrites) addWrite(0xffff0002,0);
if (dumpWrites) postWrite(0xffff0002,0);
break;
} else {
if (dumpWrites) addWrite(0xffff0000,dacSample);
if (dumpWrites) postWrite(0xffff0000,dacSample);
}
dacRate=parent->getSample(dacSample)->rate;
if (dumpWrites) {
addWrite(0xffff0001,dacRate);
postWrite(0xffff0001,dacRate);
}
chan[1].active=true;
chan[1].keyOn=true;
@ -298,7 +305,7 @@ int DivPlatformSwan::dispatch(DivCommand c) {
case DIV_CMD_NOTE_OFF:
if (c.chan==1&&pcm) {
dacSample=-1;
if (dumpWrites) addWrite(0xffff0002,0);
if (dumpWrites) postWrite(0xffff0002,0);
pcm=false;
}
chan[c.chan].active=false;
@ -463,6 +470,7 @@ int DivPlatformSwan::getRegisterPoolSize() {
void DivPlatformSwan::reset() {
while (!writes.empty()) writes.pop();
while (!postDACWrites.empty()) postDACWrites.pop();
memset(regPool,0,128);
for (int i=0; i<4; i++) {
chan[i]=Channel();

View file

@ -51,6 +51,7 @@ class DivPlatformSwan: public DivDispatch {
QueuedWrite(unsigned char a, unsigned char v): addr(a), val(v) {}
};
std::queue<QueuedWrite> writes;
std::queue<DivRegWrite> postDACWrites;
WSwan* ws;
void updateWave(int ch);
friend void putDispatchChip(void*,int);

View file

@ -136,7 +136,9 @@ float SafeReader::readF() {
memcpy(&ret,&buf[curSeek],4);
curSeek+=4;
ret=((ret>>24)|((ret&0xff0000)>>8)|((ret&0xff00)<<8)|((ret&0xff)<<24));
return *((float*)(&ret));
float realRet;
memcpy(&realRet,&ret,4);
return realRet;
}
double SafeReader::readD() {
@ -153,7 +155,9 @@ double SafeReader::readD() {
retB[5]=ret[2];
retB[6]=ret[1];
retB[7]=ret[0];
return *((double*)retB);
double realRet;
memcpy(&realRet,retB,8);
return realRet;
}
#else
short SafeReader::readS() {

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

@ -24,7 +24,7 @@
constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0;
void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, bool directStream) {
void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, bool directStream) {
unsigned char baseAddr1=isSecond?0xa0:0x50;
unsigned char baseAddr2=isSecond?0x80:0;
unsigned short baseAddr2S=isSecond?0x8000:0;
@ -541,14 +541,19 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
switch (write.addr&0xff) {
case 0: // play sample
if (write.val<song.sampleLen) {
DivSample* sample=song.sample[write.val];
w->writeC(0x95);
w->writeC(streamID);
w->writeS(write.val); // sample number
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0)|(sampleDir[streamID]?0x10:0)); // flags
if (sample->isLoopable() && !sampleDir[streamID]) {
loopTimer[streamID]=sample->length8;
loopSample[streamID]=write.val;
if (playingSample[streamID]!=write.val) {
pendingFreq[streamID]=write.val;
} else {
DivSample* sample=song.sample[write.val];
w->writeC(0x95);
w->writeC(streamID);
w->writeS(write.val); // sample number
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0)|(sampleDir[streamID]?0x10:0)); // flags
if (sample->isLoopable() && !sampleDir[streamID]) {
loopTimer[streamID]=sample->length8;
loopSample[streamID]=write.val;
}
playingSample[streamID]=write.val;
}
}
break;
@ -557,11 +562,26 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
w->writeC(streamID);
w->writeI(write.val);
loopFreq[streamID]=write.val;
if (pendingFreq[streamID]!=-1) {
DivSample* sample=song.sample[pendingFreq[streamID]];
w->writeC(0x95);
w->writeC(streamID);
w->writeS(pendingFreq[streamID]); // sample number
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0)|(sampleDir[streamID]?0x10:0)); // flags
if (sample->isLoopable() && !sampleDir[streamID]) {
loopTimer[streamID]=sample->length8;
loopSample[streamID]=pendingFreq[streamID];
}
playingSample[streamID]=pendingFreq[streamID];
pendingFreq[streamID]=-1;
}
break;
case 2: // stop sample
w->writeC(0x94);
w->writeC(streamID);
loopSample[streamID]=-1;
playingSample[streamID]=-1;
pendingFreq[streamID]=-1;
break;
case 3: // set sample direction
sampleDir[streamID]=write.val;
@ -863,16 +883,20 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
}
#define CHIP_VOL(_id,_mult) { \
double _vol=fabs((float)song.systemVol[i])*4.0*_mult; \
double _vol=fabs((float)song.systemVol[i])*256.0*_mult; \
if (_vol<0.0) _vol=0.0; \
if (_vol>32767.0) _vol=32767.0; \
chipVolSum+=(unsigned int)(_vol/_mult); \
chipAccounting++; \
chipVol.push_back((_id)|(0x80000000)|(((unsigned int)_vol)<<16)); \
}
#define CHIP_VOL_SECOND(_id,_mult) { \
double _vol=fabs((float)song.systemVol[i])*4.0*_mult; \
double _vol=fabs((float)song.systemVol[i])*256.0*_mult; \
if (_vol<0.0) _vol=0.0; \
if (_vol>32767.0) _vol=32767.0; \
chipVolSum+=(unsigned int)(_vol/_mult); \
chipAccounting++; \
chipVol.push_back((_id)|(0x80000100)|(((unsigned int)_vol)<<16)); \
}
@ -957,6 +981,8 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
int hasLynx=0;
int howManyChips=0;
int chipVolSum=0;
int chipAccounting=0;
int loopPos=-1;
int loopTick=-1;
@ -979,6 +1005,8 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
double loopFreq[DIV_MAX_CHANS];
int loopSample[DIV_MAX_CHANS];
bool sampleDir[DIV_MAX_CHANS];
int pendingFreq[DIV_MAX_CHANS];
int playingSample[DIV_MAX_CHANS];
std::vector<unsigned int> chipVol;
std::vector<DivDelayedWrite> delayedWrites[DIV_MAX_CHIPS];
std::vector<std::pair<int,DivDelayedWrite>> sortedWrites;
@ -987,6 +1015,8 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
loopTimer[i]=0;
loopFreq[i]=0;
loopSample[i]=-1;
pendingFreq[i]=-1;
playingSample[i]=-1;
sampleDir[i]=false;
}
@ -1016,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,1.0);
CHIP_VOL(0,2.0);
willExport[i]=true;
switch (song.systemFlags[i].getInt("chipType",0)) {
case 1: // real SN
@ -1035,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,1.0);
CHIP_VOL_SECOND(0,2.0);
hasSN|=0x40000000;
howManyChips++;
}
@ -1043,9 +1073,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_GB:
if (!hasGB) {
hasGB=disCont[i].dispatch->chipClock;
CHIP_VOL(19,0.75);
willExport[i]=true;
} else if (!(hasGB&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(19,0.75);
willExport[i]=true;
hasGB|=0x40000000;
howManyChips++;
@ -1054,10 +1086,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_PCE:
if (!hasPCE) {
hasPCE=disCont[i].dispatch->chipClock;
CHIP_VOL(27,0.98);
willExport[i]=true;
writePCESamples=true;
} else if (!(hasPCE&0x40000000)) {
isSecond[i]=true;
CHIP_VOL(27,0.98);
willExport[i]=true;
hasPCE|=0x40000000;
howManyChips++;
@ -1066,10 +1100,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_NES:
if (!hasNES) {
hasNES=disCont[i].dispatch->chipClock;
CHIP_VOL(20,1.7);
willExport[i]=true;
writeNESSamples=true;
} else if (!(hasNES&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(20,1.7);
willExport[i]=true;
hasNES|=0x40000000;
howManyChips++;
@ -1079,10 +1115,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_SEGAPCM_COMPAT:
if (!hasSegaPCM) {
hasSegaPCM=4000000;
CHIP_VOL(4,0.67);
willExport[i]=true;
writeSegaPCM=1;
} else if (!(hasSegaPCM&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(4,0.67);
willExport[i]=true;
writeSegaPCM=2;
hasSegaPCM|=0x40000000;
@ -1092,10 +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);
willExport[i]=true;
writeX1010[0]=disCont[i].dispatch;
} else if (!(hasX1&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(38,0.5);
willExport[i]=true;
writeX1010[1]=disCont[i].dispatch;
hasX1|=0x40000000;
@ -1110,10 +1150,14 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_YM2610B_EXT:
if (!hasOPNB) {
hasOPNB=disCont[i].dispatch->chipClock;
CHIP_VOL(8,1.0);
CHIP_VOL(0x88,1.25);
willExport[i]=true;
writeADPCM_OPNB[0]=disCont[i].dispatch;
} else if (!(hasOPNB&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(8,1.0);
CHIP_VOL_SECOND(0x88,1.25);
willExport[i]=true;
writeADPCM_OPNB[1]=disCont[i].dispatch;
hasOPNB|=0x40000000;
@ -1158,9 +1202,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
if (hasStereo && song.systemFlags[i].getBool("stereo",false)) {
ayFlags|=0x80;
}
CHIP_VOL(18,1.0);
willExport[i]=true;
} else if (!(hasAY&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(18,1.0);
willExport[i]=true;
hasAY|=0x40000000;
howManyChips++;
@ -1170,9 +1216,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_SAA1099:
if (!hasSAA) {
hasSAA=disCont[i].dispatch->chipClock;
CHIP_VOL(35,1.0);
willExport[i]=true;
} else if (!(hasSAA&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(35,1.0);
willExport[i]=true;
hasSAA|=0x40000000;
howManyChips++;
@ -1184,10 +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);
willExport[i]=true;
writeDACSamples=true;
} else if (!(hasOPN2&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(2,0.8);
willExport[i]=true;
hasOPN2|=0x40000000;
howManyChips++;
@ -1196,9 +1246,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_YM2151:
if (!hasOPM) {
hasOPM=disCont[i].dispatch->chipClock;
CHIP_VOL(3,1.0);
willExport[i]=true;
} else if (!(hasOPM&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(3,1.0);
willExport[i]=true;
hasOPM|=0x40000000;
howManyChips++;
@ -1209,10 +1261,14 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
if (!hasOPN) {
hasOPN=disCont[i].dispatch->chipClock;
willExport[i]=true;
CHIP_VOL(6,1.0);
CHIP_VOL(0x86,1.7);
writeDACSamples=true;
} else if (!(hasOPN&0x40000000)) {
isSecond[i]=true;
willExport[i]=true;
CHIP_VOL_SECOND(6,1.0);
CHIP_VOL_SECOND(0x86,1.7);
hasOPN|=0x40000000;
howManyChips++;
}
@ -1221,10 +1277,14 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_YM2608_EXT:
if (!hasOPNA) {
hasOPNA=disCont[i].dispatch->chipClock;
CHIP_VOL(7,1.0);
CHIP_VOL(0x87,1.3);
willExport[i]=true;
writeADPCM_OPNA[0]=disCont[i].dispatch;
} else if (!(hasOPNA&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(7,1.0);
CHIP_VOL_SECOND(0x87,1.3);
willExport[i]=true;
writeADPCM_OPNA[1]=disCont[i].dispatch;
hasOPNA|=0x40000000;
@ -1236,9 +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);
willExport[i]=true;
} else if (!(hasOPLL&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(1,1.6);
willExport[i]=true;
hasOPLL|=0x40000000;
howManyChips++;
@ -1261,9 +1323,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_POKEY:
if (!hasPOKEY) {
hasPOKEY=disCont[i].dispatch->chipClock;
CHIP_VOL(30,0.8);
willExport[i]=true;
} else if (!(hasPOKEY&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(30,0.8);
willExport[i]=true;
hasPOKEY|=0x40000000;
howManyChips++;
@ -1286,10 +1350,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
// However I think it it not necessary because old VGM players will still
// not be able to handle the 64kb sample bank trick
hasQSound=disCont[i].dispatch->chipClock;
CHIP_VOL(31,1.0);
willExport[i]=true;
writeQSound[0]=disCont[i].dispatch;
} else if (!(hasQSound&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(31,1.0);
willExport[i]=false;
writeQSound[1]=disCont[i].dispatch;
addWarning("dual QSound is not supported by the VGM format");
@ -1298,6 +1364,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_SWAN:
if (!hasSwan) {
hasSwan=disCont[i].dispatch->chipClock;
CHIP_VOL(33,1.0);
willExport[i]=true;
// funny enough, VGM doesn't have support for WSC's sound DMA by design
// so DAC stream it goes
@ -1305,6 +1372,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
writeDACSamples=true;
} else if (!(hasSwan&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(33,1.0);
willExport[i]=true;
hasSwan|=0x40000000;
howManyChips++;
@ -1313,9 +1381,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_VBOY:
if (!hasVSU) {
hasVSU=disCont[i].dispatch->chipClock;
CHIP_VOL(34,0.72);
willExport[i]=true;
} else if (!(hasVSU&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(34,0.72);
willExport[i]=true;
hasVSU|=0x40000000;
howManyChips++;
@ -1325,9 +1395,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_OPL_DRUMS:
if (!hasOPL) {
hasOPL=disCont[i].dispatch->chipClock;
CHIP_VOL(9,1.0);
willExport[i]=true;
} else if (!(hasOPL&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(9,1.0);
willExport[i]=true;
hasOPL|=0x40000000;
howManyChips++;
@ -1337,10 +1409,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_Y8950_DRUMS:
if (!hasY8950) {
hasY8950=disCont[i].dispatch->chipClock;
CHIP_VOL(11,1.0);
willExport[i]=true;
writeADPCM_Y8950[0]=disCont[i].dispatch;
} else if (!(hasY8950&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(11,1.0);
willExport[i]=true;
writeADPCM_Y8950[1]=disCont[i].dispatch;
hasY8950|=0x40000000;
@ -1351,9 +1425,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_OPL2_DRUMS:
if (!hasOPL2) {
hasOPL2=disCont[i].dispatch->chipClock;
CHIP_VOL(10,1.0);
willExport[i]=true;
} else if (!(hasOPL2&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(10,1.0);
willExport[i]=true;
hasOPL2|=0x40000000;
howManyChips++;
@ -1363,9 +1439,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_OPL3_DRUMS:
if (!hasOPL3) {
hasOPL3=disCont[i].dispatch->chipClock;
CHIP_VOL(12,1.0);
willExport[i]=true;
} else if (!(hasOPL3&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(12,1.0);
willExport[i]=true;
hasOPL3|=0x40000000;
howManyChips++;
@ -1378,9 +1456,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
if (song.system[i]==DIV_SYSTEM_SCC_PLUS) {
hasK051649|=0x80000000;
}
CHIP_VOL(25,1.0);
willExport[i]=true;
} else if (!(hasK051649&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(25,1.0);
willExport[i]=true;
hasK051649|=0x40000000;
if (song.system[i]==DIV_SYSTEM_SCC_PLUS) {
@ -1392,10 +1472,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_YMZ280B:
if (!hasZ280) {
hasZ280=disCont[i].dispatch->chipClock;
CHIP_VOL(15,0.72);
willExport[i]=true;
writeZ280[0]=disCont[i].dispatch;
} else if (!(hasZ280&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(15,0.72);
willExport[i]=true;
writeZ280[1]=disCont[i].dispatch;
hasZ280|=0x40000000;
@ -1411,11 +1493,13 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
if (!hasRFC1) {
hasRFC1=disCont[i].dispatch->chipClock;
isSecond[i]=true;
CHIP_VOL(16,1.6);
willExport[i]=true;
writeRF5C68[1]=disCont[i].dispatch;
}
} else if (!hasRFC) {
hasRFC=disCont[i].dispatch->chipClock;
CHIP_VOL(5,1.6);
willExport[i]=true;
writeRF5C68[0]=disCont[i].dispatch;
}
@ -1423,10 +1507,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_MSM6295:
if (!hasOKIM6295) {
hasOKIM6295=disCont[i].dispatch->chipClock;
CHIP_VOL(24,1.0);
willExport[i]=true;
writeMSM6295[0]=disCont[i].dispatch;
} else if (!(hasOKIM6295&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(24,1.0);
willExport[i]=true;
writeMSM6295[1]=disCont[i].dispatch;
hasOKIM6295|=0x40000000;
@ -1436,10 +1522,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_GA20:
if (!hasGA20) {
hasGA20=disCont[i].dispatch->chipClock;
CHIP_VOL(40,0.4);
willExport[i]=true;
writeGA20[0]=disCont[i].dispatch;
} else if (!(hasGA20&0x40000000)) {
isSecond[i]=true;
CHIP_VOL_SECOND(40,0.4);
willExport[i]=true;
writeGA20[1]=disCont[i].dispatch;
hasGA20|=0x40000000;
@ -1449,7 +1537,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
case DIV_SYSTEM_T6W28:
if (!hasSN) {
hasSN=0xc0000000|disCont[i].dispatch->chipClock;
CHIP_VOL(0,1.0);
CHIP_VOL(0,2.0);
snNoiseConfig=3;
snNoiseSize=15;
willExport[i]=true;
@ -1524,8 +1612,9 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
w->writeC(0); // OPN
w->writeC(0); // OPNA
}
if (version>=0x160) {
int calcVolume=32.0*(log(song.masterVol)/log(2.0));
if (version>=0x160) { // global volume
double abnormalVol=song.masterVol*(double)chipVolSum/(256.0*MAX(1,chipAccounting));
int calcVolume=32.0*(log(abnormalVol)/log(2.0));
if (calcVolume<-63) calcVolume=-63;
if (calcVolume>192) calcVolume=192;
w->writeC(calcVolume&0xff); // volume
@ -1991,7 +2080,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
for (int i=0; i<song.systemLen; i++) {
std::vector<DivRegWrite>& writes=disCont[i].dispatch->getRegisterWrites();
for (DivRegWrite& j: writes) {
performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i],directStream);
performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i],pendingFreq,playingSample,directStream);
writeCount++;
}
writes.clear();
@ -2031,7 +2120,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
lastOne=i.second.time;
}
// write write
performVGMWrite(w,song.system[i.first],i.second.write,streamIDs[i.first],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i.first],directStream);
performVGMWrite(w,song.system[i.first],i.second.write,streamIDs[i.first],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i.first],pendingFreq,playingSample,directStream);
writeCount++;
}
sortedWrites.clear();
@ -2164,7 +2253,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
w->writeI(0);
} else {
w->writeI(loopPos-0x1c);
w->writeI(tickCount-loopTick-1);
w->writeI(tickCount-loopTick);
}
} else {
w->writeI(0);

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));
}

View file

@ -24,7 +24,8 @@
#ifdef _WIN32
#include <windows.h>
typedef HRESULT (*GDFM)(HMONITOR,int,UINT*,UINT*);
#include "shellScalingStub.h"
typedef HRESULT (WINAPI *GDFM)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*);
#endif
#ifdef __APPLE__
@ -71,9 +72,9 @@ double getScaleFactor(const char* driverHint) {
return 1.0;
}
unsigned int dpiX=96;
unsigned int dpiY=96;
HRESULT result=ta_GetDpiForMonitor(disp,0,&dpiX,&dpiY);
UINT dpiX=96;
UINT dpiY=96;
HRESULT result=ta_GetDpiForMonitor(disp,MDT_EFFECTIVE_DPI,&dpiX,&dpiY);
if (result!=S_OK) {
logW("GetDpiForMonitor failure (%.8x) - no scaling detection available!",result);

View file

@ -0,0 +1,36 @@
/*
* Copyright 2016 Sebastian Lackner
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __WINE_SHELLSCALINGAPI_H
typedef enum MONITOR_DPI_TYPE
{
MDT_EFFECTIVE_DPI = 0,
MDT_ANGULAR_DPI = 1,
MDT_RAW_DPI = 2,
MDT_DEFAULT = MDT_EFFECTIVE_DPI,
} MONITOR_DPI_TYPE;
typedef enum PROCESS_DPI_AWARENESS
{
PROCESS_DPI_UNAWARE,
PROCESS_SYSTEM_DPI_AWARE,
PROCESS_PER_MONITOR_DPI_AWARE
} PROCESS_DPI_AWARENESS;
#endif /* __WINE_SHELLSCALINGAPI_H */

View file

@ -32,6 +32,10 @@
#include <windows.h>
#include <combaseapi.h>
#include <shellapi.h>
#include "gui/shellScalingStub.h"
typedef HRESULT (WINAPI *SPDA)(PROCESS_DPI_AWARENESS);
#else
#include <unistd.h>
#endif
@ -339,6 +343,22 @@ void reportError(String what) {
int main(int argc, char** argv) {
initLog();
#ifdef _WIN32
// set DPI awareness
HMODULE shcore=LoadLibraryW(L"shcore.dll");
if (shcore!=NULL) {
SPDA ta_SetProcessDpiAwareness=(SPDA)GetProcAddress(shcore,"SetProcessDpiAwareness");
if (ta_SetProcessDpiAwareness!=NULL) {
HRESULT result=ta_SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
if (result!=S_OK) {
// ???
}
}
if (!FreeLibrary(shcore)) {
// ???
}
}
// co initialize ex
HRESULT coResult=CoInitializeEx(NULL,COINIT_MULTITHREADED);
if (coResult!=S_OK) {
logE("CoInitializeEx failed!");