mirror of
https://github.com/tildearrow/furnace.git
synced 2024-12-04 18:27:25 +00:00
Merge branch 'master' of https://github.com/tildearrow/furnace into ymf289b
This commit is contained in:
commit
371c82338f
18 changed files with 270 additions and 93 deletions
8
.github/workflows/build.yml
vendored
8
.github/workflows/build.yml
vendored
|
@ -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
|
||||
|
||||
|
|
BIN
demos/pce/Bad_Dudes_Greased_Lightning.fur
Normal file
BIN
demos/pce/Bad_Dudes_Greased_Lightning.fur
Normal file
Binary file not shown.
BIN
instruments/OPL/2-OP OPL3 Slap Bass.fui
Normal file
BIN
instruments/OPL/2-OP OPL3 Slap Bass.fui
Normal file
Binary file not shown.
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,7 +1005,9 @@ 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];
|
||||
std::vector<unsigned int> chipVol;
|
||||
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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
36
src/gui/shellScalingStub.h
Normal file
36
src/gui/shellScalingStub.h
Normal 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 */
|
20
src/main.cpp
20
src/main.cpp
|
@ -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!");
|
||||
|
|
Loading…
Reference in a new issue