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

This commit is contained in:
cam900 2022-11-15 11:52:30 +09:00
commit 46880634b4
50 changed files with 2492 additions and 1960 deletions

View file

@ -19,6 +19,7 @@
#include "config.h"
#include "../ta-log.h"
#include "../baseutils.h"
#include "../fileutils.h"
#include <fmt/printf.h>
@ -48,41 +49,9 @@ String DivConfig::toString() {
return ret;
}
const char* base64Table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
String DivConfig::toBase64() {
String data=toString();
String ret;
ret.reserve((2+data.size()*4)/3);
unsigned int groupOfThree=0;
unsigned char pos=0;
for (char& i: data) {
groupOfThree|=((unsigned char)i)<<((2-pos)<<3);
if (++pos>=3) {
pos=0;
ret+=base64Table[(groupOfThree>>18)&63];
ret+=base64Table[(groupOfThree>>12)&63];
ret+=base64Table[(groupOfThree>>6)&63];
ret+=base64Table[groupOfThree&63];
groupOfThree=0;
}
}
if (pos==2) {
ret+=base64Table[(groupOfThree>>18)&63];
ret+=base64Table[(groupOfThree>>12)&63];
ret+=base64Table[(groupOfThree>>6)&63];
ret+='=';
} else if (pos==1) {
ret+=base64Table[(groupOfThree>>18)&63];
ret+=base64Table[(groupOfThree>>12)&63];
ret+="==";
}
logV("toBase64: %s",ret);
return ret;
return taEncodeBase64(data);
}
void DivConfig::parseLine(const char* line) {
@ -143,38 +112,7 @@ bool DivConfig::loadFromMemory(const char* buf) {
}
bool DivConfig::loadFromBase64(const char* buf) {
String data;
unsigned int groupOfThree=0;
signed char pos=18;
for (const char* i=buf; *i; i++) {
unsigned char nextVal=0;
if ((*i)=='/') {
nextVal=63;
} else if ((*i)=='+') {
nextVal=62;
} else if ((*i)>='0' && (*i)<='9') {
nextVal=52+((*i)-'0');
} else if ((*i)>='a' && (*i)<='z') {
nextVal=26+((*i)-'a');
} else if ((*i)>='A' && (*i)<='Z') {
nextVal=((*i)-'A');
} else {
nextVal=0;
}
groupOfThree|=nextVal<<pos;
pos-=6;
if (pos<0) {
pos=18;
if ((groupOfThree>>16)&0xff) data+=(groupOfThree>>16)&0xff;
if ((groupOfThree>>8)&0xff) data+=(groupOfThree>>8)&0xff;
if (groupOfThree&0xff) data+=groupOfThree&0xff;
groupOfThree=0;
}
}
logV("fromBase64: %s",data);
String data=taDecodeBase64(buf);
return loadFromMemory(data.c_str());
}

View file

@ -1390,10 +1390,14 @@ String DivEngine::decodeSysDesc(String desc) {
return newDesc.toBase64();
}
void DivEngine::initSongWithDesc(const char* description) {
void DivEngine::initSongWithDesc(const char* description, bool inBase64) {
int chanCount=0;
DivConfig c;
c.loadFromBase64(description);
if (inBase64) {
c.loadFromBase64(description);
} else {
c.loadFromMemory(description);
}
int index=0;
for (; index<32; index++) {
song.system[index]=systemFromFileFur(c.getInt(fmt::sprintf("id%d",index),0));
@ -1414,7 +1418,7 @@ void DivEngine::initSongWithDesc(const char* description) {
song.systemLen=index;
}
void DivEngine::createNew(const char* description, String sysName) {
void DivEngine::createNew(const char* description, String sysName, bool inBase64) {
quitDispatch();
BUSY_BEGIN;
saveLock.lock();
@ -1422,7 +1426,7 @@ void DivEngine::createNew(const char* description, String sysName) {
song=DivSong();
changeSong(0);
if (description!=NULL) {
initSongWithDesc(description);
initSongWithDesc(description,inBase64);
}
if (sysName=="") {
song.systemName=getSongSystemLegacyName(song,!getConfInt("noMultiSystem",0));
@ -2358,6 +2362,9 @@ void DivEngine::reset() {
firstTick=false;
shallStop=false;
shallStopSched=false;
pendingMetroTick=0;
elapsedBars=0;
elapsedBeats=0;
nextSpeed=speed1;
divider=60;
if (curSubSong->customTempo) {
@ -2548,6 +2555,14 @@ int DivEngine::getRow() {
return prevRow;
}
int DivEngine::getElapsedBars() {
return elapsedBars;
}
int DivEngine::getElapsedBeats() {
return elapsedBeats;
}
size_t DivEngine::getCurrentSubSong() {
return curSubSongIndex;
}
@ -2673,12 +2688,17 @@ void DivEngine::unmuteAll() {
BUSY_END;
}
int DivEngine::addInstrument(int refChan) {
int DivEngine::addInstrument(int refChan, DivInstrumentType fallbackType) {
if (song.ins.size()>=256) return -1;
BUSY_BEGIN;
DivInstrument* ins=new DivInstrument;
int insCount=(int)song.ins.size();
DivInstrumentType prefType=getPreferInsType(refChan);
DivInstrumentType prefType;
if (refChan<0) {
prefType=fallbackType;
} else {
prefType=getPreferInsType(refChan);
}
switch (prefType) {
case DIV_INS_OPLL:
*ins=song.nullInsOPLL;
@ -2692,8 +2712,10 @@ int DivEngine::addInstrument(int refChan) {
default:
break;
}
if (sysOfChan[refChan]==DIV_SYSTEM_QSOUND) {
*ins=song.nullInsQSound;
if (refChan>=0) {
if (sysOfChan[refChan]==DIV_SYSTEM_QSOUND) {
*ins=song.nullInsQSound;
}
}
ins->name=fmt::sprintf("Instrument %d",insCount);
if (prefType!=DIV_INS_NULL) {

View file

@ -47,8 +47,8 @@
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
#define BUSY_END isBusy.unlock(); softLocked=false;
#define DIV_VERSION "dev122"
#define DIV_ENGINE_VERSION 122
#define DIV_VERSION "dev125"
#define DIV_ENGINE_VERSION 125
// for imports
#define DIV_VERSION_MOD 0xff01
#define DIV_VERSION_FC 0xff02
@ -351,14 +351,14 @@ class DivEngine {
bool midiOutClock;
int midiOutMode;
int softLockCount;
int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed;
int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed, elapsedBars, elapsedBeats;
size_t curSubSongIndex;
double divider;
int cycles;
double clockDrift;
int stepPlay;
int changeOrd, changePos, totalSeconds, totalTicks, totalTicksR, totalCmds, lastCmds, cmdsPerSecond, globalPitch;
unsigned char extValue;
unsigned char extValue, pendingMetroTick;
unsigned char speed1, speed2;
short tempoAccum;
DivStatusView view;
@ -382,9 +382,9 @@ class DivEngine {
std::vector<String> midiOuts;
std::vector<DivCommand> cmdStream;
std::vector<DivInstrumentType> possibleInsTypes;
DivSysDef* sysDefs[256];
DivSystem sysFileMapFur[256];
DivSystem sysFileMapDMF[256];
static DivSysDef* sysDefs[256];
static DivSystem sysFileMapFur[256];
static DivSystem sysFileMapDMF[256];
struct SamplePreview {
double rate;
@ -440,8 +440,6 @@ class DivEngine {
void reset();
void playSub(bool preserveDrift, int goalRow=0);
void convertOldFlags(unsigned int oldFlags, DivConfig& newFlags, DivSystem sys);
bool loadDMF(unsigned char* file, size_t len);
bool loadFur(unsigned char* file, size_t len);
bool loadMod(unsigned char* file, size_t len);
@ -469,7 +467,7 @@ class DivEngine {
bool deinitAudioBackend(bool dueToSwitchMaster=false);
void registerSystems();
void initSongWithDesc(const char* description);
void initSongWithDesc(const char* description, bool inBase64=true);
void exchangeIns(int one, int two);
void swapChannels(int src, int dest);
@ -503,7 +501,7 @@ class DivEngine {
// parse old system setup description
String decodeSysDesc(String desc);
// start fresh
void createNew(const char* description, String sysName);
void createNew(const char* description, String sysName, bool inBase64=true);
// load a file.
bool load(unsigned char* f, size_t length);
// save as .dmf.
@ -532,10 +530,14 @@ class DivEngine {
void notifyWaveChange(int wave);
// get system IDs
DivSystem systemFromFileFur(unsigned char val);
unsigned char systemToFileFur(DivSystem val);
DivSystem systemFromFileDMF(unsigned char val);
unsigned char systemToFileDMF(DivSystem val);
static DivSystem systemFromFileFur(unsigned char val);
static unsigned char systemToFileFur(DivSystem val);
static DivSystem systemFromFileDMF(unsigned char val);
static unsigned char systemToFileDMF(DivSystem val);
// convert old flags
static void convertOldFlags(unsigned int oldFlags, DivConfig& newFlags, DivSystem sys);
// benchmark (returns time in seconds)
double benchmarkPlayback();
@ -709,6 +711,10 @@ class DivEngine {
// get current row
int getRow();
// get beat/bar
int getElapsedBars();
int getElapsedBeats();
// get current subsong
size_t getCurrentSubSong();
@ -753,7 +759,7 @@ class DivEngine {
bool isExporting();
// add instrument
int addInstrument(int refChan=0);
int addInstrument(int refChan=0, DivInstrumentType fallbackType=DIV_INS_STD);
// add instrument from pointer
int addInstrumentPtr(DivInstrument* which);
@ -1058,6 +1064,8 @@ class DivEngine {
lastLoopPos(0),
exportLoopCount(0),
nextSpeed(3),
elapsedBars(0),
elapsedBeats(0),
curSubSongIndex(0),
divider(60),
cycles(0),
@ -1073,6 +1081,7 @@ class DivEngine {
cmdsPerSecond(0),
globalPitch(0),
extValue(0),
pendingMetroTick(0),
speed1(3),
speed2(3),
tempoAccum(0),

View file

@ -2383,11 +2383,16 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
if (isNewSample) {
sample->centerRate=reader.readI();
sample->depth=(DivSampleDepth)reader.readC();
if (ds.version>=123) {
sample->loopMode=(DivSampleLoopMode)reader.readC();
} else {
sample->loopMode=DIV_SAMPLE_LOOP_FORWARD;
reader.readC();
}
// reserved
reader.readC();
reader.readC();
reader.readC();
sample->loopStart=reader.readI();
sample->loopEnd=reader.readI();
@ -2611,6 +2616,21 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
}
}
// ExtCh compat flag
if (ds.version<125) {
for (int i=0; i<ds.systemLen; i++) {
if (ds.system[i]==DIV_SYSTEM_YM2612_EXT ||
ds.system[i]==DIV_SYSTEM_YM2612_FRAC_EXT ||
ds.system[i]==DIV_SYSTEM_YM2610_EXT ||
ds.system[i]==DIV_SYSTEM_YM2610_FULL_EXT ||
ds.system[i]==DIV_SYSTEM_YM2610B_EXT ||
ds.system[i]==DIV_SYSTEM_OPN_EXT ||
ds.system[i]==DIV_SYSTEM_PC98_EXT) {
ds.systemFlags[i].set("noExtMacros",true);
}
}
}
if (active) quitDispatch();
BUSY_BEGIN_SOFT;
saveLock.lock();
@ -2946,7 +2966,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
writeFxCol(fxTyp,fxVal);
break;
case 12: // set vol
data[row][3]=fxVal;
data[row][3]=MIN(0x40,fxVal);
break;
case 13: // break to row (BCD)
writeFxCol(fxTyp,((fxVal>>4)*10)+(fxVal&15));
@ -4624,9 +4644,9 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
w->writeI(sample->rate);
w->writeI(sample->centerRate);
w->writeC(sample->depth);
w->writeC(sample->loopMode);
w->writeC(0); // reserved
w->writeC(0);
w->writeC(0);
w->writeI(sample->loop?sample->loopStart:-1);
w->writeI(sample->loop?sample->loopEnd:-1);

View file

@ -285,7 +285,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
chan[i].freqChanged=true;
}
} else {
if (chan[i].std.arp.had) {
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11);
}
@ -1224,6 +1224,7 @@ void DivPlatformGenesis::setFlags(const DivConfig& flags) {
break;
}
ladder=flags.getBool("ladderEffect",false);
noExtMacros=flags.getBool("noExtMacros",false);
OPN2_SetChipType(ladder?ym3438_mode_ym2612:0);
if (useYMFM) {
if (fm_ymfm!=NULL) delete fm_ymfm;

View file

@ -116,7 +116,7 @@ class DivPlatformGenesis: public DivPlatformOPN {
int softPCMTimer;
bool extMode, softPCM, useYMFM;
bool extMode, softPCM, noExtMacros, useYMFM;
bool ladder;
unsigned char dacVolTable[128];

View file

@ -52,6 +52,15 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
chan[2].state.ams=ins->fm.ams;
chan[2].state.op[ordch]=ins->fm.op[ordch];
}
if (noExtMacros) {
opChan[ch].macroInit(NULL);
} else {
opChan[ch].macroInit(ins);
}
if (!opChan[ch].std.vol.will) {
opChan[ch].outVol=opChan[ch].vol;
}
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
DivInstrumentFM::Operator& op=chan[2].state.op[ordch];
@ -60,7 +69,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
rWrite(baseAddr+0x40,127);
} else {
if (opChan[ch].insChanged) {
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].vol&0x7f,127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127));
}
}
if (opChan[ch].insChanged) {
@ -81,6 +90,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
if (c.value!=DIV_NOTE_NULL) {
opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11);
opChan[ch].portaPause=false;
opChan[ch].note=c.value;
opChan[ch].freqChanged=true;
}
opChan[ch].keyOn=true;
@ -92,14 +102,28 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
opChan[ch].keyOn=false;
opChan[ch].active=false;
break;
case DIV_CMD_NOTE_OFF_ENV:
if (noExtMacros) break;
opChan[ch].keyOff=true;
opChan[ch].keyOn=false;
opChan[ch].active=false;
opChan[ch].std.release();
break;
case DIV_CMD_ENV_RELEASE:
if (noExtMacros) break;
opChan[ch].std.release();
break;
case DIV_CMD_VOLUME: {
opChan[ch].vol=c.value;
if (!opChan[ch].std.vol.has) {
opChan[ch].outVol=c.value;
}
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
DivInstrumentFM::Operator& op=chan[2].state.op[ordch];
if (isOpMuted[ch]) {
rWrite(baseAddr+0x40,127);
} else {
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].vol&0x7f,127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127));
}
break;
}
@ -210,7 +234,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
if (isOpMuted[ch]) {
rWrite(baseAddr+0x40,127);
} else if (KVS(2,c.value)) {
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].vol&0x7f,127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127));
} else {
rWrite(baseAddr+0x40,op.tl);
}
@ -393,8 +417,8 @@ void DivPlatformGenesisExt::muteChannel(int ch, bool mute) {
rWrite(baseAddr+0x40,127);
immWrite(baseAddr+0x40,127);
} else if (KVS(2,ordch)) {
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].vol&0x7f,127));
immWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].vol&0x7f,127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].outVol&0x7f,127));
immWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].outVol&0x7f,127));
} else {
rWrite(baseAddr+0x40,op.tl);
immWrite(baseAddr+0x40,op.tl);
@ -438,6 +462,91 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
}
}
if (extMode && !noExtMacros) for (int i=0; i<4; i++) {
opChan[i].std.next();
if (opChan[i].std.vol.had) {
opChan[i].outVol=VOL_SCALE_LOG_BROKEN(opChan[i].vol,MIN(127,opChan[i].std.vol.val),127);
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[i]];
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[i]];
if (isOpMuted[i]) {
rWrite(baseAddr+ADDR_TL,127);
} else {
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[i].outVol&0x7f,127));
}
}
if (opChan[i].std.arp.had) {
if (!opChan[i].inPorta) {
opChan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(opChan[i].note,opChan[i].std.arp.val),11);
}
opChan[i].freqChanged=true;
}
if (opChan[i].std.pitch.had) {
if (opChan[i].std.pitch.mode) {
opChan[i].pitch2+=opChan[i].std.pitch.val;
CLAMP_VAR(opChan[i].pitch2,-32768,32767);
} else {
opChan[i].pitch2=opChan[i].std.pitch.val;
}
opChan[i].freqChanged=true;
}
// param macros
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[i]];
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[i]];
DivMacroInt::IntOp& m=opChan[i].std.op[orderedOps[i]];
if (m.am.had) {
op.am=m.am.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
if (m.ar.had) {
op.ar=m.ar.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
}
if (m.dr.had) {
op.dr=m.dr.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
if (m.mult.had) {
op.mult=m.mult.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
}
if (m.rr.had) {
op.rr=m.rr.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
if (m.sl.had) {
op.sl=m.sl.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
if (m.tl.had) {
op.tl=127-m.tl.val;
if (isOpMuted[i]) {
rWrite(baseAddr+ADDR_TL,127);
} else {
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[i].outVol&0x7f,127));
}
}
if (m.rs.had) {
op.rs=m.rs.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
}
if (m.dt.had) {
op.dt=m.dt.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
}
if (m.d2r.had) {
op.d2r=m.d2r.val;
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
}
if (m.ssg.had) {
op.ssgEnv=m.ssg.val;
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
}
}
DivPlatformGenesis::tick(sysTick);
bool writeNoteOn=false;
@ -527,7 +636,7 @@ void DivPlatformGenesisExt::forceIns() {
if (isOpMuted[j]) {
rWrite(baseAddr+0x40,127);
} else if (KVS(i,j)) {
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[j].vol&0x7f,127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[j].outVol&0x7f,127));
} else {
rWrite(baseAddr+0x40,op.tl);
}
@ -601,7 +710,9 @@ void DivPlatformGenesisExt::reset() {
for (int i=0; i<4; i++) {
opChan[i]=DivPlatformGenesisExt::OpChannel();
opChan[i].std.setEngine(parent);
opChan[i].vol=127;
opChan[i].outVol=127;
}
// channel 3 mode

View file

@ -25,11 +25,15 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
struct OpChannel {
DivMacroInt std;
unsigned char freqH, freqL;
int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins;
int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins, note;
signed char konCycles;
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, mask;
int vol;
int vol, outVol;
unsigned char pan;
void macroInit(DivInstrument* which) {
std.init(which);
pitch2=0;
}
OpChannel():
freqH(0),
freqL(0),
@ -39,6 +43,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
pitch2(0),
portaPauseFreq(0),
ins(-1),
note(0),
active(false),
insChanged(true),
freqChanged(false),
@ -48,6 +53,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
inPorta(false),
mask(true),
vol(0),
outVol(0),
pan(3) {}
};
OpChannel opChan[4];

View file

@ -587,7 +587,17 @@ bool DivPlatformPCSpeaker::keyOffAffectsArp(int ch) {
}
void DivPlatformPCSpeaker::setFlags(const DivConfig& flags) {
chipClock=COLOR_NTSC/3.0;
switch (flags.getInt("clockSel",0)) {
case 1: // PC-98
chipClock=38400*52;
break;
case 2: // PC-98
chipClock=38400*64;
break;
default: // IBM PC
chipClock=COLOR_NTSC/3.0;
break;
}
rate=chipClock/PCSPKR_DIVIDER;
speakerType=flags.getInt("speakerType",0)&3;
oscBuf->rate=rate;

View file

@ -129,7 +129,7 @@ void DivPlatformSMS::tick(bool sysTick) {
if (chan[i].outVol<0) chan[i].outVol=0;
// old formula
// ((chan[i].vol&15)*MIN(15,chan[i].std.vol.val))>>4;
rWrite(0,0x90|(i<<5)|(isMuted[i]?15:(15-(chan[i].outVol&15))));
chan[i].writeVol=true;
}
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
@ -235,6 +235,12 @@ void DivPlatformSMS::tick(bool sysTick) {
chan[3].freqChanged=false;
updateSNMode=false;
}
for (int i=0; i<4; i++) {
if (chan[i].writeVol) {
rWrite(0,0x90|(i<<5)|(isMuted[i]?15:(15-(chan[i].outVol&15))));
chan[i].writeVol=false;
}
}
}
int DivPlatformSMS::dispatch(DivCommand c) {
@ -249,9 +255,11 @@ int DivPlatformSMS::dispatch(DivCommand c) {
chan[c.chan].actualNote=c.value;
}
chan[c.chan].active=true;
if (!parent->song.brokenOutVol2) {
rWrite(0,0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15))));
}
//if (!parent->song.brokenOutVol2) {
chan[c.chan].writeVol=true;
chan[c.chan].outVol=chan[c.chan].vol;
//rWrite(0,0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15))));
//}
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
@ -276,7 +284,9 @@ int DivPlatformSMS::dispatch(DivCommand c) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
if (chan[c.chan].active) rWrite(0,0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15))));
if (chan[c.chan].active) {
chan[c.chan].writeVol=true;
}
}
break;
case DIV_CMD_GET_VOLUME:
@ -356,7 +366,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
void DivPlatformSMS::muteChannel(int ch, bool mute) {
isMuted[ch]=mute;
if (chan[ch].active) rWrite(0,0x90|ch<<5|(isMuted[ch]?15:(15-(chan[ch].outVol&15))));
if (chan[ch].active) chan[ch].writeVol=true;
}
void DivPlatformSMS::forceIns() {

View file

@ -31,7 +31,7 @@ extern "C" {
class DivPlatformSMS: public DivDispatch {
struct Channel {
int freq, baseFreq, pitch, pitch2, note, actualNote, ins;
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, writeVol;
signed char vol, outVol;
DivMacroInt std;
void macroInit(DivInstrument* which) {
@ -52,6 +52,7 @@ class DivPlatformSMS: public DivDispatch {
keyOn(false),
keyOff(false),
inPorta(false),
writeVol(false),
vol(15),
outVol(15) {}
};

View file

@ -952,6 +952,7 @@ void DivPlatformYM2203::setFlags(const DivConfig& flags) {
ayDiv=16;
break;
}
noExtMacros=flags.getBool("noExtMacros",false);
rate=fm->sample_rate(chipClock);
for (int i=0; i<6; i++) {
oscBuf[i]->rate=rate;

View file

@ -91,7 +91,7 @@ class DivPlatformYM2203: public DivPlatformOPN {
DivPlatformAY8910* ay;
unsigned char sampleBank;
bool extMode;
bool extMode, noExtMacros;
unsigned char prescale;
friend void putDispatchChip(void*,int);

View file

@ -1394,6 +1394,7 @@ void DivPlatformYM2608::setFlags(const DivConfig& flags) {
ayDiv=32;
break;
}
noExtMacros=flags.getBool("noExtMacros",false);
rate=fm->sample_rate(chipClock);
for (int i=0; i<16; i++) {
oscBuf[i]->rate=rate;

View file

@ -106,7 +106,7 @@ class DivPlatformYM2608: public DivPlatformOPN {
unsigned char writeRSSOff, writeRSSOn;
int globalRSSVolume;
bool extMode;
bool extMode, noExtMacros;
unsigned char prescale;
double NOTE_OPNB(int ch, int note);

View file

@ -141,7 +141,7 @@ template<int ChanNum> class DivPlatformYM2610Base: public DivPlatformOPN {
unsigned char sampleBank;
bool extMode;
bool extMode, noExtMacros;
unsigned char writeADPCMAOff, writeADPCMAOn;
int globalADPCMAVolume;
@ -269,6 +269,7 @@ template<int ChanNum> class DivPlatformYM2610Base: public DivPlatformOPN {
chipClock=8000000.0;
break;
}
noExtMacros=flags.getBool("noExtMacros",false);
rate=chipClock/16;
for (int i=0; i<ChanNum; i++) {
oscBuf[i]->rate=rate;

View file

@ -975,6 +975,20 @@ void DivEngine::nextRow() {
printf("| %.2x:%s | \x1b[1;33m%3d%s\x1b[m\n",curOrder,pb1,curRow,pb3);
}
if (curSubSong->hilightA>0) {
if ((curRow%curSubSong->hilightA)==0) {
pendingMetroTick=1;
elapsedBeats++;
}
}
if (curSubSong->hilightB>0) {
if ((curRow%curSubSong->hilightB)==0) {
pendingMetroTick=2;
elapsedBars++;
elapsedBeats=0;
}
}
prevOrder=curOrder;
prevRow=curRow;
@ -1608,16 +1622,6 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
// 2. check whether we gonna tick
if (cycles<=0) {
// we have to tick
if (!freelance && stepPlay!=-1 && subticks==1) {
unsigned int realPos=size-(runLeftG>>MASTER_CLOCK_PREC);
if (realPos>=size) realPos=size-1;
if (curSubSong->hilightA>0) {
if ((curRow%curSubSong->hilightA)==0 && ticks==1) metroTick[realPos]=1;
}
if (curSubSong->hilightB>0) {
if ((curRow%curSubSong->hilightB)==0 && ticks==1) metroTick[realPos]=2;
}
}
if (nextTick()) {
lastLoopPos=size-(runLeftG>>MASTER_CLOCK_PREC);
logD("last loop pos: %d for a size of %d and runLeftG of %d",lastLoopPos,size,runLeftG);
@ -1634,6 +1638,12 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
}
}
}
if (pendingMetroTick) {
unsigned int realPos=size-(runLeftG>>MASTER_CLOCK_PREC);
if (realPos>=size) realPos=size-1;
metroTick[realPos]=pendingMetroTick;
pendingMetroTick=0;
}
} else {
// 3. tick the clock and fill buffers as needed
if (cycles<runLeftG) {

View file

@ -23,6 +23,10 @@
#include "song.h"
#include "../ta-log.h"
DivSysDef* DivEngine::sysDefs[256];
DivSystem DivEngine::sysFileMapFur[256];
DivSystem DivEngine::sysFileMapDMF[256];
DivSystem DivEngine::systemFromFileFur(unsigned char val) {
return sysFileMapFur[val];
}

View file

@ -94,10 +94,12 @@ SafeWriter* DivEngine::saveZSM(unsigned int zsmrate, bool loop) {
if (VERA >= 0) disCont[VERA].dispatch->toggleRegisterDump(true);
if (YM >= 0) {
disCont[YM].dispatch->toggleRegisterDump(true);
zsm.writeYM(0x18,0); // initialize the LFO freq to 0
// note - I think there's a bug where Furnace writes AMD/PMD=max
// that shouldn't be there, requiring this initialization that shouldn't
// be there for ZSM.
// emit LFO initialization commands
zsm.writeYM(0x18,0); // freq = 0
zsm.writeYM(0x19,0x7F); // AMD = 7F
zsm.writeYM(0x19,0xFF); // PMD = 7F
// TODO: incorporate the Furnace meta-command for init data and filter
// out writes to otherwise-unused channels.
}
while (!done) {