Merge branch 'master' of https://github.com/tildearrow/furnace into ym2610b
# Conflicts: # src/engine/engine.cpp # src/engine/platform/ym2610Interface.cpp
This commit is contained in:
commit
d831a522a4
|
@ -25,6 +25,8 @@ furthermore, an `or reserved` indicates this field is always present, but is res
|
||||||
|
|
||||||
the format versions are:
|
the format versions are:
|
||||||
|
|
||||||
|
- 59: Furnace dev59
|
||||||
|
- 58: Furnace dev58
|
||||||
- 57: Furnace dev57
|
- 57: Furnace dev57
|
||||||
|
|
||||||
- 53: Furnace 0.5.7
|
- 53: Furnace 0.5.7
|
||||||
|
@ -202,6 +204,8 @@ size | description
|
||||||
S?? | channel short names
|
S?? | channel short names
|
||||||
| - same as above
|
| - same as above
|
||||||
STR | song comment
|
STR | song comment
|
||||||
|
4f | master volume, 1.0f=100% (>=59)
|
||||||
|
| this is 2.0f for modules before 59
|
||||||
|
|
||||||
# instrument
|
# instrument
|
||||||
|
|
||||||
|
|
|
@ -444,44 +444,65 @@ void DivEngine::renderSamples() {
|
||||||
sPreview.sample=-1;
|
sPreview.sample=-1;
|
||||||
sPreview.pos=0;
|
sPreview.pos=0;
|
||||||
|
|
||||||
|
// step 1: render samples
|
||||||
for (int i=0; i<song.sampleLen; i++) {
|
for (int i=0; i<song.sampleLen; i++) {
|
||||||
song.sample[i]->render();
|
song.sample[i]->render();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// step 2: allocate ADPCM-A samples
|
||||||
// step 3: allocate ADPCM samples
|
if (adpcmAMem==NULL) adpcmAMem=new unsigned char[16777216];
|
||||||
if (adpcmMem==NULL) adpcmMem=new unsigned char[16777216];
|
|
||||||
|
|
||||||
size_t memPos=0;
|
size_t memPos=0;
|
||||||
for (int i=0; i<song.sampleLen; i++) {
|
for (int i=0; i<song.sampleLen; i++) {
|
||||||
DivSample* s=song.sample[i];
|
DivSample* s=song.sample[i];
|
||||||
if ((memPos&0xf00000)!=((memPos+s->adpcmRendLength)&0xf00000)) {
|
int paddedLen=(s->lengthA+255)&(~0xff);
|
||||||
|
if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) {
|
||||||
memPos=(memPos+0xfffff)&0xf00000;
|
memPos=(memPos+0xfffff)&0xf00000;
|
||||||
}
|
}
|
||||||
if (memPos>=16777216) {
|
if (memPos>=16777216) {
|
||||||
logW("out of ADPCM memory for sample %d!\n",i);
|
logW("out of ADPCM memory for sample %d!\n",i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (memPos+s->adpcmRendLength>=16777216) {
|
if (memPos+paddedLen>=16777216) {
|
||||||
memcpy(adpcmMem+memPos,s->adpcmRendData,16777216-memPos);
|
memcpy(adpcmAMem+memPos,s->dataA,16777216-memPos);
|
||||||
logW("out of ADPCM memory for sample %d!\n",i);
|
logW("out of ADPCM memory for sample %d!\n",i);
|
||||||
} else {
|
} else {
|
||||||
memcpy(adpcmMem+memPos,s->adpcmRendData,s->adpcmRendLength);
|
memcpy(adpcmAMem+memPos,s->dataA,paddedLen);
|
||||||
}
|
}
|
||||||
s->rendOff=memPos;
|
s->offA=memPos;
|
||||||
memPos+=s->adpcmRendLength;
|
memPos+=paddedLen;
|
||||||
}
|
}
|
||||||
adpcmMemLen=memPos+256;
|
adpcmAMemLen=memPos+256;
|
||||||
|
|
||||||
// step 4: allocate qsound pcm samples
|
// step 3: allocate ADPCM-B samples
|
||||||
if (qsoundMem==NULL) qsoundMem=new unsigned char[16777216];
|
if (adpcmBMem==NULL) adpcmBMem=new unsigned char[16777216];
|
||||||
|
|
||||||
memset(qsoundMem, 0, 16777216);
|
|
||||||
|
|
||||||
memPos=0;
|
memPos=0;
|
||||||
for (int i=0; i<song.sampleLen; i++) {
|
for (int i=0; i<song.sampleLen; i++) {
|
||||||
DivSample* s=song.sample[i];
|
DivSample* s=song.sample[i];
|
||||||
int length = s->rendLength;
|
int paddedLen=(s->lengthB+255)&(~0xff);
|
||||||
|
if (memPos>=16777216) {
|
||||||
|
logW("out of ADPCM-B memory for sample %d!\n",i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (memPos+paddedLen>=16777216) {
|
||||||
|
memcpy(adpcmBMem+memPos,s->dataB,16777216-memPos);
|
||||||
|
logW("out of ADPCM-B memory for sample %d!\n",i);
|
||||||
|
} else {
|
||||||
|
memcpy(adpcmBMem+memPos,s->dataB,paddedLen);
|
||||||
|
}
|
||||||
|
s->offB=memPos;
|
||||||
|
memPos+=paddedLen;
|
||||||
|
}
|
||||||
|
adpcmBMemLen=memPos+256;
|
||||||
|
|
||||||
|
// step 4: allocate qsound pcm samples
|
||||||
|
if (qsoundMem==NULL) qsoundMem=new unsigned char[16777216];
|
||||||
|
|
||||||
|
memPos=0;
|
||||||
|
for (int i=0; i<song.sampleLen; i++) {
|
||||||
|
DivSample* s=song.sample[i];
|
||||||
|
int length=s->length8;
|
||||||
if (length>65536-16) {
|
if (length>65536-16) {
|
||||||
length=65536-16;
|
length=65536-16;
|
||||||
}
|
}
|
||||||
|
@ -494,41 +515,18 @@ void DivEngine::renderSamples() {
|
||||||
}
|
}
|
||||||
if (memPos+length>=16777216) {
|
if (memPos+length>=16777216) {
|
||||||
for (unsigned int i=0; i<16777216-(memPos+length); i++) {
|
for (unsigned int i=0; i<16777216-(memPos+length); i++) {
|
||||||
qsoundMem[(memPos + i) ^ 0x8000] = s->rendData[i] >> ((s->depth == 16) ? 8 : 0);
|
qsoundMem[(memPos+i)^0x8000]=s->data8[i];
|
||||||
}
|
}
|
||||||
logW("out of QSound PCM memory for sample %d!\n",i);
|
logW("out of QSound PCM memory for sample %d!\n",i);
|
||||||
} else {
|
} else {
|
||||||
for (int i=0; i<length; i++) {
|
for (int i=0; i<length; i++) {
|
||||||
qsoundMem[(memPos + i) ^ 0x8000] = s->rendData[i] >> ((s->depth == 16) ? 8 : 0);
|
qsoundMem[(memPos+i)^0x8000]=s->data8[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s->rendOffQsound=memPos ^ 0x8000;
|
s->offQSound=memPos^0x8000;
|
||||||
memPos+=length+16;
|
memPos+=length+16;
|
||||||
}
|
}
|
||||||
qsoundMemLen=memPos+256;
|
qsoundMemLen=memPos+256;
|
||||||
|
|
||||||
// step 5: allocate ADPCM-B samples
|
|
||||||
if (adpcmBMem==NULL) adpcmBMem=new unsigned char[16777216];
|
|
||||||
|
|
||||||
memPos=0;
|
|
||||||
for (int i=0; i<song.sampleLen; i++) {
|
|
||||||
DivSample* s=song.sample[i];
|
|
||||||
if (memPos>=16777216) {
|
|
||||||
logW("out of ADPCM-B memory for sample %d!\n",i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (memPos+s->adpcmBRendLength>=16777216) {
|
|
||||||
memcpy(adpcmBMem+memPos,s->adpcmBRendData,16777216-memPos);
|
|
||||||
logW("out of ADPCM-B memory for sample %d!\n",i);
|
|
||||||
} else {
|
|
||||||
memcpy(adpcmBMem+memPos,s->adpcmBRendData,s->adpcmBRendLength);
|
|
||||||
}
|
|
||||||
s->rendOff=memPos;
|
|
||||||
memPos+=s->adpcmBRendLength;
|
|
||||||
}
|
|
||||||
adpcmBMemLen=memPos+256;
|
|
||||||
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivEngine::createNew() {
|
void DivEngine::createNew() {
|
||||||
|
|
|
@ -37,8 +37,8 @@
|
||||||
warnings+=(String("\n")+x); \
|
warnings+=(String("\n")+x); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DIV_VERSION "dev58"
|
#define DIV_VERSION "dev59"
|
||||||
#define DIV_ENGINE_VERSION 58
|
#define DIV_ENGINE_VERSION 59
|
||||||
|
|
||||||
enum DivStatusView {
|
enum DivStatusView {
|
||||||
DIV_STATUS_NOTHING=0,
|
DIV_STATUS_NOTHING=0,
|
||||||
|
@ -621,12 +621,16 @@ class DivEngine {
|
||||||
// terminate the engine.
|
// terminate the engine.
|
||||||
bool quit();
|
bool quit();
|
||||||
|
|
||||||
unsigned char* adpcmMem;
|
unsigned char* adpcmAMem;
|
||||||
size_t adpcmMemLen;
|
size_t adpcmAMemLen;
|
||||||
unsigned char* adpcmBMem;
|
unsigned char* adpcmBMem;
|
||||||
size_t adpcmBMemLen;
|
size_t adpcmBMemLen;
|
||||||
unsigned char* qsoundMem;
|
unsigned char* qsoundMem;
|
||||||
size_t qsoundMemLen;
|
size_t qsoundMemLen;
|
||||||
|
unsigned char* qsoundAMem;
|
||||||
|
size_t qsoundAMemLen;
|
||||||
|
unsigned char* dpcmMem;
|
||||||
|
size_t dpcmMemLen;
|
||||||
|
|
||||||
DivEngine():
|
DivEngine():
|
||||||
output(NULL),
|
output(NULL),
|
||||||
|
@ -680,11 +684,15 @@ class DivEngine {
|
||||||
totalProcessed(0),
|
totalProcessed(0),
|
||||||
oscBuf{NULL,NULL},
|
oscBuf{NULL,NULL},
|
||||||
oscSize(1),
|
oscSize(1),
|
||||||
adpcmMem(NULL),
|
adpcmAMem(NULL),
|
||||||
adpcmMemLen(0),
|
adpcmAMemLen(0),
|
||||||
adpcmBMem(NULL),
|
adpcmBMem(NULL),
|
||||||
adpcmBMemLen(0),
|
adpcmBMemLen(0),
|
||||||
qsoundMem(NULL),
|
qsoundMem(NULL),
|
||||||
qsoundMemLen(0) {}
|
qsoundMemLen(0),
|
||||||
|
qsoundAMem(NULL),
|
||||||
|
qsoundAMemLen(0),
|
||||||
|
dpcmMem(NULL),
|
||||||
|
dpcmMemLen(0) {}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -845,7 +845,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
||||||
if (tchans>DIV_MAX_CHANS) tchans=DIV_MAX_CHANS;
|
if (tchans>DIV_MAX_CHANS) tchans=DIV_MAX_CHANS;
|
||||||
|
|
||||||
// system volume
|
// system volume
|
||||||
for (int i=0; i<32; i++) ds.systemVol[i]=reader.readC();
|
for (int i=0; i<32; i++) {
|
||||||
|
ds.systemVol[i]=reader.readC();
|
||||||
|
if (ds.version<59 && ds.system[i]==DIV_SYSTEM_NES) {
|
||||||
|
ds.systemVol[i]/=4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// system panning
|
// system panning
|
||||||
for (int i=0; i<32; i++) ds.systemPan[i]=reader.readC();
|
for (int i=0; i<32; i++) ds.systemPan[i]=reader.readC();
|
||||||
|
@ -1003,6 +1008,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
||||||
ds.notes=reader.readString();
|
ds.notes=reader.readString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ds.version>=59) {
|
||||||
|
ds.masterVol=reader.readF();
|
||||||
|
} else {
|
||||||
|
ds.masterVol=2.0f;
|
||||||
|
}
|
||||||
|
|
||||||
// read instruments
|
// read instruments
|
||||||
for (int i=0; i<ds.insLen; i++) {
|
for (int i=0; i<ds.insLen; i++) {
|
||||||
DivInstrument* ins=new DivInstrument;
|
DivInstrument* ins=new DivInstrument;
|
||||||
|
@ -1448,6 +1459,8 @@ SafeWriter* DivEngine::saveFur() {
|
||||||
|
|
||||||
w->writeString(song.notes,false);
|
w->writeString(song.notes,false);
|
||||||
|
|
||||||
|
w->writeF(song.masterVol);
|
||||||
|
|
||||||
/// INSTRUMENT
|
/// INSTRUMENT
|
||||||
for (int i=0; i<song.insLen; i++) {
|
for (int i=0; i<song.insLen; i++) {
|
||||||
DivInstrument* ins=song.ins[i];
|
DivInstrument* ins=song.ins[i];
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#define WRITE_CONTROL(ch,v) rWrite(0x25+(ch<<3),(v))
|
#define WRITE_CONTROL(ch,v) rWrite(0x25+(ch<<3),(v))
|
||||||
#define WRITE_OTHER(ch,v) rWrite(0x27+(ch<<3),(v))
|
#define WRITE_OTHER(ch,v) rWrite(0x27+(ch<<3),(v))
|
||||||
#define WRITE_ATTEN(ch,v) rWrite((0x40+ch),(v))
|
#define WRITE_ATTEN(ch,v) rWrite((0x40+ch),(v))
|
||||||
|
#define WRITE_STEREO(v) rWrite(0x50,(v))
|
||||||
|
|
||||||
#define CHIP_DIVIDER 64
|
#define CHIP_DIVIDER 64
|
||||||
|
|
||||||
|
@ -197,7 +198,8 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_PANNING:
|
case DIV_CMD_PANNING:
|
||||||
WRITE_ATTEN(c.chan, c.value);
|
chan[c.chan].pan=((c.value&0x0f)<<4)|((c.value&0xf0)>>4);
|
||||||
|
WRITE_ATTEN(c.chan,chan[c.chan].pan);
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_GET_VOLUME:
|
case DIV_CMD_GET_VOLUME:
|
||||||
if (chan[c.chan].std.hasVol) {
|
if (chan[c.chan].std.hasVol) {
|
||||||
|
@ -261,6 +263,10 @@ void DivPlatformLynx::muteChannel(int ch, bool mute) {
|
||||||
if (chan[ch].active) WRITE_VOLUME(ch,(isMuted[ch]?0:(chan[ch].outVol&127)));
|
if (chan[ch].active) WRITE_VOLUME(ch,(isMuted[ch]?0:(chan[ch].outVol&127)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DivPlatformLynx::isStereo() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformLynx::forceIns() {
|
void DivPlatformLynx::forceIns() {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
if (chan[i].active) {
|
if (chan[i].active) {
|
||||||
|
@ -294,6 +300,7 @@ void DivPlatformLynx::reset() {
|
||||||
if (dumpWrites) {
|
if (dumpWrites) {
|
||||||
addWrite(0xffffffff,0);
|
addWrite(0xffffffff,0);
|
||||||
}
|
}
|
||||||
|
WRITE_STEREO(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DivPlatformLynx::keyOffAffectsArp(int ch) {
|
bool DivPlatformLynx::keyOffAffectsArp(int ch) {
|
||||||
|
|
|
@ -45,7 +45,7 @@ class DivPlatformLynx: public DivDispatch {
|
||||||
MikeyFreqDiv fd;
|
MikeyFreqDiv fd;
|
||||||
MikeyDuty duty;
|
MikeyDuty duty;
|
||||||
int baseFreq, pitch, note, actualNote, lfsr;
|
int baseFreq, pitch, note, actualNote, lfsr;
|
||||||
unsigned char ins;
|
unsigned char ins, pan;
|
||||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
|
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
|
||||||
signed char vol, outVol;
|
signed char vol, outVol;
|
||||||
Channel():
|
Channel():
|
||||||
|
@ -58,6 +58,7 @@ class DivPlatformLynx: public DivDispatch {
|
||||||
actualNote(0),
|
actualNote(0),
|
||||||
lfsr(-1),
|
lfsr(-1),
|
||||||
ins(-1),
|
ins(-1),
|
||||||
|
pan(0xff),
|
||||||
active(false),
|
active(false),
|
||||||
insChanged(true),
|
insChanged(true),
|
||||||
freqChanged(false),
|
freqChanged(false),
|
||||||
|
@ -81,6 +82,7 @@ class DivPlatformLynx: public DivDispatch {
|
||||||
void forceIns();
|
void forceIns();
|
||||||
void tick();
|
void tick();
|
||||||
void muteChannel(int ch, bool mute);
|
void muteChannel(int ch, bool mute);
|
||||||
|
bool isStereo();
|
||||||
bool keyOffAffectsArp(int ch);
|
bool keyOffAffectsArp(int ch);
|
||||||
bool keyOffAffectsPorta(int ch);
|
bool keyOffAffectsPorta(int ch);
|
||||||
//int getPortaFloor(int ch);
|
//int getPortaFloor(int ch);
|
||||||
|
|
|
@ -99,7 +99,10 @@ void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len)
|
||||||
if (nes->apu.clocked) {
|
if (nes->apu.clocked) {
|
||||||
nes->apu.clocked=false;
|
nes->apu.clocked=false;
|
||||||
}
|
}
|
||||||
bufL[i]=(pulse_output(nes)+tnd_output(nes))*30;
|
int sample=(pulse_output(nes)+tnd_output(nes)-128)<<7;
|
||||||
|
if (sample>32767) sample=32767;
|
||||||
|
if (sample<-32768) sample=-32768;
|
||||||
|
bufL[i]=sample;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -301,7 +301,9 @@ void DivPlatformSMS::poke(std::vector<DivRegWrite>& wlist) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformSMS::setFlags(unsigned int flags) {
|
void DivPlatformSMS::setFlags(unsigned int flags) {
|
||||||
if ((flags&3)==2) {
|
if ((flags&3)==3) {
|
||||||
|
chipClock=COLOR_NTSC/2.0;
|
||||||
|
} else if ((flags&3)==2) {
|
||||||
chipClock=4000000;
|
chipClock=4000000;
|
||||||
} else if ((flags&3)==1) {
|
} else if ((flags&3)==1) {
|
||||||
chipClock=COLOR_PAL*4.0/5.0;
|
chipClock=COLOR_PAL*4.0/5.0;
|
||||||
|
|
|
@ -22,11 +22,19 @@
|
||||||
#include "../engine.h"
|
#include "../engine.h"
|
||||||
|
|
||||||
uint8_t DivYM2610Interface::ymfm_external_read(ymfm::access_class type, uint32_t address) {
|
uint8_t DivYM2610Interface::ymfm_external_read(ymfm::access_class type, uint32_t address) {
|
||||||
//printf("wants to read from %x\n",address);
|
switch (type) {
|
||||||
if (type!=ymfm::ACCESS_ADPCM_A) return /*s->dataB[address&0xffffff];*/0;
|
case ymfm::ACCESS_ADPCM_A:
|
||||||
return parent->adpcmMem[address&0xffffff];/*s->dataA[address&0xffffff]*/
|
if (parent->adpcmAMem==NULL) return 0;
|
||||||
/*if (12*sampleBank+(address>>16)>=parent->song.sampleLen) return 0;
|
if ((address&0xffffff)>=parent->adpcmAMemLen) return 0;
|
||||||
return parent->song.sample[12*sampleBank+(address>>16)]->adpcmRendData[(address&0xffff)];*/
|
return parent->adpcmAMem[address&0xffffff];
|
||||||
|
case ymfm::ACCESS_ADPCM_B:
|
||||||
|
if (parent->adpcmBMem==NULL) return 0;
|
||||||
|
if ((address&0xffffff)>=parent->adpcmBMemLen) return 0;
|
||||||
|
return parent->adpcmBMem[address&0xffffff];
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivYM2610Interface::ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data) {
|
void DivYM2610Interface::ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data) {
|
||||||
|
|
|
@ -237,7 +237,7 @@ void DivPlatformYM2610B::tick() {
|
||||||
|
|
||||||
// FM
|
// FM
|
||||||
for (int i=0; i<6; i++) {
|
for (int i=0; i<6; i++) {
|
||||||
if (i==1 && extMode) continue;
|
if (i==2 && extMode) continue;
|
||||||
chan[i].std.next();
|
chan[i].std.next();
|
||||||
|
|
||||||
if (chan[i].std.hadVol) {
|
if (chan[i].std.hadVol) {
|
||||||
|
@ -366,7 +366,7 @@ void DivPlatformYM2610B::tick() {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<6; i++) {
|
for (int i=0; i<6; i++) {
|
||||||
if (i==1 && extMode) continue;
|
if (i==2 && extMode) continue;
|
||||||
if (chan[i].freqChanged) {
|
if (chan[i].freqChanged) {
|
||||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq));
|
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq));
|
||||||
if (chan[i].freq>262143) chan[i].freq=262143;
|
if (chan[i].freq>262143) chan[i].freq=262143;
|
||||||
|
|
|
@ -1314,17 +1314,17 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<song.systemLen; i++) {
|
for (int i=0; i<song.systemLen; i++) {
|
||||||
float volL=((float)song.systemVol[i]/64.0f)*((float)MIN(127,127-(int)song.systemPan[i])/127.0f);
|
float volL=((float)song.systemVol[i]/64.0f)*((float)MIN(127,127-(int)song.systemPan[i])/127.0f)*song.masterVol;
|
||||||
float volR=((float)song.systemVol[i]/64.0f)*((float)MIN(127,127+(int)song.systemPan[i])/127.0f);
|
float volR=((float)song.systemVol[i]/64.0f)*((float)MIN(127,127+(int)song.systemPan[i])/127.0f)*song.masterVol;
|
||||||
if (disCont[i].dispatch->isStereo()) {
|
if (disCont[i].dispatch->isStereo()) {
|
||||||
for (size_t j=0; j<size; j++) {
|
for (size_t j=0; j<size; j++) {
|
||||||
out[0][j]+=((float)disCont[i].bbOut[0][j]/16384.0)*volL;
|
out[0][j]+=((float)disCont[i].bbOut[0][j]/32768.0)*volL;
|
||||||
out[1][j]+=((float)disCont[i].bbOut[1][j]/16384.0)*volR;
|
out[1][j]+=((float)disCont[i].bbOut[1][j]/32768.0)*volR;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (size_t j=0; j<size; j++) {
|
for (size_t j=0; j<size; j++) {
|
||||||
out[0][j]+=((float)disCont[i].bbOut[0][j]/16384.0)*volL;
|
out[0][j]+=((float)disCont[i].bbOut[0][j]/32768.0)*volL;
|
||||||
out[1][j]+=((float)disCont[i].bbOut[0][j]/16384.0)*volR;
|
out[1][j]+=((float)disCont[i].bbOut[0][j]/32768.0)*volR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ bool DivSample::save(const char* path) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 16-bit memory is padded to 512, to make things easier for ADPCM-A/B.
|
||||||
bool DivSample::initInternal(unsigned char d, int count) {
|
bool DivSample::initInternal(unsigned char d, int count) {
|
||||||
switch (d) {
|
switch (d) {
|
||||||
case 0: // 1-bit
|
case 0: // 1-bit
|
||||||
|
@ -96,14 +97,14 @@ bool DivSample::initInternal(unsigned char d, int count) {
|
||||||
case 5: // ADPCM-A
|
case 5: // ADPCM-A
|
||||||
if (dataA!=NULL) delete[] dataA;
|
if (dataA!=NULL) delete[] dataA;
|
||||||
lengthA=(count+1)/2;
|
lengthA=(count+1)/2;
|
||||||
dataA=new unsigned char[lengthA];
|
dataA=new unsigned char[(lengthA+255)&(~0xff)];
|
||||||
memset(dataA,0,lengthA);
|
memset(dataA,0,(lengthA+255)&(~0xff));
|
||||||
break;
|
break;
|
||||||
case 6: // ADPCM-B
|
case 6: // ADPCM-B
|
||||||
if (dataB!=NULL) delete[] dataB;
|
if (dataB!=NULL) delete[] dataB;
|
||||||
lengthB=(count+1)/2;
|
lengthB=(count+1)/2;
|
||||||
dataB=new unsigned char[lengthB];
|
dataB=new unsigned char[(lengthB+255)&(~0xff)];
|
||||||
memset(dataB,0,lengthB);
|
memset(dataB,0,(lengthB+255)&(~0xff));
|
||||||
break;
|
break;
|
||||||
case 7: // X68000 ADPCM
|
case 7: // X68000 ADPCM
|
||||||
if (dataX68!=NULL) delete[] dataX68;
|
if (dataX68!=NULL) delete[] dataX68;
|
||||||
|
@ -132,8 +133,8 @@ bool DivSample::initInternal(unsigned char d, int count) {
|
||||||
case 16: // 16-bit
|
case 16: // 16-bit
|
||||||
if (data16!=NULL) delete[] data16;
|
if (data16!=NULL) delete[] data16;
|
||||||
length16=count*2;
|
length16=count*2;
|
||||||
data16=new short[count];
|
data16=new short[(count+511)&(~0x1ff)];
|
||||||
memset(data16,0,count*sizeof(short));
|
memset(data16,0,((count+511)&(~0x1ff))*sizeof(short));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -223,13 +224,14 @@ void DivSample::render() {
|
||||||
if (!initInternal(4,samples)) return;
|
if (!initInternal(4,samples)) return;
|
||||||
bs_encode(data16,dataQSoundA,samples);
|
bs_encode(data16,dataQSoundA,samples);
|
||||||
}
|
}
|
||||||
|
// TODO: pad to 256.
|
||||||
if (depth!=5) { // ADPCM-A
|
if (depth!=5) { // ADPCM-A
|
||||||
if (!initInternal(5,samples)) return;
|
if (!initInternal(5,samples)) return;
|
||||||
yma_encode(data16,dataA,samples);
|
yma_encode(data16,dataA,(samples+511)&(~0x1ff));
|
||||||
}
|
}
|
||||||
if (depth!=6) { // ADPCM-B
|
if (depth!=6) { // ADPCM-B
|
||||||
if (!initInternal(6,samples)) return;
|
if (!initInternal(6,samples)) return;
|
||||||
ymb_encode(data16,dataB,samples);
|
ymb_encode(data16,dataB,(samples+511)&(~0x1ff));
|
||||||
}
|
}
|
||||||
if (depth!=7) { // X68000 ADPCM
|
if (depth!=7) { // X68000 ADPCM
|
||||||
if (!initInternal(7,samples)) return;
|
if (!initInternal(7,samples)) return;
|
||||||
|
|
|
@ -242,6 +242,7 @@ struct DivSong {
|
||||||
bool pal;
|
bool pal;
|
||||||
bool customTempo;
|
bool customTempo;
|
||||||
int hz, patLen, ordersLen, insLen, waveLen, sampleLen;
|
int hz, patLen, ordersLen, insLen, waveLen, sampleLen;
|
||||||
|
float masterVol;
|
||||||
float tuning;
|
float tuning;
|
||||||
|
|
||||||
// compatibility flags
|
// compatibility flags
|
||||||
|
@ -309,6 +310,7 @@ struct DivSong {
|
||||||
insLen(0),
|
insLen(0),
|
||||||
waveLen(0),
|
waveLen(0),
|
||||||
sampleLen(0),
|
sampleLen(0),
|
||||||
|
masterVol(1.0f),
|
||||||
tuning(440.0f),
|
tuning(440.0f),
|
||||||
limitSlides(false),
|
limitSlides(false),
|
||||||
linearPitch(true),
|
linearPitch(true),
|
||||||
|
|
|
@ -938,14 +938,24 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop) {
|
||||||
delete[] pcmMem;
|
delete[] pcmMem;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (writeADPCM && adpcmMemLen>0) {
|
if (writeADPCM && adpcmAMemLen>0) {
|
||||||
w->writeC(0x67);
|
w->writeC(0x67);
|
||||||
w->writeC(0x66);
|
w->writeC(0x66);
|
||||||
w->writeC(0x82);
|
w->writeC(0x82);
|
||||||
w->writeI(adpcmMemLen+8);
|
w->writeI(adpcmAMemLen+8);
|
||||||
w->writeI(adpcmMemLen);
|
w->writeI(adpcmAMemLen);
|
||||||
w->writeI(0);
|
w->writeI(0);
|
||||||
w->write(adpcmMem,adpcmMemLen);
|
w->write(adpcmAMem,adpcmAMemLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writeADPCM && adpcmBMemLen>0) {
|
||||||
|
w->writeC(0x67);
|
||||||
|
w->writeC(0x66);
|
||||||
|
w->writeC(0x83);
|
||||||
|
w->writeI(adpcmBMemLen+8);
|
||||||
|
w->writeI(adpcmBMemLen);
|
||||||
|
w->writeI(0);
|
||||||
|
w->write(adpcmBMem,adpcmBMemLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (writeQSound && qsoundMemLen>0) {
|
if (writeQSound && qsoundMemLen>0) {
|
||||||
|
|
|
@ -1345,6 +1345,10 @@ void FurnaceGUI::drawMixer() {
|
||||||
ImGui::SetNextWindowSizeConstraints(ImVec2(400.0f*dpiScale,200.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale));
|
ImGui::SetNextWindowSizeConstraints(ImVec2(400.0f*dpiScale,200.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale));
|
||||||
if (ImGui::Begin("Mixer",&mixerOpen,settings.allowEditDocking?0:ImGuiWindowFlags_NoDocking)) {
|
if (ImGui::Begin("Mixer",&mixerOpen,settings.allowEditDocking?0:ImGuiWindowFlags_NoDocking)) {
|
||||||
char id[32];
|
char id[32];
|
||||||
|
if (ImGui::SliderFloat("Master Volume",&e->song.masterVol,0,3,"%.2fx")) {
|
||||||
|
if (e->song.masterVol<0) e->song.masterVol=0;
|
||||||
|
if (e->song.masterVol>3) e->song.masterVol=3;
|
||||||
|
}
|
||||||
for (int i=0; i<e->song.systemLen; i++) {
|
for (int i=0; i<e->song.systemLen; i++) {
|
||||||
snprintf(id,31,"MixS%d",i);
|
snprintf(id,31,"MixS%d",i);
|
||||||
bool doInvert=e->song.systemVol[i]&128;
|
bool doInvert=e->song.systemVol[i]&128;
|
||||||
|
@ -1898,12 +1902,12 @@ void FurnaceGUI::drawStats() {
|
||||||
}
|
}
|
||||||
if (!statsOpen) return;
|
if (!statsOpen) return;
|
||||||
if (ImGui::Begin("Statistics",&statsOpen)) {
|
if (ImGui::Begin("Statistics",&statsOpen)) {
|
||||||
String adpcmUsage=fmt::sprintf("%d/16384KB",e->adpcmMemLen/1024);
|
String adpcmAUsage=fmt::sprintf("%d/16384KB",e->adpcmAMemLen/1024);
|
||||||
String adpcmBUsage=fmt::sprintf("%d/16384KB",e->adpcmBMemLen/1024);
|
String adpcmBUsage=fmt::sprintf("%d/16384KB",e->adpcmBMemLen/1024);
|
||||||
String qsoundUsage=fmt::sprintf("%d/16384KB",e->qsoundMemLen/1024);
|
String qsoundUsage=fmt::sprintf("%d/16384KB",e->qsoundMemLen/1024);
|
||||||
ImGui::Text("ADPCM-A");
|
ImGui::Text("ADPCM-A");
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::ProgressBar(((float)e->adpcmMemLen)/16777216.0f,ImVec2(-FLT_MIN,0),adpcmUsage.c_str());
|
ImGui::ProgressBar(((float)e->adpcmAMemLen)/16777216.0f,ImVec2(-FLT_MIN,0),adpcmAUsage.c_str());
|
||||||
ImGui::Text("ADPCM-B");
|
ImGui::Text("ADPCM-B");
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::ProgressBar(((float)e->adpcmBMemLen)/16777216.0f,ImVec2(-FLT_MIN,0),adpcmBUsage.c_str());
|
ImGui::ProgressBar(((float)e->adpcmBMemLen)/16777216.0f,ImVec2(-FLT_MIN,0),adpcmBUsage.c_str());
|
||||||
|
@ -4542,6 +4546,10 @@ bool FurnaceGUI::loop() {
|
||||||
e->setSysFlags(i,(flags&(~3))|2,restart);
|
e->setSysFlags(i,(flags&(~3))|2,restart);
|
||||||
updateWindowTitle();
|
updateWindowTitle();
|
||||||
}
|
}
|
||||||
|
if (ImGui::RadioButton("Half NTSC (1.79MHz)",(flags&3)==3)) {
|
||||||
|
e->setSysFlags(i,(flags&(~3))|3,restart);
|
||||||
|
updateWindowTitle();
|
||||||
|
}
|
||||||
ImGui::Text("Chip type:");
|
ImGui::Text("Chip type:");
|
||||||
if (ImGui::RadioButton("Sega VDP/Master System",((flags>>2)&3)==0)) {
|
if (ImGui::RadioButton("Sega VDP/Master System",((flags>>2)&3)==0)) {
|
||||||
e->setSysFlags(i,(flags&(~12))|0,restart);
|
e->setSysFlags(i,(flags&(~12))|0,restart);
|
||||||
|
|
Loading…
Reference in New Issue