Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt
This commit is contained in:
commit
46880634b4
50 changed files with 2492 additions and 1960 deletions
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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) {}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue