Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt
This commit is contained in:
commit
5a6cde65ed
|
@ -22,39 +22,122 @@
|
||||||
|
|
||||||
#include "brrUtils.h"
|
#include "brrUtils.h"
|
||||||
|
|
||||||
long brrEncode(short* buf, unsigned char* out, long len) {
|
long brrEncode(short* buf, unsigned char* out, long len, long loopStart) {
|
||||||
if (len==0) return 0;
|
if (len==0) return 0;
|
||||||
// TODO
|
|
||||||
return 0;
|
// encoding process:
|
||||||
|
// 1. read next group of 16 samples
|
||||||
|
// 2. is this the first block?
|
||||||
|
// - if yes, don't filter. output and then go to 1
|
||||||
|
// 3. is this the loop block?
|
||||||
|
// - if yes, don't filter. output and then go to 1
|
||||||
|
// 4. try encoding using 4 filters
|
||||||
|
// 5. which one of these yields the least amount of error?
|
||||||
|
// 6. output the one which does
|
||||||
|
// 7. is this the last block?
|
||||||
|
// - if yes, mark end and finish
|
||||||
|
// 8. go to 1
|
||||||
|
long total=0;
|
||||||
|
unsigned char next[9];
|
||||||
|
unsigned char filter=0;
|
||||||
|
unsigned char range=0;
|
||||||
|
unsigned char o=0;
|
||||||
|
short o0=0;
|
||||||
|
|
||||||
|
len&=~15;
|
||||||
|
loopStart&=~15;
|
||||||
|
for (long i=0; i<len; i+=16) {
|
||||||
|
// don't filter on the first or loop block
|
||||||
|
if (i && i!=loopStart) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
filter=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
range=0;
|
||||||
|
for (int j=0; j<16; j++) {
|
||||||
|
short s=buf[j]-(buf[j]>>13);
|
||||||
|
if (s<0) s=-s;
|
||||||
|
while (range<12 && s>((8<<range)-1)) range++;
|
||||||
|
}
|
||||||
|
next[0]=(range<<4)|(filter<<2)|((i+16>=len)?((loopStart>=0)?3:1):0);
|
||||||
|
switch (filter) {
|
||||||
|
case 0:
|
||||||
|
for (int j=0; j<16; j++) {
|
||||||
|
short s=buf[j]-(buf[j]>>13);
|
||||||
|
o0=s>>range;
|
||||||
|
if (o0>7) o0=7;
|
||||||
|
if (o0<-8) o0=-8;
|
||||||
|
if (range>=12) if (o0<-7) o0=-7;
|
||||||
|
o=o0&15;
|
||||||
|
if (j&1) {
|
||||||
|
next[1+(j>>1)]|=o;
|
||||||
|
} else {
|
||||||
|
next[1+(j>>1)]=o<<4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out[0]=next[0];
|
||||||
|
out[1]=next[1];
|
||||||
|
out[2]=next[2];
|
||||||
|
out[3]=next[3];
|
||||||
|
out[4]=next[4];
|
||||||
|
out[5]=next[5];
|
||||||
|
out[6]=next[6];
|
||||||
|
out[7]=next[7];
|
||||||
|
out[8]=next[8];
|
||||||
|
buf+=16;
|
||||||
|
out+=9;
|
||||||
|
total+=9;
|
||||||
|
}
|
||||||
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DO_ONE_SAMPLE \
|
#define DO_ONE_SAMPLE \
|
||||||
if (next&8) next|=0xfffffff8; \
|
if (next&8) next|=0xfffffff0; \
|
||||||
\
|
\
|
||||||
|
if (buf[0]>=0xd0) { /* invalid shift */ \
|
||||||
|
next=(next<0)?0xfffff800:0; \
|
||||||
|
} else { \
|
||||||
next<<=(buf[0]>>4); /* range */ \
|
next<<=(buf[0]>>4); /* range */ \
|
||||||
|
next>>=1; \
|
||||||
|
} \
|
||||||
\
|
\
|
||||||
switch (control&0xc) { /* filter */ \
|
switch (control&0xc) { /* filter */ \
|
||||||
case 0: \
|
case 0: \
|
||||||
break; \
|
break; \
|
||||||
case 4: \
|
case 4: \
|
||||||
next+=(last1*15)/16; \
|
next+=last1+((-last1)>>4); \
|
||||||
break; \
|
break; \
|
||||||
case 8: \
|
case 8: \
|
||||||
next+=((last1*61)/32)-((last2*15)/16); \
|
next+=last1*2+((-last1*3)>>5)-last2+(last2>>4); \
|
||||||
break; \
|
break; \
|
||||||
case 12: \
|
case 12: \
|
||||||
next+=((last1*115)/64)-((last2*13)/16); \
|
next+=last1*2+((-last1*13)>>6)-last2+((last2*3)>>4); \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
if (next>32767) next=32767; \
|
if (next>32767) next=32767; \
|
||||||
if (next<-32768) next=-32768; \
|
if (next<-32768) next=-32768; \
|
||||||
|
next&=0x7fff; \
|
||||||
|
if (next&0x4000) next|=0xffff8000; \
|
||||||
\
|
\
|
||||||
last2=last1; \
|
last2=last1; \
|
||||||
last1=next; \
|
last1=next; \
|
||||||
*out=next; \
|
*out=next<<1; \
|
||||||
out++;
|
out++;
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// - what happens during overflow?
|
||||||
|
// - what happens when range values 12 to 15 are used?
|
||||||
long brrDecode(unsigned char* buf, short* out, long len) {
|
long brrDecode(unsigned char* buf, short* out, long len) {
|
||||||
if (len==0) return 0;
|
if (len==0) return 0;
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,10 @@ extern "C" {
|
||||||
* @param buf input data.
|
* @param buf input data.
|
||||||
* @param out output buffer. shall be at least 9*(len/16) shorts in size.
|
* @param out output buffer. shall be at least 9*(len/16) shorts in size.
|
||||||
* @param len input length (should be a multiple of 16. if it isn't, the output will be padded).
|
* @param len input length (should be a multiple of 16. if it isn't, the output will be padded).
|
||||||
|
* @param loopStart beginning of loop area (may be -1 for no loop). this is used to ensure the respective block has no filter in order to loop properly.
|
||||||
* @return number of written samples.
|
* @return number of written samples.
|
||||||
*/
|
*/
|
||||||
long brrEncode(short* buf, unsigned char* out, long len);
|
long brrEncode(short* buf, unsigned char* out, long len, long loopStart);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* read len bytes from buf, decode BRR and output to out.
|
* read len bytes from buf, decode BRR and output to out.
|
||||||
|
|
|
@ -206,6 +206,18 @@ enum DivDispatchCmds {
|
||||||
|
|
||||||
DIV_CMD_ADPCMA_GLOBAL_VOLUME,
|
DIV_CMD_ADPCMA_GLOBAL_VOLUME,
|
||||||
|
|
||||||
|
DIV_CMD_SNES_ECHO,
|
||||||
|
DIV_CMD_SNES_PITCH_MOD,
|
||||||
|
DIV_CMD_SNES_INVERT,
|
||||||
|
DIV_CMD_SNES_GAIN_MODE,
|
||||||
|
DIV_CMD_SNES_GAIN,
|
||||||
|
DIV_CMD_SNES_ECHO_ENABLE,
|
||||||
|
DIV_CMD_SNES_ECHO_DELAY,
|
||||||
|
DIV_CMD_SNES_ECHO_VOL_LEFT,
|
||||||
|
DIV_CMD_SNES_ECHO_VOL_RIGHT,
|
||||||
|
DIV_CMD_SNES_ECHO_FEEDBACK,
|
||||||
|
DIV_CMD_SNES_ECHO_FIR,
|
||||||
|
|
||||||
DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol
|
DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol
|
||||||
|
|
||||||
DIV_CMD_MAX
|
DIV_CMD_MAX
|
||||||
|
|
|
@ -2651,7 +2651,7 @@ DivSample* DivEngine::sampleFromFile(const char* path) {
|
||||||
}
|
}
|
||||||
extS+=i;
|
extS+=i;
|
||||||
}
|
}
|
||||||
if (extS==".dmc") { // read as .dmc
|
if (extS==".dmc" || extS==".brr") { // read as .dmc or .brr
|
||||||
size_t len=0;
|
size_t len=0;
|
||||||
DivSample* sample=new DivSample;
|
DivSample* sample=new DivSample;
|
||||||
sample->name=stripPath;
|
sample->name=stripPath;
|
||||||
|
@ -2698,12 +2698,48 @@ DivSample* DivEngine::sampleFromFile(const char* path) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (extS==".dmc") {
|
||||||
sample->rate=33144;
|
sample->rate=33144;
|
||||||
sample->centerRate=33144;
|
sample->centerRate=33144;
|
||||||
sample->depth=DIV_SAMPLE_DEPTH_1BIT_DPCM;
|
sample->depth=DIV_SAMPLE_DEPTH_1BIT_DPCM;
|
||||||
sample->init(len*8);
|
sample->init(len*8);
|
||||||
|
} else if (extS==".brr") {
|
||||||
|
sample->rate=32000;
|
||||||
|
sample->centerRate=32000;
|
||||||
|
sample->depth=DIV_SAMPLE_DEPTH_BRR;
|
||||||
|
sample->init(16*(len/9));
|
||||||
|
} else {
|
||||||
|
fclose(f);
|
||||||
|
BUSY_END;
|
||||||
|
lastError="wait... is that right? no I don't think so...";
|
||||||
|
delete sample;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (fread(sample->dataDPCM,1,len,f)==0) {
|
unsigned char* dataBuf=sample->dataDPCM;
|
||||||
|
if (extS==".brr") {
|
||||||
|
dataBuf=sample->dataBRR;
|
||||||
|
if ((len%9)==2) {
|
||||||
|
// ignore loop position
|
||||||
|
fseek(f,2,SEEK_SET);
|
||||||
|
len-=2;
|
||||||
|
if (len==0) {
|
||||||
|
fclose(f);
|
||||||
|
BUSY_END;
|
||||||
|
lastError="BRR sample is empty!";
|
||||||
|
delete sample;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else if ((len%9)!=0) {
|
||||||
|
fclose(f);
|
||||||
|
BUSY_END;
|
||||||
|
lastError="possibly corrupt BRR sample!";
|
||||||
|
delete sample;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fread(dataBuf,1,len,f)==0) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
BUSY_END;
|
BUSY_END;
|
||||||
lastError=fmt::sprintf("could not read file! (%s)",strerror(errno));
|
lastError=fmt::sprintf("could not read file! (%s)",strerror(errno));
|
||||||
|
|
|
@ -115,7 +115,7 @@ const unsigned char dacLogTableAY[256]={
|
||||||
|
|
||||||
void DivPlatformAY8910::runDAC() {
|
void DivPlatformAY8910::runDAC() {
|
||||||
for (int i=0; i<3; i++) {
|
for (int i=0; i<3; i++) {
|
||||||
if (chan[i].psgMode.dac && chan[i].dac.sample!=-1) {
|
if (chan[i].active && chan[i].psgMode.dac && chan[i].dac.sample!=-1) {
|
||||||
chan[i].dac.period+=chan[i].dac.rate;
|
chan[i].dac.period+=chan[i].dac.rate;
|
||||||
bool end=false;
|
bool end=false;
|
||||||
bool changed=false;
|
bool changed=false;
|
||||||
|
@ -129,7 +129,7 @@ void DivPlatformAY8910::runDAC() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
unsigned char dacData=dacLogTableAY[(unsigned char)s->data8[chan[i].dac.pos]^0x80];
|
unsigned char dacData=dacLogTableAY[(unsigned char)s->data8[chan[i].dac.pos]^0x80];
|
||||||
chan[i].dac.out=MAX(0,dacData-(15-chan[i].outVol));
|
chan[i].dac.out=(chan[i].active && !isMuted[i])?MAX(0,dacData-(15-chan[i].outVol)):0;
|
||||||
if (prevOut!=chan[i].dac.out) {
|
if (prevOut!=chan[i].dac.out) {
|
||||||
prevOut=chan[i].dac.out;
|
prevOut=chan[i].dac.out;
|
||||||
changed=true;
|
changed=true;
|
||||||
|
@ -264,7 +264,7 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
if (chan[i].std.wave.had) {
|
if (chan[i].std.wave.had) {
|
||||||
if (!chan[i].psgMode.dac) {
|
if (!chan[i].psgMode.dac) {
|
||||||
chan[i].psgMode=(chan[i].std.wave.val+1)&7;
|
chan[i].psgMode.val=(chan[i].std.wave.val+1)&7;
|
||||||
if (isMuted[i]) {
|
if (isMuted[i]) {
|
||||||
rWrite(0x08+i,0);
|
rWrite(0x08+i,0);
|
||||||
} else if (intellivision && (chan[i].psgMode.getEnvelope())) {
|
} else if (intellivision && (chan[i].psgMode.getEnvelope())) {
|
||||||
|
@ -336,8 +336,12 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
||||||
if (chan[i].keyOn) {
|
if (chan[i].keyOn) {
|
||||||
//rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63)));
|
//rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63)));
|
||||||
//rWrite(16+i*5+2,((chan[i].vol<<4))|(ins->gb.envLen&7)|((ins->gb.envDir&1)<<3));
|
//rWrite(16+i*5+2,((chan[i].vol<<4))|(ins->gb.envLen&7)|((ins->gb.envDir&1)<<3));
|
||||||
|
if (chan[i].psgMode.val==0) {
|
||||||
|
chan[i].psgMode.val=1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (chan[i].keyOff) {
|
if (chan[i].keyOff) {
|
||||||
|
chan[i].psgMode.val=0;
|
||||||
rWrite(0x08+i,0);
|
rWrite(0x08+i,0);
|
||||||
}
|
}
|
||||||
rWrite((i)<<1,chan[i].freq&0xff);
|
rWrite((i)<<1,chan[i].freq&0xff);
|
||||||
|
@ -543,7 +547,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_STD_NOISE_MODE:
|
case DIV_CMD_STD_NOISE_MODE:
|
||||||
if (!chan[c.chan].psgMode.dac) {
|
if (!chan[c.chan].psgMode.dac) {
|
||||||
if (c.value<16) {
|
if (c.value<16) {
|
||||||
chan[c.chan].psgMode=(c.value+1)&7;
|
chan[c.chan].psgMode.val=(c.value+1)&7;
|
||||||
if (isMuted[c.chan]) {
|
if (isMuted[c.chan]) {
|
||||||
rWrite(0x08+c.chan,0);
|
rWrite(0x08+c.chan,0);
|
||||||
} else if (chan[c.chan].active) {
|
} else if (chan[c.chan].active) {
|
||||||
|
|
|
@ -32,10 +32,15 @@ class DivPlatformAY8910: public DivDispatch {
|
||||||
inline unsigned char regRemap(unsigned char reg) { return intellivision?AY8914RegRemap[reg&0x0f]:reg&0x0f; }
|
inline unsigned char regRemap(unsigned char reg) { return intellivision?AY8914RegRemap[reg&0x0f]:reg&0x0f; }
|
||||||
struct Channel {
|
struct Channel {
|
||||||
struct PSGMode {
|
struct PSGMode {
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
unsigned char tone: 1;
|
unsigned char tone: 1;
|
||||||
unsigned char noise: 1;
|
unsigned char noise: 1;
|
||||||
unsigned char envelope: 1;
|
unsigned char envelope: 1;
|
||||||
unsigned char dac: 1;
|
unsigned char dac: 1;
|
||||||
|
};
|
||||||
|
unsigned char val=1;
|
||||||
|
};
|
||||||
|
|
||||||
unsigned char getTone() {
|
unsigned char getTone() {
|
||||||
return dac?0:(tone<<0);
|
return dac?0:(tone<<0);
|
||||||
|
@ -49,19 +54,8 @@ class DivPlatformAY8910: public DivDispatch {
|
||||||
return dac?0:(envelope<<2);
|
return dac?0:(envelope<<2);
|
||||||
}
|
}
|
||||||
|
|
||||||
PSGMode& operator=(unsigned char s) {
|
|
||||||
tone=(s>>0)&1;
|
|
||||||
noise=(s>>1)&1;
|
|
||||||
envelope=(s>>2)&1;
|
|
||||||
dac=(s>>3)&1;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
PSGMode():
|
PSGMode():
|
||||||
tone(1),
|
val(1) {}
|
||||||
noise(0),
|
|
||||||
envelope(0),
|
|
||||||
dac(0) {}
|
|
||||||
} psgMode;
|
} psgMode;
|
||||||
|
|
||||||
struct DAC {
|
struct DAC {
|
||||||
|
|
|
@ -111,7 +111,7 @@ const unsigned char dacLogTableAY8930[256]={
|
||||||
|
|
||||||
void DivPlatformAY8930::runDAC() {
|
void DivPlatformAY8930::runDAC() {
|
||||||
for (int i=0; i<3; i++) {
|
for (int i=0; i<3; i++) {
|
||||||
if (chan[i].psgMode.dac && chan[i].dac.sample!=-1) {
|
if (chan[i].active && chan[i].psgMode.dac && chan[i].dac.sample!=-1) {
|
||||||
chan[i].dac.period+=chan[i].dac.rate;
|
chan[i].dac.period+=chan[i].dac.rate;
|
||||||
bool end=false;
|
bool end=false;
|
||||||
bool changed=false;
|
bool changed=false;
|
||||||
|
@ -125,7 +125,7 @@ void DivPlatformAY8930::runDAC() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
unsigned char dacData=dacLogTableAY8930[(unsigned char)s->data8[chan[i].dac.pos]^0x80];
|
unsigned char dacData=dacLogTableAY8930[(unsigned char)s->data8[chan[i].dac.pos]^0x80];
|
||||||
chan[i].dac.out=MAX(0,dacData-(31-chan[i].outVol));
|
chan[i].dac.out=(chan[i].active && !isMuted[i])?MAX(0,dacData-(31-chan[i].outVol)):0;
|
||||||
if (prevOut!=chan[i].dac.out) {
|
if (prevOut!=chan[i].dac.out) {
|
||||||
prevOut=chan[i].dac.out;
|
prevOut=chan[i].dac.out;
|
||||||
changed=true;
|
changed=true;
|
||||||
|
@ -254,7 +254,7 @@ void DivPlatformAY8930::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
if (chan[i].std.wave.had) {
|
if (chan[i].std.wave.had) {
|
||||||
if (!chan[i].psgMode.dac) {
|
if (!chan[i].psgMode.dac) {
|
||||||
chan[i].psgMode=(chan[i].std.wave.val+1)&7;
|
chan[i].psgMode.val=(chan[i].std.wave.val+1)&7;
|
||||||
if (isMuted[i]) {
|
if (isMuted[i]) {
|
||||||
rWrite(0x08+i,0);
|
rWrite(0x08+i,0);
|
||||||
} else {
|
} else {
|
||||||
|
@ -333,12 +333,16 @@ void DivPlatformAY8930::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
if (chan[i].freq>65535) chan[i].freq=65535;
|
if (chan[i].freq>65535) chan[i].freq=65535;
|
||||||
if (chan[i].keyOn) {
|
if (chan[i].keyOn) {
|
||||||
|
if (chan[i].psgMode.val==0) {
|
||||||
|
chan[i].psgMode.val=1;
|
||||||
|
}
|
||||||
if (chan[i].insChanged) {
|
if (chan[i].insChanged) {
|
||||||
if (!chan[i].std.ex1.will) immWrite(0x16+i,chan[i].duty);
|
if (!chan[i].std.ex1.will) immWrite(0x16+i,chan[i].duty);
|
||||||
chan[i].insChanged=false;
|
chan[i].insChanged=false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (chan[i].keyOff) {
|
if (chan[i].keyOff) {
|
||||||
|
chan[i].psgMode.val=0;
|
||||||
rWrite(0x08+i,0);
|
rWrite(0x08+i,0);
|
||||||
}
|
}
|
||||||
rWrite((i)<<1,chan[i].freq&0xff);
|
rWrite((i)<<1,chan[i].freq&0xff);
|
||||||
|
@ -537,7 +541,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_STD_NOISE_MODE:
|
case DIV_CMD_STD_NOISE_MODE:
|
||||||
if (c.value<0x10) {
|
if (c.value<0x10) {
|
||||||
if (!chan[c.chan].psgMode.dac) {
|
if (!chan[c.chan].psgMode.dac) {
|
||||||
chan[c.chan].psgMode=(c.value+1)&7;
|
chan[c.chan].psgMode.val=(c.value+1)&7;
|
||||||
if (isMuted[c.chan]) {
|
if (isMuted[c.chan]) {
|
||||||
rWrite(0x08+c.chan,0);
|
rWrite(0x08+c.chan,0);
|
||||||
} else if (chan[c.chan].active) {
|
} else if (chan[c.chan].active) {
|
||||||
|
|
|
@ -40,10 +40,15 @@ class DivPlatformAY8930: public DivDispatch {
|
||||||
} envelope;
|
} envelope;
|
||||||
|
|
||||||
struct PSGMode {
|
struct PSGMode {
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
unsigned char tone: 1;
|
unsigned char tone: 1;
|
||||||
unsigned char noise: 1;
|
unsigned char noise: 1;
|
||||||
unsigned char envelope: 1;
|
unsigned char envelope: 1;
|
||||||
unsigned char dac: 1;
|
unsigned char dac: 1;
|
||||||
|
};
|
||||||
|
unsigned char val=1;
|
||||||
|
};
|
||||||
|
|
||||||
unsigned char getTone() {
|
unsigned char getTone() {
|
||||||
return dac?0:(tone<<0);
|
return dac?0:(tone<<0);
|
||||||
|
@ -57,19 +62,8 @@ class DivPlatformAY8930: public DivDispatch {
|
||||||
return dac?0:(envelope<<2);
|
return dac?0:(envelope<<2);
|
||||||
}
|
}
|
||||||
|
|
||||||
PSGMode& operator=(unsigned char s) {
|
|
||||||
tone=(s>>0)&1;
|
|
||||||
noise=(s>>1)&1;
|
|
||||||
envelope=(s>>2)&1;
|
|
||||||
dac=(s>>3)&1;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
PSGMode():
|
PSGMode():
|
||||||
tone(1),
|
val(1) {}
|
||||||
noise(0),
|
|
||||||
envelope(0),
|
|
||||||
dac(0) {}
|
|
||||||
} psgMode;
|
} psgMode;
|
||||||
|
|
||||||
struct DAC {
|
struct DAC {
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
#define CHIP_FREQBASE 131072
|
#define CHIP_FREQBASE 131072
|
||||||
|
|
||||||
#define rWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
|
#define rWrite(a,v) if (!skipRegisterWrites) {writes.push(QueuedWrite(a,v)); if (dumpWrites) {addWrite(a,v);} }
|
||||||
#define chWrite(c,a,v) {rWrite((a)+(c)*16,v)}
|
#define chWrite(c,a,v) {rWrite((a)+(c)*16,v)}
|
||||||
#define sampleTableAddr(c) (sampleTableBase+(c)*4)
|
#define sampleTableAddr(c) (sampleTableBase+(c)*4)
|
||||||
#define waveTableAddr(c) (sampleTableBase+8*4+(c)*9*16)
|
#define waveTableAddr(c) (sampleTableBase+8*4+(c)*9*16)
|
||||||
|
@ -94,19 +94,9 @@ void DivPlatformSNES::tick(bool sysTick) {
|
||||||
unsigned char kon=0;
|
unsigned char kon=0;
|
||||||
unsigned char koff=0;
|
unsigned char koff=0;
|
||||||
for (int i=0; i<8; i++) {
|
for (int i=0; i<8; i++) {
|
||||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA);
|
|
||||||
bool hadGain=chan[i].std.vol.had || chan[i].std.ex1.had || chan[i].std.ex2.had;
|
|
||||||
chan[i].std.next();
|
chan[i].std.next();
|
||||||
if (ins->type==DIV_INS_AMIGA && chan[i].std.vol.had) {
|
if (chan[i].std.vol.had) {
|
||||||
chWrite(i,7,MIN(127,chan[i].std.vol.val*2));
|
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol&127,MIN(127,chan[i].std.vol.val),127);
|
||||||
} else if (!chan[i].useEnv && hadGain) {
|
|
||||||
if (chan[i].std.ex1.val==0) {
|
|
||||||
// direct gain
|
|
||||||
chWrite(i,7,chan[i].std.vol.val);
|
|
||||||
} else {
|
|
||||||
// inc/dec
|
|
||||||
chWrite(i,7,chan[i].std.ex2.val|((chan[i].std.ex1.val-1)<<5)|0x80);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (chan[i].std.arp.had) {
|
if (chan[i].std.arp.had) {
|
||||||
if (!chan[i].inPorta) {
|
if (!chan[i].inPorta) {
|
||||||
|
@ -123,6 +113,10 @@ void DivPlatformSNES::tick(bool sysTick) {
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.duty.had) {
|
||||||
|
noiseFreq=chan[i].std.duty.val;
|
||||||
|
writeControl=true;
|
||||||
|
}
|
||||||
if (chan[i].useWave && chan[i].std.wave.had) {
|
if (chan[i].useWave && chan[i].std.wave.had) {
|
||||||
if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) {
|
if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) {
|
||||||
chan[i].wave=chan[i].std.wave.val;
|
chan[i].wave=chan[i].std.wave.val;
|
||||||
|
@ -146,7 +140,30 @@ void DivPlatformSNES::tick(bool sysTick) {
|
||||||
int val=chan[i].std.panR.val&0x7f;
|
int val=chan[i].std.panR.val&0x7f;
|
||||||
chan[i].panR=(val<<1)|(val>>6);
|
chan[i].panR=(val<<1)|(val>>6);
|
||||||
}
|
}
|
||||||
if (chan[i].std.panL.had || chan[i].std.panR.had) {
|
bool hasInverted=false;
|
||||||
|
if (chan[i].std.ex1.had) {
|
||||||
|
if (chan[i].invertL!=(bool)(chan[i].std.ex1.val&16)) {
|
||||||
|
chan[i].invertL=chan[i].std.ex1.val&16;
|
||||||
|
hasInverted=true;
|
||||||
|
}
|
||||||
|
if (chan[i].invertR!=(bool)(chan[i].std.ex1.val&8)) {
|
||||||
|
chan[i].invertR=chan[i].std.ex1.val&8;
|
||||||
|
hasInverted=true;
|
||||||
|
}
|
||||||
|
if (chan[i].pitchMod!=(bool)(chan[i].std.ex1.val&4)) {
|
||||||
|
chan[i].pitchMod=chan[i].std.ex1.val&4;
|
||||||
|
writePitchMod=true;
|
||||||
|
}
|
||||||
|
if (chan[i].echo!=(bool)(chan[i].std.ex1.val&2)) {
|
||||||
|
chan[i].echo=chan[i].std.ex1.val&2;
|
||||||
|
writeEcho=true;
|
||||||
|
}
|
||||||
|
if (chan[i].noise!=(bool)(chan[i].std.ex1.val&1)) {
|
||||||
|
chan[i].noise=chan[i].std.ex1.val&1;
|
||||||
|
writeNoise=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan[i].std.vol.had || chan[i].std.panL.had || chan[i].std.panR.had || hasInverted) {
|
||||||
writeOutVol(i);
|
writeOutVol(i);
|
||||||
}
|
}
|
||||||
if (chan[i].setPos) {
|
if (chan[i].setPos) {
|
||||||
|
@ -164,17 +181,12 @@ void DivPlatformSNES::tick(bool sysTick) {
|
||||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||||
DivSample* s=parent->getSample(chan[i].sample);
|
DivSample* s=parent->getSample(chan[i].sample);
|
||||||
double off=(s->centerRate>=1)?((double)s->centerRate/8363.0):1.0;
|
double off=(s->centerRate>=1)?((double)s->centerRate/8363.0):1.0;
|
||||||
|
if (chan[i].useWave) off=(double)chan[i].wtLen/32.0;
|
||||||
chan[i].freq=(unsigned int)(off*parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE));
|
chan[i].freq=(unsigned int)(off*parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE));
|
||||||
if (chan[i].freq>16383) chan[i].freq=16383;
|
if (chan[i].freq>16383) chan[i].freq=16383;
|
||||||
if (chan[i].keyOn) {
|
if (chan[i].keyOn) {
|
||||||
unsigned int start, end, loop;
|
unsigned int start, end, loop;
|
||||||
size_t tabAddr=sampleTableAddr(i);
|
unsigned short tabAddr=sampleTableAddr(i);
|
||||||
if (chan[i].useEnv) {
|
|
||||||
chWrite(i,5,ins->snes.a|(ins->snes.d<<4)|0x80);
|
|
||||||
chWrite(i,6,ins->snes.r|(ins->snes.s<<5));
|
|
||||||
} else {
|
|
||||||
chWrite(i,5,0);
|
|
||||||
}
|
|
||||||
if (chan[i].useWave) {
|
if (chan[i].useWave) {
|
||||||
start=waveTableAddr(i);
|
start=waveTableAddr(i);
|
||||||
loop=start;
|
loop=start;
|
||||||
|
@ -193,9 +205,6 @@ void DivPlatformSNES::tick(bool sysTick) {
|
||||||
sampleMem[tabAddr+1]=start>>8;
|
sampleMem[tabAddr+1]=start>>8;
|
||||||
sampleMem[tabAddr+2]=loop&0xff;
|
sampleMem[tabAddr+2]=loop&0xff;
|
||||||
sampleMem[tabAddr+3]=loop>>8;
|
sampleMem[tabAddr+3]=loop>>8;
|
||||||
if (!hadGain) {
|
|
||||||
chWrite(i,7,0x7f);
|
|
||||||
}
|
|
||||||
kon|=(1<<i);
|
kon|=(1<<i);
|
||||||
chan[i].keyOn=false;
|
chan[i].keyOn=false;
|
||||||
}
|
}
|
||||||
|
@ -210,6 +219,53 @@ void DivPlatformSNES::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (writeControl) {
|
||||||
|
unsigned char control=noiseFreq&0x1f;
|
||||||
|
rWrite(0x6c,control);
|
||||||
|
writeControl=false;
|
||||||
|
}
|
||||||
|
if (writeNoise) {
|
||||||
|
unsigned char noiseBits=(
|
||||||
|
(chan[0].noise?1:0)|
|
||||||
|
(chan[1].noise?2:0)|
|
||||||
|
(chan[2].noise?4:0)|
|
||||||
|
(chan[3].noise?8:0)|
|
||||||
|
(chan[4].noise?0x10:0)|
|
||||||
|
(chan[5].noise?0x20:0)|
|
||||||
|
(chan[6].noise?0x40:0)|
|
||||||
|
(chan[7].noise?0x80:0)
|
||||||
|
);
|
||||||
|
rWrite(0x3d,noiseBits);
|
||||||
|
writeNoise=false;
|
||||||
|
}
|
||||||
|
if (writePitchMod) {
|
||||||
|
unsigned char pitchModBits=(
|
||||||
|
(chan[0].pitchMod?1:0)|
|
||||||
|
(chan[1].pitchMod?2:0)|
|
||||||
|
(chan[2].pitchMod?4:0)|
|
||||||
|
(chan[3].pitchMod?8:0)|
|
||||||
|
(chan[4].pitchMod?0x10:0)|
|
||||||
|
(chan[5].pitchMod?0x20:0)|
|
||||||
|
(chan[6].pitchMod?0x40:0)|
|
||||||
|
(chan[7].pitchMod?0x80:0)
|
||||||
|
);
|
||||||
|
rWrite(0x2d,pitchModBits);
|
||||||
|
writePitchMod=false;
|
||||||
|
}
|
||||||
|
if (writeEcho) {
|
||||||
|
unsigned char echoBits=(
|
||||||
|
(chan[0].echo?1:0)|
|
||||||
|
(chan[1].echo?2:0)|
|
||||||
|
(chan[2].echo?4:0)|
|
||||||
|
(chan[3].echo?8:0)|
|
||||||
|
(chan[4].echo?0x10:0)|
|
||||||
|
(chan[5].echo?0x20:0)|
|
||||||
|
(chan[6].echo?0x40:0)|
|
||||||
|
(chan[7].echo?0x80:0)
|
||||||
|
);
|
||||||
|
rWrite(0x4d,echoBits);
|
||||||
|
writeEcho=false;
|
||||||
|
}
|
||||||
if (kon!=0) {
|
if (kon!=0) {
|
||||||
rWrite(0x4c,kon);
|
rWrite(0x4c,kon);
|
||||||
}
|
}
|
||||||
|
@ -220,7 +276,7 @@ void DivPlatformSNES::tick(bool sysTick) {
|
||||||
int DivPlatformSNES::dispatch(DivCommand c) {
|
int DivPlatformSNES::dispatch(DivCommand c) {
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SNES);
|
||||||
if (ins->amiga.useWave) {
|
if (ins->amiga.useWave) {
|
||||||
chan[c.chan].useWave=true;
|
chan[c.chan].useWave=true;
|
||||||
chan[c.chan].wtLen=ins->amiga.waveLen+1;
|
chan[c.chan].wtLen=ins->amiga.waveLen+1;
|
||||||
|
@ -239,6 +295,32 @@ int DivPlatformSNES::dispatch(DivCommand c) {
|
||||||
if (chan[c.chan].useWave || chan[c.chan].sample<0 || chan[c.chan].sample>=parent->song.sampleLen) {
|
if (chan[c.chan].useWave || chan[c.chan].sample<0 || chan[c.chan].sample>=parent->song.sampleLen) {
|
||||||
chan[c.chan].sample=-1;
|
chan[c.chan].sample=-1;
|
||||||
}
|
}
|
||||||
|
if (chan[c.chan].insChanged) {
|
||||||
|
chan[c.chan].state=ins->snes;
|
||||||
|
}
|
||||||
|
if (chan[c.chan].state.useEnv) {
|
||||||
|
chWrite(c.chan,5,chan[c.chan].state.a|(chan[c.chan].state.d<<4)|0x80);
|
||||||
|
chWrite(c.chan,6,chan[c.chan].state.r|(chan[c.chan].state.s<<5));
|
||||||
|
} else {
|
||||||
|
chWrite(c.chan,5,0);
|
||||||
|
switch (chan[c.chan].state.gainMode) {
|
||||||
|
case DivInstrumentSNES::GAIN_MODE_DIRECT:
|
||||||
|
chWrite(c.chan,7,chan[c.chan].state.gain&127);
|
||||||
|
break;
|
||||||
|
case DivInstrumentSNES::GAIN_MODE_DEC_LINEAR:
|
||||||
|
chWrite(c.chan,7,0x80|(chan[c.chan].state.gain&31));
|
||||||
|
break;
|
||||||
|
case DivInstrumentSNES::GAIN_MODE_INC_LINEAR:
|
||||||
|
chWrite(c.chan,7,0xc0|(chan[c.chan].state.gain&31));
|
||||||
|
break;
|
||||||
|
case DivInstrumentSNES::GAIN_MODE_DEC_LOG:
|
||||||
|
chWrite(c.chan,7,0xa0|(chan[c.chan].state.gain&31));
|
||||||
|
break;
|
||||||
|
case DivInstrumentSNES::GAIN_MODE_INC_INVLOG:
|
||||||
|
chWrite(c.chan,7,0xe0|(chan[c.chan].state.gain&31));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (c.value!=DIV_NOTE_NULL) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].baseFreq=round(NOTE_FREQUENCY(c.value));
|
chan[c.chan].baseFreq=round(NOTE_FREQUENCY(c.value));
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
|
@ -247,11 +329,6 @@ int DivPlatformSNES::dispatch(DivCommand c) {
|
||||||
chan[c.chan].active=true;
|
chan[c.chan].active=true;
|
||||||
chan[c.chan].keyOn=true;
|
chan[c.chan].keyOn=true;
|
||||||
chan[c.chan].macroInit(ins);
|
chan[c.chan].macroInit(ins);
|
||||||
if (ins->type==DIV_INS_SNES) {
|
|
||||||
// initialize to max gain in case of direct gain mode macro without gain level macro
|
|
||||||
chan[c.chan].std.vol.val=0x7f;
|
|
||||||
chan[c.chan].useEnv=ins->snes.useEnv;
|
|
||||||
}
|
|
||||||
chan[c.chan].insChanged=false;
|
chan[c.chan].insChanged=false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -277,12 +354,6 @@ int DivPlatformSNES::dispatch(DivCommand c) {
|
||||||
writeOutVol(c.chan);
|
writeOutVol(c.chan);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// case DIV_CMD_GLOBAL_VOLUME:
|
|
||||||
// gblVolL=MIN(c.value,127);
|
|
||||||
// gblVolR=MIN(c.value,127);
|
|
||||||
// rWrite(0x0c,gblVolL);
|
|
||||||
// rWrite(0x1c,gblVolR);
|
|
||||||
// break;
|
|
||||||
case DIV_CMD_GET_VOLUME:
|
case DIV_CMD_GET_VOLUME:
|
||||||
return chan[c.chan].vol;
|
return chan[c.chan].vol;
|
||||||
break;
|
break;
|
||||||
|
@ -326,7 +397,7 @@ int DivPlatformSNES::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
case DIV_CMD_PRE_PORTA:
|
case DIV_CMD_PRE_PORTA:
|
||||||
if (chan[c.chan].active && c.value2) {
|
if (chan[c.chan].active && c.value2) {
|
||||||
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
|
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SNES));
|
||||||
}
|
}
|
||||||
chan[c.chan].inPorta=c.value;
|
chan[c.chan].inPorta=c.value;
|
||||||
break;
|
break;
|
||||||
|
@ -346,7 +417,7 @@ int DivPlatformSNES::dispatch(DivCommand c) {
|
||||||
|
|
||||||
void DivPlatformSNES::updateWave(int ch) {
|
void DivPlatformSNES::updateWave(int ch) {
|
||||||
// Due to the overflow bug in hardware's resampler, the written amplitude here is half of maximum
|
// Due to the overflow bug in hardware's resampler, the written amplitude here is half of maximum
|
||||||
size_t pos=waveTableAddr(ch);
|
unsigned short pos=waveTableAddr(ch);
|
||||||
for (int i=0; i<chan[ch].wtLen/16; i++) {
|
for (int i=0; i<chan[ch].wtLen/16; i++) {
|
||||||
sampleMem[pos++]=0xb0;
|
sampleMem[pos++]=0xb0;
|
||||||
for (int j=0; j<8; j++) {
|
for (int j=0; j<8; j++) {
|
||||||
|
@ -359,12 +430,13 @@ void DivPlatformSNES::updateWave(int ch) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformSNES::writeOutVol(int ch) {
|
void DivPlatformSNES::writeOutVol(int ch) {
|
||||||
// TODO negative (inverted) panning support
|
|
||||||
int outL=0;
|
int outL=0;
|
||||||
int outR=0;
|
int outR=0;
|
||||||
if (!isMuted[ch]) {
|
if (!isMuted[ch]) {
|
||||||
outL=chan[ch].vol*chan[ch].panL/255;
|
outL=(globalVolL*((chan[ch].outVol*chan[ch].panL)/127))/127;
|
||||||
outR=chan[ch].vol*chan[ch].panR/255;
|
outR=(globalVolR*((chan[ch].outVol*chan[ch].panR)/127))/127;
|
||||||
|
if (chan[ch].invertL) outL=-outL;
|
||||||
|
if (chan[ch].invertR) outR=-outR;
|
||||||
}
|
}
|
||||||
chWrite(ch,0,outL);
|
chWrite(ch,0,outL);
|
||||||
chWrite(ch,1,outR);
|
chWrite(ch,1,outR);
|
||||||
|
@ -380,8 +452,15 @@ void DivPlatformSNES::forceIns() {
|
||||||
chan[i].insChanged=true;
|
chan[i].insChanged=true;
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
chan[i].sample=-1;
|
chan[i].sample=-1;
|
||||||
|
if (chan[i].active && chan[i].useWave) {
|
||||||
updateWave(i);
|
updateWave(i);
|
||||||
}
|
}
|
||||||
|
writeOutVol(i);
|
||||||
|
}
|
||||||
|
writeControl=true;
|
||||||
|
writeNoise=true;
|
||||||
|
writePitchMod=true;
|
||||||
|
writeEcho=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* DivPlatformSNES::getChanState(int ch) {
|
void* DivPlatformSNES::getChanState(int ch) {
|
||||||
|
@ -414,9 +493,9 @@ void DivPlatformSNES::reset() {
|
||||||
dsp.init(sampleMem);
|
dsp.init(sampleMem);
|
||||||
dsp.set_output(NULL,0);
|
dsp.set_output(NULL,0);
|
||||||
memset(regPool,0,128);
|
memset(regPool,0,128);
|
||||||
// TODO more initial values
|
|
||||||
// this can't be 0 or channel 1 won't play
|
// this can't be 0 or channel 1 won't play
|
||||||
// this can't be 0x100 either as that's used by SPC700 page 1 and the stack
|
// this can't be 0x100 either as that's used by SPC700 page 1 and the stack
|
||||||
|
// this may not even be 0x200 as some space will be taken by the playback routine and variables
|
||||||
sampleTableBase=0x200;
|
sampleTableBase=0x200;
|
||||||
rWrite(0x5d,sampleTableBase>>8);
|
rWrite(0x5d,sampleTableBase>>8);
|
||||||
rWrite(0x0c,127); // global volume left
|
rWrite(0x0c,127); // global volume left
|
||||||
|
@ -430,6 +509,10 @@ void DivPlatformSNES::reset() {
|
||||||
writeOutVol(i);
|
writeOutVol(i);
|
||||||
chWrite(i,4,i); // source number
|
chWrite(i,4,i); // source number
|
||||||
}
|
}
|
||||||
|
writeControl=false;
|
||||||
|
writeNoise=false;
|
||||||
|
writePitchMod=false;
|
||||||
|
writeEcho=false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DivPlatformSNES::isStereo() {
|
bool DivPlatformSNES::isStereo() {
|
||||||
|
@ -493,7 +576,7 @@ void DivPlatformSNES::renderSamples() {
|
||||||
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)/9*9,length);
|
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)/9*9,length);
|
||||||
if (actualLength>0) {
|
if (actualLength>0) {
|
||||||
s->offSNES=memPos;
|
s->offSNES=memPos;
|
||||||
memcpy(&sampleMem[memPos],s->data8,actualLength);
|
memcpy(&sampleMem[memPos],s->dataBRR,actualLength);
|
||||||
memPos+=actualLength;
|
memPos+=actualLength;
|
||||||
}
|
}
|
||||||
if (actualLength<length) {
|
if (actualLength<length) {
|
||||||
|
@ -506,6 +589,11 @@ void DivPlatformSNES::renderSamples() {
|
||||||
sampleMemLen=memPos;
|
sampleMemLen=memPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformSNES::setFlags(unsigned int flags) {
|
||||||
|
globalVolL=127-(flags&127);
|
||||||
|
globalVolR=127-((flags>>8)&127);
|
||||||
|
}
|
||||||
|
|
||||||
int DivPlatformSNES::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
int DivPlatformSNES::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||||
parent=p;
|
parent=p;
|
||||||
dumpWrites=false;
|
dumpWrites=false;
|
||||||
|
@ -517,6 +605,7 @@ int DivPlatformSNES::init(DivEngine* p, int channels, int sugRate, unsigned int
|
||||||
sampleMemLen=0;
|
sampleMemLen=0;
|
||||||
chipClock=1024000;
|
chipClock=1024000;
|
||||||
rate=chipClock/32;
|
rate=chipClock/32;
|
||||||
|
setFlags(flags);
|
||||||
reset();
|
reset();
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,10 +33,10 @@ class DivPlatformSNES: public DivDispatch {
|
||||||
int sample, wave, ins;
|
int sample, wave, ins;
|
||||||
int note;
|
int note;
|
||||||
int panL, panR;
|
int panL, panR;
|
||||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, setPos;
|
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, setPos, noise, echo, pitchMod, invertL, invertR;
|
||||||
signed char vol;
|
int vol, outVol;
|
||||||
int wtLen;
|
int wtLen;
|
||||||
bool useEnv;
|
DivInstrumentSNES state;
|
||||||
DivMacroInt std;
|
DivMacroInt std;
|
||||||
DivWaveSynth ws;
|
DivWaveSynth ws;
|
||||||
void macroInit(DivInstrument* which) {
|
void macroInit(DivInstrument* which) {
|
||||||
|
@ -53,8 +53,8 @@ class DivPlatformSNES: public DivDispatch {
|
||||||
wave(-1),
|
wave(-1),
|
||||||
ins(-1),
|
ins(-1),
|
||||||
note(0),
|
note(0),
|
||||||
panL(255),
|
panL(127),
|
||||||
panR(255),
|
panR(127),
|
||||||
active(false),
|
active(false),
|
||||||
insChanged(true),
|
insChanged(true),
|
||||||
freqChanged(false),
|
freqChanged(false),
|
||||||
|
@ -63,15 +63,25 @@ class DivPlatformSNES: public DivDispatch {
|
||||||
inPorta(false),
|
inPorta(false),
|
||||||
useWave(false),
|
useWave(false),
|
||||||
setPos(false),
|
setPos(false),
|
||||||
|
noise(false),
|
||||||
|
echo(false),
|
||||||
|
pitchMod(false),
|
||||||
|
invertL(false),
|
||||||
|
invertR(false),
|
||||||
vol(127),
|
vol(127),
|
||||||
wtLen(16),
|
outVol(127),
|
||||||
useEnv(false) {}
|
wtLen(16) {}
|
||||||
};
|
};
|
||||||
Channel chan[8];
|
Channel chan[8];
|
||||||
DivDispatchOscBuffer* oscBuf[8];
|
DivDispatchOscBuffer* oscBuf[8];
|
||||||
bool isMuted[8];
|
bool isMuted[8];
|
||||||
signed char gblVolL, gblVolR;
|
signed char globalVolL, globalVolR;
|
||||||
|
unsigned char noiseFreq;
|
||||||
size_t sampleTableBase;
|
size_t sampleTableBase;
|
||||||
|
bool writeControl;
|
||||||
|
bool writeNoise;
|
||||||
|
bool writePitchMod;
|
||||||
|
bool writeEcho;
|
||||||
|
|
||||||
struct QueuedWrite {
|
struct QueuedWrite {
|
||||||
unsigned char addr;
|
unsigned char addr;
|
||||||
|
@ -101,6 +111,7 @@ class DivPlatformSNES: public DivDispatch {
|
||||||
bool isStereo();
|
bool isStereo();
|
||||||
void notifyInsChange(int ins);
|
void notifyInsChange(int ins);
|
||||||
void notifyWaveChange(int wave);
|
void notifyWaveChange(int wave);
|
||||||
|
void setFlags(unsigned int flags);
|
||||||
void notifyInsDeletion(void* ins);
|
void notifyInsDeletion(void* ins);
|
||||||
void poke(unsigned int addr, unsigned short val);
|
void poke(unsigned int addr, unsigned short val);
|
||||||
void poke(std::vector<DivRegWrite>& wlist);
|
void poke(std::vector<DivRegWrite>& wlist);
|
||||||
|
|
|
@ -803,7 +803,7 @@ void SPC_DSP::run( int clocks_remain )
|
||||||
{
|
{
|
||||||
loop:
|
loop:
|
||||||
// GCC, why
|
// GCC, why
|
||||||
#ifdef __GNUC__
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
#define PHASE( n ) if ( n && !--clocks_remain ) break; __attribute__ ((fallthrough)); case n:
|
#define PHASE( n ) if ( n && !--clocks_remain ) break; __attribute__ ((fallthrough)); case n:
|
||||||
#else
|
#else
|
||||||
#define PHASE( n ) if ( n && !--clocks_remain ) break; case n:
|
#define PHASE( n ) if ( n && !--clocks_remain ) break; case n:
|
||||||
|
|
|
@ -199,15 +199,25 @@ const char* cmdName[]={
|
||||||
"ES5506_ENVELOPE_K2RAMP",
|
"ES5506_ENVELOPE_K2RAMP",
|
||||||
"ES5506_PAUSE",
|
"ES5506_PAUSE",
|
||||||
|
|
||||||
"DIV_CMD_SU_SWEEP_PERIOD_LOW",
|
"SU_SWEEP_PERIOD_LOW",
|
||||||
"DIV_CMD_SU_SWEEP_PERIOD_HIGH",
|
"SU_SWEEP_PERIOD_HIGH",
|
||||||
"DIV_CMD_SU_SWEEP_BOUND",
|
"SU_SWEEP_BOUND",
|
||||||
"DIV_CMD_SU_SWEEP_ENABLE",
|
"SU_SWEEP_ENABLE",
|
||||||
"DIV_CMD_SU_SYNC_PERIOD_LOW",
|
"SU_SYNC_PERIOD_LOW",
|
||||||
"DIV_CMD_SU_SYNC_PERIOD_HIGH",
|
|
||||||
|
|
||||||
"ADPCMA_GLOBAL_VOLUME",
|
"ADPCMA_GLOBAL_VOLUME",
|
||||||
|
|
||||||
|
"SNES_ECHO",
|
||||||
|
"SNES_PITCH_MOD",
|
||||||
|
"SNES_GAIN_MODE",
|
||||||
|
"SNES_GAIN",
|
||||||
|
"SNES_ECHO_ENABLE",
|
||||||
|
"SNES_ECHO_DELAY",
|
||||||
|
"SNES_ECHO_VOL_LEFT",
|
||||||
|
"SNES_ECHO_VOL_RIGHT",
|
||||||
|
"SNES_ECHO_FEEDBACK",
|
||||||
|
"SNES_ECHO_FIR",
|
||||||
|
|
||||||
"ALWAYS_SET_VOLUME"
|
"ALWAYS_SET_VOLUME"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -243,7 +243,7 @@ bool DivSample::save(const char* path) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
sf_write_raw(f,data16,length16);
|
sf_writef_short(f,data16,samples);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -852,7 +852,7 @@ void DivSample::render() {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DIV_SAMPLE_DEPTH_BRR: // BRR
|
case DIV_SAMPLE_DEPTH_BRR: // BRR
|
||||||
brrDecode(dataBRR,data16,samples);
|
brrDecode(dataBRR,data16,lengthBRR);
|
||||||
break;
|
break;
|
||||||
case DIV_SAMPLE_DEPTH_VOX: // VOX
|
case DIV_SAMPLE_DEPTH_VOX: // VOX
|
||||||
oki_decode(dataVOX,data16,samples);
|
oki_decode(dataVOX,data16,samples);
|
||||||
|
@ -911,7 +911,7 @@ void DivSample::render() {
|
||||||
}
|
}
|
||||||
if (depth!=DIV_SAMPLE_DEPTH_BRR) { // BRR
|
if (depth!=DIV_SAMPLE_DEPTH_BRR) { // BRR
|
||||||
if (!initInternal(DIV_SAMPLE_DEPTH_BRR,samples)) return;
|
if (!initInternal(DIV_SAMPLE_DEPTH_BRR,samples)) return;
|
||||||
brrEncode(data16,dataBRR,samples);
|
brrEncode(data16,dataBRR,(samples+15)&(~15),loop?loopStart:-1);
|
||||||
}
|
}
|
||||||
if (depth!=DIV_SAMPLE_DEPTH_VOX) { // VOX
|
if (depth!=DIV_SAMPLE_DEPTH_VOX) { // VOX
|
||||||
if (!initInternal(DIV_SAMPLE_DEPTH_VOX,samples)) return;
|
if (!initInternal(DIV_SAMPLE_DEPTH_VOX,samples)) return;
|
||||||
|
|
|
@ -618,7 +618,7 @@ struct DivSong {
|
||||||
e1e2StopOnSameNote(false),
|
e1e2StopOnSameNote(false),
|
||||||
brokenPortaArp(false),
|
brokenPortaArp(false),
|
||||||
snNoLowPeriods(false),
|
snNoLowPeriods(false),
|
||||||
disableSampleMacro(true),
|
disableSampleMacro(false),
|
||||||
autoSystem(true) {
|
autoSystem(true) {
|
||||||
for (int i=0; i<32; i++) {
|
for (int i=0; i<32; i++) {
|
||||||
system[i]=DIV_SYSTEM_NULL;
|
system[i]=DIV_SYSTEM_NULL;
|
||||||
|
|
|
@ -871,7 +871,35 @@ void DivEngine::registerSystems() {
|
||||||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"},
|
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"},
|
||||||
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"},
|
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"},
|
||||||
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
||||||
{DIV_INS_SNES, DIV_INS_SNES, DIV_INS_SNES, DIV_INS_SNES, DIV_INS_SNES, DIV_INS_SNES, DIV_INS_SNES, DIV_INS_SNES}
|
{DIV_INS_SNES, DIV_INS_SNES, DIV_INS_SNES, DIV_INS_SNES, DIV_INS_SNES, DIV_INS_SNES, DIV_INS_SNES, DIV_INS_SNES},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
{0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}},
|
||||||
|
{0x11, {DIV_CMD_STD_NOISE_MODE, "11xx: Toggle noise mode"}},
|
||||||
|
{0x12, {DIV_CMD_SNES_ECHO, "12xx: Toggle echo on this channel"}},
|
||||||
|
{0x13, {DIV_CMD_SNES_PITCH_MOD, "13xx: Toggle pitch modulation"}},
|
||||||
|
{0x14, {DIV_CMD_SNES_INVERT, "14xy: Toggle invert (x: left; y: right)"}},
|
||||||
|
{0x15, {DIV_CMD_SNES_GAIN_MODE, "15xx: Set gain mode"}},
|
||||||
|
{0x16, {DIV_CMD_SNES_GAIN, "16xx: Set gain"}},
|
||||||
|
{0x18, {DIV_CMD_SNES_ECHO_ENABLE, "18xx: Enable echo buffer"}},
|
||||||
|
{0x19, {DIV_CMD_SNES_ECHO_DELAY, "19xx: Set echo delay"}},
|
||||||
|
{0x1a, {DIV_CMD_SNES_ECHO_VOL_LEFT, "1Axx: Set left echo volume"}},
|
||||||
|
{0x1b, {DIV_CMD_SNES_ECHO_VOL_RIGHT, "1Bxx: Set right echo volume"}},
|
||||||
|
{0x1c, {DIV_CMD_SNES_ECHO_FEEDBACK, "1Cxx: Set echo feedback"}},
|
||||||
|
{0x1d, {DIV_CMD_STD_NOISE_FREQ, "1Dxx: Set noise frequency"}},
|
||||||
|
{0x20, {DIV_CMD_FM_AR, "20xx: Set attack"}},
|
||||||
|
{0x21, {DIV_CMD_FM_DR, "21xx: Set decay"}},
|
||||||
|
{0x22, {DIV_CMD_FM_SL, "22xx: Set sustain"}},
|
||||||
|
{0x23, {DIV_CMD_FM_RR, "23xx: Set release"}},
|
||||||
|
{0x30, {DIV_CMD_SNES_ECHO_FIR, "30xx: Set echo filter coefficient 0",constVal<0>,effectVal}},
|
||||||
|
{0x31, {DIV_CMD_SNES_ECHO_FIR, "31xx: Set echo filter coefficient 1",constVal<1>,effectVal}},
|
||||||
|
{0x32, {DIV_CMD_SNES_ECHO_FIR, "32xx: Set echo filter coefficient 2",constVal<2>,effectVal}},
|
||||||
|
{0x33, {DIV_CMD_SNES_ECHO_FIR, "33xx: Set echo filter coefficient 3",constVal<3>,effectVal}},
|
||||||
|
{0x34, {DIV_CMD_SNES_ECHO_FIR, "34xx: Set echo filter coefficient 4",constVal<4>,effectVal}},
|
||||||
|
{0x35, {DIV_CMD_SNES_ECHO_FIR, "35xx: Set echo filter coefficient 5",constVal<5>,effectVal}},
|
||||||
|
{0x36, {DIV_CMD_SNES_ECHO_FIR, "36xx: Set echo filter coefficient 6",constVal<6>,effectVal}},
|
||||||
|
{0x37, {DIV_CMD_SNES_ECHO_FIR, "37xx: Set echo filter coefficient 7",constVal<7>,effectVal}},
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
sysDefs[DIV_SYSTEM_VRC6]=new DivSysDef(
|
sysDefs[DIV_SYSTEM_VRC6]=new DivSysDef(
|
||||||
|
|
|
@ -86,7 +86,7 @@ SafeWriter* DivEngine::saveZSM(unsigned int zsmrate, bool loop) {
|
||||||
|
|
||||||
// Prepare to write song data
|
// Prepare to write song data
|
||||||
playSub(false);
|
playSub(false);
|
||||||
size_t tickCount=0;
|
//size_t tickCount=0;
|
||||||
bool done=false;
|
bool done=false;
|
||||||
int loopPos=-1;
|
int loopPos=-1;
|
||||||
int writeCount=0;
|
int writeCount=0;
|
||||||
|
@ -155,7 +155,7 @@ SafeWriter* DivEngine::saveZSM(unsigned int zsmrate, bool loop) {
|
||||||
fracWait &= MASTER_CLOCK_MASK;
|
fracWait &= MASTER_CLOCK_MASK;
|
||||||
if (totalWait>0) {
|
if (totalWait>0) {
|
||||||
zsm.tick(totalWait);
|
zsm.tick(totalWait);
|
||||||
tickCount+=totalWait;
|
//tickCount+=totalWait;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// end of song
|
// end of song
|
||||||
|
|
|
@ -1556,9 +1556,9 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
||||||
if (!dirExists(workingDirSample)) workingDirSample=getHomeDir();
|
if (!dirExists(workingDirSample)) workingDirSample=getHomeDir();
|
||||||
hasOpened=fileDialog->openLoad(
|
hasOpened=fileDialog->openLoad(
|
||||||
"Load Sample",
|
"Load Sample",
|
||||||
{"compatible files", "*.wav *.dmc",
|
{"compatible files", "*.wav *.dmc *.brr",
|
||||||
"all files", ".*"},
|
"all files", ".*"},
|
||||||
"compatible files{.wav,.dmc},.*",
|
"compatible files{.wav,.dmc,.brr},.*",
|
||||||
workingDirSample,
|
workingDirSample,
|
||||||
dpiScale
|
dpiScale
|
||||||
);
|
);
|
||||||
|
|
|
@ -1043,6 +1043,7 @@ const int chipsSample[]={
|
||||||
DIV_SYSTEM_MSM6258,
|
DIV_SYSTEM_MSM6258,
|
||||||
DIV_SYSTEM_MSM6295,
|
DIV_SYSTEM_MSM6295,
|
||||||
DIV_SYSTEM_RF5C68,
|
DIV_SYSTEM_RF5C68,
|
||||||
|
DIV_SYSTEM_SNES,
|
||||||
DIV_SYSTEM_PCM_DAC,
|
DIV_SYSTEM_PCM_DAC,
|
||||||
DIV_SYSTEM_ES5506,
|
DIV_SYSTEM_ES5506,
|
||||||
0 // don't remove this last one!
|
0 // don't remove this last one!
|
||||||
|
|
|
@ -227,6 +227,10 @@ const char* saaEnvBits[9]={
|
||||||
"mirror", "loop", "cut", "direction", "resolution", "fixed", "N/A","enabled", NULL
|
"mirror", "loop", "cut", "direction", "resolution", "fixed", "N/A","enabled", NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char* snesModeBits[6]={
|
||||||
|
"noise", "echo", "pitch mod", "invert right", "invert left", NULL
|
||||||
|
};
|
||||||
|
|
||||||
const char* filtModeBits[5]={
|
const char* filtModeBits[5]={
|
||||||
"low", "band", "high", "ch3off", NULL
|
"low", "band", "high", "ch3off", NULL
|
||||||
};
|
};
|
||||||
|
@ -4499,7 +4503,9 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
if (ins->type==DIV_INS_AMIGA) {
|
if (ins->type==DIV_INS_AMIGA) {
|
||||||
volMax=64;
|
volMax=64;
|
||||||
}
|
}
|
||||||
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_SEGAPCM || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) {
|
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_SEGAPCM || ins->type==DIV_INS_MIKEY ||
|
||||||
|
ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU || ins->type==DIV_INS_OPZ ||
|
||||||
|
ins->type==DIV_INS_OPM || ins->type==DIV_INS_SNES) {
|
||||||
volMax=127;
|
volMax=127;
|
||||||
}
|
}
|
||||||
if (ins->type==DIV_INS_GB) {
|
if (ins->type==DIV_INS_GB) {
|
||||||
|
@ -4582,9 +4588,12 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
dutyLabel="Noise";
|
dutyLabel="Noise";
|
||||||
dutyMax=ins->amiga.useSample?0:8;
|
dutyMax=ins->amiga.useSample?0:8;
|
||||||
}
|
}
|
||||||
|
if (ins->type==DIV_INS_SNES) {
|
||||||
|
dutyLabel="Noise Freq";
|
||||||
|
dutyMax=31;
|
||||||
|
}
|
||||||
if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS ||
|
if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS ||
|
||||||
ins->type==DIV_INS_VRC6_SAW || ins->type==DIV_INS_FDS || ins->type==DIV_INS_MULTIPCM ||
|
ins->type==DIV_INS_VRC6_SAW || ins->type==DIV_INS_FDS || ins->type==DIV_INS_MULTIPCM) {
|
||||||
ins->type==DIV_INS_SNES) {
|
|
||||||
dutyMax=0;
|
dutyMax=0;
|
||||||
}
|
}
|
||||||
if (ins->type==DIV_INS_VERA) {
|
if (ins->type==DIV_INS_VERA) {
|
||||||
|
@ -4730,9 +4739,9 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
ex1Max=65535;
|
ex1Max=65535;
|
||||||
ex2Max=65535;
|
ex2Max=65535;
|
||||||
}
|
}
|
||||||
if (ins->type==DIV_INS_SNES && !ins->snes.useEnv) {
|
if (ins->type==DIV_INS_SNES) {
|
||||||
ex1Max=4;
|
ex1Max=5;
|
||||||
ex2Max=31;
|
ex2Max=5;
|
||||||
}
|
}
|
||||||
|
|
||||||
int panMin=0;
|
int panMin=0;
|
||||||
|
@ -4783,6 +4792,10 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
panMax=127;
|
panMax=127;
|
||||||
panSingleNoBit=true;
|
panSingleNoBit=true;
|
||||||
}
|
}
|
||||||
|
if (ins->type==DIV_INS_SNES) {
|
||||||
|
panMin=0;
|
||||||
|
panMax=127;
|
||||||
|
}
|
||||||
if (ins->type==DIV_INS_ES5506) {
|
if (ins->type==DIV_INS_ES5506) {
|
||||||
panMax=65535;
|
panMax=65535;
|
||||||
}
|
}
|
||||||
|
@ -4875,7 +4888,7 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
} else if (ins->type==DIV_INS_QSOUND) {
|
} else if (ins->type==DIV_INS_QSOUND) {
|
||||||
macroList.push_back(FurnaceGUIMacroDesc("Echo Feedback",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
macroList.push_back(FurnaceGUIMacroDesc("Echo Feedback",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||||
} else if (ins->type==DIV_INS_SNES) {
|
} else if (ins->type==DIV_INS_SNES) {
|
||||||
macroList.push_back(FurnaceGUIMacroDesc("Gain Mode",&ins->std.ex1Macro,0,ex1Max,64,uiColors[GUI_COLOR_MACRO_VOLUME],false,NULL,NULL,false,snesGainModes));
|
macroList.push_back(FurnaceGUIMacroDesc("Special",&ins->std.ex1Macro,0,ex1Max,96,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,snesModeBits));
|
||||||
} else {
|
} else {
|
||||||
macroList.push_back(FurnaceGUIMacroDesc("Duty",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
macroList.push_back(FurnaceGUIMacroDesc("Duty",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||||
}
|
}
|
||||||
|
@ -4894,7 +4907,7 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
} else if (ins->type==DIV_INS_QSOUND) {
|
} else if (ins->type==DIV_INS_QSOUND) {
|
||||||
macroList.push_back(FurnaceGUIMacroDesc("Echo Length",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
macroList.push_back(FurnaceGUIMacroDesc("Echo Length",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||||
} else if (ins->type==DIV_INS_SNES) {
|
} else if (ins->type==DIV_INS_SNES) {
|
||||||
macroList.push_back(FurnaceGUIMacroDesc("Gain Rate",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
|
macroList.push_back(FurnaceGUIMacroDesc("Gain Mode",&ins->std.ex2Macro,0,ex2Max,64,uiColors[GUI_COLOR_MACRO_VOLUME],false,NULL,NULL,false,snesGainModes));
|
||||||
} else {
|
} else {
|
||||||
macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex2Macro,0,ex2Max,ex2Bit?64:160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,ex2Bit,ayEnvBits));
|
macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex2Macro,0,ex2Max,ex2Bit?64:160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,ex2Bit,ayEnvBits));
|
||||||
}
|
}
|
||||||
|
@ -4934,6 +4947,9 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
macroList.push_back(FurnaceGUIMacroDesc("Envelope mode",&ins->std.ex8Macro,0,2,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,es5506EnvelopeModes));
|
macroList.push_back(FurnaceGUIMacroDesc("Envelope mode",&ins->std.ex8Macro,0,2,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,es5506EnvelopeModes));
|
||||||
macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,es5506ControlModes));
|
macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,es5506ControlModes));
|
||||||
}
|
}
|
||||||
|
if (ins->type==DIV_INS_SNES) {
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc("Gain Rate",&ins->std.ex3Macro,0,127,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
|
||||||
|
}
|
||||||
|
|
||||||
drawMacros(macroList);
|
drawMacros(macroList);
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
|
|
|
@ -3296,6 +3296,7 @@ void FurnaceGUI::applyUISettings(bool updateFonts) {
|
||||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".dmw",uiColors[GUI_COLOR_FILE_WAVE],ICON_FA_FILE);
|
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".dmw",uiColors[GUI_COLOR_FILE_WAVE],ICON_FA_FILE);
|
||||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".wav",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".wav",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
||||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".dmc",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".dmc",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
||||||
|
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".brr",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
||||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".vgm",uiColors[GUI_COLOR_FILE_VGM],ICON_FA_FILE_AUDIO_O);
|
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".vgm",uiColors[GUI_COLOR_FILE_VGM],ICON_FA_FILE_AUDIO_O);
|
||||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".zsm",uiColors[GUI_COLOR_FILE_ZSM],ICON_FA_FILE_AUDIO_O);
|
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".zsm",uiColors[GUI_COLOR_FILE_ZSM],ICON_FA_FILE_AUDIO_O);
|
||||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".ttf",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT);
|
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".ttf",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT);
|
||||||
|
|
|
@ -764,12 +764,27 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case DIV_SYSTEM_SNES: {
|
||||||
|
ImGui::Text("Volume scale:");
|
||||||
|
int vsL=127-(flags&127);
|
||||||
|
int vsR=127-((flags>>8)&127);
|
||||||
|
if (CWSliderInt("Left##VolScaleL",&vsL,0,127)) {
|
||||||
|
if (vsL<0) vsL=0;
|
||||||
|
if (vsL>127) vsL=127;
|
||||||
|
copyOfFlags=(flags&(~0x7f))|(127-vsL);
|
||||||
|
} rightClickable
|
||||||
|
if (CWSliderInt("Right##VolScaleL",&vsR,0,127)) {
|
||||||
|
if (vsR<0) vsR=0;
|
||||||
|
if (vsR>127) vsR=127;
|
||||||
|
copyOfFlags=(flags&(~0x7f00))|((127-vsR)<<8);
|
||||||
|
} rightClickable
|
||||||
|
break;
|
||||||
|
}
|
||||||
case DIV_SYSTEM_SWAN:
|
case DIV_SYSTEM_SWAN:
|
||||||
case DIV_SYSTEM_VERA:
|
case DIV_SYSTEM_VERA:
|
||||||
case DIV_SYSTEM_BUBSYS_WSG:
|
case DIV_SYSTEM_BUBSYS_WSG:
|
||||||
case DIV_SYSTEM_YMU759:
|
case DIV_SYSTEM_YMU759:
|
||||||
case DIV_SYSTEM_PET:
|
case DIV_SYSTEM_PET:
|
||||||
case DIV_SYSTEM_SNES:
|
|
||||||
case DIV_SYSTEM_T6W28:
|
case DIV_SYSTEM_T6W28:
|
||||||
ImGui::Text("nothing to configure");
|
ImGui::Text("nothing to configure");
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue