Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt
This commit is contained in:
commit
03e0c8d8ee
30 changed files with 673 additions and 142 deletions
|
|
@ -24,6 +24,7 @@
|
|||
#define DIV_MAX_CHIPS 32
|
||||
#define DIV_MAX_CHANS 128
|
||||
#define DIV_MAX_PATTERNS 256
|
||||
#define DIV_MAX_CHIP_DEFS 256
|
||||
|
||||
// in-pattern
|
||||
#define DIV_MAX_ROWS 256
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
|
|||
case 0x08:
|
||||
return "08xy: Set panning (x: left; y: right)";
|
||||
case 0x09:
|
||||
return "09xx: Set speed 1";
|
||||
return "09xx: Set groove pattern (speed 1 if no grooves exist)";
|
||||
case 0x0a:
|
||||
return "0Axy: Volume slide (0y: down; x0: up)";
|
||||
case 0x0b:
|
||||
|
|
@ -70,7 +70,7 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
|
|||
case 0x0d:
|
||||
return "0Dxx: Jump to next pattern";
|
||||
case 0x0f:
|
||||
return "0Fxx: Set speed 2";
|
||||
return "0Fxx: Set speed (speed 2 if no grooves exist)";
|
||||
case 0x80:
|
||||
return "80xx: Set panning (00: left; 80: center; FF: right)";
|
||||
case 0x81:
|
||||
|
|
@ -1959,14 +1959,12 @@ String DivEngine::getPlaybackDebugInfo() {
|
|||
"cmdsPerSecond: %d\n"
|
||||
"globalPitch: %d\n"
|
||||
"extValue: %d\n"
|
||||
"speed1: %d\n"
|
||||
"speed2: %d\n"
|
||||
"tempoAccum: %d\n"
|
||||
"totalProcessed: %d\n"
|
||||
"bufferPos: %d\n",
|
||||
curOrder,prevOrder,curRow,prevRow,ticks,subticks,totalLoops,lastLoopPos,nextSpeed,divider,cycles,clockDrift,
|
||||
changeOrd,changePos,totalSeconds,totalTicks,totalTicksR,totalCmds,lastCmds,cmdsPerSecond,globalPitch,
|
||||
(int)extValue,(int)speed1,(int)speed2,(int)tempoAccum,(int)totalProcessed,(int)bufferPos
|
||||
(int)extValue,(int)tempoAccum,(int)totalProcessed,(int)bufferPos
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -2091,7 +2089,8 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) {
|
|||
lastLoopPos=-1;
|
||||
}
|
||||
endOfSong=false;
|
||||
speedAB=false;
|
||||
// whaaaaa?
|
||||
curSpeed=0;
|
||||
playing=true;
|
||||
skipping=true;
|
||||
memset(walked,0,8192);
|
||||
|
|
@ -2439,15 +2438,14 @@ void DivEngine::reset() {
|
|||
}
|
||||
extValue=0;
|
||||
extValuePresent=0;
|
||||
speed1=curSubSong->speed1;
|
||||
speed2=curSubSong->speed2;
|
||||
speeds=curSubSong->speeds;
|
||||
firstTick=false;
|
||||
shallStop=false;
|
||||
shallStopSched=false;
|
||||
pendingMetroTick=0;
|
||||
elapsedBars=0;
|
||||
elapsedBeats=0;
|
||||
nextSpeed=speed1;
|
||||
nextSpeed=speeds.val[0];
|
||||
divider=60;
|
||||
if (curSubSong->customTempo) {
|
||||
divider=curSubSong->hz;
|
||||
|
|
@ -2649,12 +2647,8 @@ size_t DivEngine::getCurrentSubSong() {
|
|||
return curSubSongIndex;
|
||||
}
|
||||
|
||||
unsigned char DivEngine::getSpeed1() {
|
||||
return speed1;
|
||||
}
|
||||
|
||||
unsigned char DivEngine::getSpeed2() {
|
||||
return speed2;
|
||||
const DivGroovePattern& DivEngine::getSpeeds() {
|
||||
return speeds;
|
||||
}
|
||||
|
||||
float DivEngine::getHz() {
|
||||
|
|
@ -4236,7 +4230,7 @@ void DivEngine::quitDispatch() {
|
|||
clockDrift=0;
|
||||
chans=0;
|
||||
playing=false;
|
||||
speedAB=false;
|
||||
curSpeed=0;
|
||||
endOfSong=false;
|
||||
ticks=0;
|
||||
tempoAccum=0;
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@
|
|||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||
|
||||
#define DIV_VERSION "dev138"
|
||||
#define DIV_ENGINE_VERSION 138
|
||||
#define DIV_VERSION "dev139"
|
||||
#define DIV_ENGINE_VERSION 139
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
#define DIV_VERSION_FC 0xff02
|
||||
|
|
@ -337,7 +337,6 @@ class DivEngine {
|
|||
bool playing;
|
||||
bool freelance;
|
||||
bool shallStop, shallStopSched;
|
||||
bool speedAB;
|
||||
bool endOfSong;
|
||||
bool consoleMode;
|
||||
bool extValuePresent;
|
||||
|
|
@ -359,7 +358,7 @@ class DivEngine {
|
|||
bool midiOutClock;
|
||||
int midiOutMode;
|
||||
int softLockCount;
|
||||
int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed, elapsedBars, elapsedBeats;
|
||||
int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed, elapsedBars, elapsedBeats, curSpeed;
|
||||
size_t curSubSongIndex;
|
||||
size_t bufferPos;
|
||||
double divider;
|
||||
|
|
@ -368,7 +367,7 @@ class DivEngine {
|
|||
int stepPlay;
|
||||
int changeOrd, changePos, totalSeconds, totalTicks, totalTicksR, totalCmds, lastCmds, cmdsPerSecond, globalPitch;
|
||||
unsigned char extValue, pendingMetroTick;
|
||||
unsigned char speed1, speed2;
|
||||
DivGroovePattern speeds;
|
||||
short tempoAccum;
|
||||
DivStatusView view;
|
||||
DivHaltPositions haltOn;
|
||||
|
|
@ -391,9 +390,9 @@ class DivEngine {
|
|||
std::vector<String> midiOuts;
|
||||
std::vector<DivCommand> cmdStream;
|
||||
std::vector<DivInstrumentType> possibleInsTypes;
|
||||
static DivSysDef* sysDefs[256];
|
||||
static DivSystem sysFileMapFur[256];
|
||||
static DivSystem sysFileMapDMF[256];
|
||||
static DivSysDef* sysDefs[DIV_MAX_CHIP_DEFS];
|
||||
static DivSystem sysFileMapFur[DIV_MAX_CHIP_DEFS];
|
||||
static DivSystem sysFileMapDMF[DIV_MAX_CHIP_DEFS];
|
||||
|
||||
struct SamplePreview {
|
||||
double rate;
|
||||
|
|
@ -730,11 +729,8 @@ class DivEngine {
|
|||
// get current subsong
|
||||
size_t getCurrentSubSong();
|
||||
|
||||
// get speed 1
|
||||
unsigned char getSpeed1();
|
||||
|
||||
// get speed 2
|
||||
unsigned char getSpeed2();
|
||||
// get speeds
|
||||
const DivGroovePattern& getSpeeds();
|
||||
|
||||
// get Hz
|
||||
float getHz();
|
||||
|
|
@ -1065,7 +1061,6 @@ class DivEngine {
|
|||
freelance(false),
|
||||
shallStop(false),
|
||||
shallStopSched(false),
|
||||
speedAB(false),
|
||||
endOfSong(false),
|
||||
consoleMode(false),
|
||||
extValuePresent(false),
|
||||
|
|
@ -1099,6 +1094,7 @@ class DivEngine {
|
|||
nextSpeed(3),
|
||||
elapsedBars(0),
|
||||
elapsedBeats(0),
|
||||
curSpeed(0),
|
||||
curSubSongIndex(0),
|
||||
bufferPos(0),
|
||||
divider(60),
|
||||
|
|
@ -1116,8 +1112,6 @@ class DivEngine {
|
|||
globalPitch(0),
|
||||
extValue(0),
|
||||
pendingMetroTick(0),
|
||||
speed1(3),
|
||||
speed2(3),
|
||||
tempoAccum(0),
|
||||
view(DIV_STATUS_NOTHING),
|
||||
haltOn(DIV_HALT_NONE),
|
||||
|
|
@ -1162,11 +1156,11 @@ class DivEngine {
|
|||
memset(tremTable,0,128*sizeof(short));
|
||||
memset(reversePitchTable,0,4096*sizeof(int));
|
||||
memset(pitchTable,0,4096*sizeof(int));
|
||||
memset(sysDefs,0,256*sizeof(void*));
|
||||
memset(sysDefs,0,DIV_MAX_CHIP_DEFS*sizeof(void*));
|
||||
memset(walked,0,8192);
|
||||
memset(oscBuf,0,DIV_MAX_OUTPUTS*(sizeof(float*)));
|
||||
|
||||
for (int i=0; i<256; i++) {
|
||||
for (int i=0; i<DIV_MAX_CHIP_DEFS; i++) {
|
||||
sysFileMapFur[i]=DIV_SYSTEM_NULL;
|
||||
sysFileMapDMF[i]=DIV_SYSTEM_NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
}
|
||||
ds.version=(unsigned char)reader.readC();
|
||||
logI("module version %d (0x%.2x)",ds.version,ds.version);
|
||||
if (ds.version>0x1a) {
|
||||
if (ds.version>0x1b) {
|
||||
logE("this version is not supported by Furnace yet!");
|
||||
lastError="this version is not supported by Furnace yet";
|
||||
delete[] file;
|
||||
|
|
@ -219,14 +219,15 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
}
|
||||
|
||||
ds.subsong[0]->timeBase=reader.readC();
|
||||
ds.subsong[0]->speed1=reader.readC();
|
||||
ds.subsong[0]->speeds.len=2;
|
||||
ds.subsong[0]->speeds.val[0]=reader.readC();
|
||||
if (ds.version>0x07) {
|
||||
ds.subsong[0]->speed2=reader.readC();
|
||||
ds.subsong[0]->speeds.val[1]=reader.readC();
|
||||
ds.subsong[0]->pal=reader.readC();
|
||||
ds.subsong[0]->hz=(ds.subsong[0]->pal)?60:50;
|
||||
ds.subsong[0]->customTempo=reader.readC();
|
||||
} else {
|
||||
ds.subsong[0]->speed2=ds.subsong[0]->speed1;
|
||||
ds.subsong[0]->speeds.len=1;
|
||||
}
|
||||
if (ds.version>0x0a) {
|
||||
String hz=reader.readString(3);
|
||||
|
|
@ -827,6 +828,8 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
for (int i=0; i<ds.sampleLen; i++) {
|
||||
DivSample* sample=new DivSample;
|
||||
int length=reader.readI();
|
||||
int cutStart=0;
|
||||
int cutEnd=length;
|
||||
int pitch=5;
|
||||
int vol=50;
|
||||
short* data;
|
||||
|
|
@ -866,6 +869,29 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
sample->depth=DIV_SAMPLE_DEPTH_YMZ_ADPCM;
|
||||
}
|
||||
}
|
||||
if (ds.version>=0x1a) {
|
||||
// what the hell man...
|
||||
cutStart=reader.readI();
|
||||
cutEnd=reader.readI();
|
||||
if (cutStart<0 || cutStart>length) {
|
||||
logE("cutStart is out of range! (%d)",cutStart);
|
||||
lastError="file is corrupt or unreadable at samples";
|
||||
delete[] file;
|
||||
return false;
|
||||
}
|
||||
if (cutEnd<0 || cutEnd>length) {
|
||||
logE("cutEnd is out of range! (%d)",cutEnd);
|
||||
lastError="file is corrupt or unreadable at samples";
|
||||
delete[] file;
|
||||
return false;
|
||||
}
|
||||
if (cutEnd<cutStart) {
|
||||
logE("cutEnd %d is before cutStart %d. what's going on?",cutEnd,cutStart);
|
||||
lastError="file is corrupt or unreadable at samples";
|
||||
delete[] file;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (length>0) {
|
||||
if (ds.version>0x08) {
|
||||
if (ds.version<0x0b) {
|
||||
|
|
@ -876,6 +902,19 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
data=new short[length];
|
||||
reader.read(data,length*2);
|
||||
}
|
||||
|
||||
if (ds.version>0x1a) {
|
||||
if (cutStart!=0 || cutEnd!=length) {
|
||||
// cut data
|
||||
short* newData=new short[cutEnd-cutStart];
|
||||
memcpy(newData,&data[cutStart],(cutEnd-cutStart)*sizeof(short));
|
||||
delete[] data;
|
||||
data=newData;
|
||||
length=cutEnd-cutStart;
|
||||
cutStart=0;
|
||||
cutEnd=length;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
// convert to big-endian
|
||||
|
|
@ -1742,8 +1781,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
reader.readI();
|
||||
|
||||
subSong->timeBase=reader.readC();
|
||||
subSong->speed1=reader.readC();
|
||||
subSong->speed2=reader.readC();
|
||||
subSong->speeds.len=2;
|
||||
subSong->speeds.val[0]=reader.readC();
|
||||
subSong->speeds.val[1]=reader.readC();
|
||||
subSong->arpLen=reader.readC();
|
||||
subSong->hz=reader.readF();
|
||||
subSong->pal=(subSong->hz>=53);
|
||||
|
|
@ -2231,6 +2271,25 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
}
|
||||
}
|
||||
|
||||
if (ds.version>=139) {
|
||||
subSong->speeds.len=reader.readC();
|
||||
for (int i=0; i<16; i++) {
|
||||
subSong->speeds.val[i]=reader.readC();
|
||||
}
|
||||
|
||||
// grooves
|
||||
unsigned char grooveCount=reader.readC();
|
||||
for (int i=0; i<grooveCount; i++) {
|
||||
DivGroovePattern gp;
|
||||
gp.len=reader.readC();
|
||||
for (int j=0; j<16; j++) {
|
||||
gp.val[j]=reader.readC();
|
||||
}
|
||||
|
||||
ds.grooves.push_back(gp);
|
||||
}
|
||||
}
|
||||
|
||||
// read system flags
|
||||
if (ds.version>=119) {
|
||||
logD("reading chip flags...");
|
||||
|
|
@ -2289,8 +2348,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
|
||||
subSong=ds.subsong[i+1];
|
||||
subSong->timeBase=reader.readC();
|
||||
subSong->speed1=reader.readC();
|
||||
subSong->speed2=reader.readC();
|
||||
subSong->speeds.len=2;
|
||||
subSong->speeds.val[0]=reader.readC();
|
||||
subSong->speeds.val[1]=reader.readC();
|
||||
subSong->arpLen=reader.readC();
|
||||
subSong->hz=reader.readF();
|
||||
subSong->pal=(subSong->hz>=53);
|
||||
|
|
@ -2338,6 +2398,13 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
for (int i=0; i<tchans; i++) {
|
||||
subSong->chanShortName[i]=reader.readString();
|
||||
}
|
||||
|
||||
if (ds.version>=139) {
|
||||
subSong->speeds.len=reader.readC();
|
||||
for (int i=0; i<16; i++) {
|
||||
subSong->speeds.val[i]=reader.readC();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2956,7 +3023,6 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
if (fxVal>0x20 && ds.name!="klisje paa klisje") {
|
||||
writeFxCol(0xf0,fxVal);
|
||||
} else {
|
||||
writeFxCol(0x09,fxVal);
|
||||
writeFxCol(0x0f,fxVal);
|
||||
}
|
||||
break;
|
||||
|
|
@ -3435,8 +3501,8 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
ds.subsong[0]->pal=true;
|
||||
ds.subsong[0]->customTempo=true;
|
||||
ds.subsong[0]->pat[3].effectCols=3;
|
||||
ds.subsong[0]->speed1=3;
|
||||
ds.subsong[0]->speed2=3;
|
||||
ds.subsong[0]->speeds.val[0]=3;
|
||||
ds.subsong[0]->speeds.len=1;
|
||||
|
||||
int lastIns[4];
|
||||
int lastNote[4];
|
||||
|
|
@ -3453,10 +3519,8 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
ds.subsong[0]->orders.ord[j][i]=i;
|
||||
DivPattern* p=ds.subsong[0]->pat[j].getPattern(i,true);
|
||||
if (j==3 && seq[i].speed) {
|
||||
p->data[0][6]=0x09;
|
||||
p->data[0][6]=0x0f;
|
||||
p->data[0][7]=seq[i].speed;
|
||||
p->data[0][8]=0x0f;
|
||||
p->data[0][9]=seq[i].speed;
|
||||
}
|
||||
|
||||
bool ignoreNext=false;
|
||||
|
|
@ -4343,8 +4407,9 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
w->writeI(0);
|
||||
|
||||
w->writeC(subSong->timeBase);
|
||||
w->writeC(subSong->speed1);
|
||||
w->writeC(subSong->speed2);
|
||||
// these are for compatibility
|
||||
w->writeC(subSong->speeds.val[0]);
|
||||
w->writeC((subSong->speeds.len>=2)?subSong->speeds.val[1]:subSong->speeds.val[0]);
|
||||
w->writeC(subSong->arpLen);
|
||||
w->writeF(subSong->hz);
|
||||
w->writeS(subSong->patLen);
|
||||
|
|
@ -4531,6 +4596,21 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
w->writeC(0);
|
||||
}
|
||||
|
||||
// speeds of first song
|
||||
w->writeC(subSong->speeds.len);
|
||||
for (int i=0; i<16; i++) {
|
||||
w->writeC(subSong->speeds.val[i]);
|
||||
}
|
||||
|
||||
// groove list
|
||||
w->writeC((unsigned char)song.grooves.size());
|
||||
for (const DivGroovePattern& i: song.grooves) {
|
||||
w->writeC(i.len);
|
||||
for (int j=0; j<16; j++) {
|
||||
w->writeC(i.val[j]);
|
||||
}
|
||||
}
|
||||
|
||||
blockEndSeek=w->tell();
|
||||
w->seek(blockStartSeek,SEEK_SET);
|
||||
w->writeI(blockEndSeek-blockStartSeek-4);
|
||||
|
|
@ -4545,8 +4625,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
w->writeI(0);
|
||||
|
||||
w->writeC(subSong->timeBase);
|
||||
w->writeC(subSong->speed1);
|
||||
w->writeC(subSong->speed2);
|
||||
w->writeC(subSong->speeds.val[0]);
|
||||
w->writeC((subSong->speeds.len>=2)?subSong->speeds.val[1]:subSong->speeds.val[0]);
|
||||
w->writeC(subSong->arpLen);
|
||||
w->writeF(subSong->hz);
|
||||
w->writeS(subSong->patLen);
|
||||
|
|
@ -4585,6 +4665,12 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
w->writeString(subSong->chanShortName[i],false);
|
||||
}
|
||||
|
||||
// speeds
|
||||
w->writeC(subSong->speeds.len);
|
||||
for (int i=0; i<16; i++) {
|
||||
w->writeC(subSong->speeds.val[i]);
|
||||
}
|
||||
|
||||
blockEndSeek=w->tell();
|
||||
w->seek(blockStartSeek,SEEK_SET);
|
||||
w->writeI(blockEndSeek-blockStartSeek-4);
|
||||
|
|
@ -4840,8 +4926,8 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
w->writeC(curSubSong->hilightB);
|
||||
|
||||
w->writeC(curSubSong->timeBase);
|
||||
w->writeC(curSubSong->speed1);
|
||||
w->writeC(curSubSong->speed2);
|
||||
w->writeC(curSubSong->speeds.val[0]);
|
||||
w->writeC((curSubSong->speeds.len>=2)?curSubSong->speeds.val[1]:curSubSong->speeds.val[0]);
|
||||
w->writeC(curSubSong->pal);
|
||||
w->writeC(curSubSong->customTempo);
|
||||
char customHz[4];
|
||||
|
|
@ -4865,6 +4951,14 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
addWarning("only the currently selected subsong will be saved");
|
||||
}
|
||||
|
||||
if (!song.grooves.empty()) {
|
||||
addWarning("grooves will not be saved");
|
||||
}
|
||||
|
||||
if (curSubSong->speeds.len>2) {
|
||||
addWarning("only the first two speeds will be effective");
|
||||
}
|
||||
|
||||
if (curSubSong->virtualTempoD!=curSubSong->virtualTempoN) {
|
||||
addWarning(".dmf format does not support virtual tempo");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,6 +154,8 @@ class DivPlatformOPN: public DivPlatformFMBase {
|
|||
unsigned int ayDiv;
|
||||
unsigned char csmChan;
|
||||
unsigned char lfoValue;
|
||||
unsigned short ssgVol;
|
||||
unsigned short fmVol;
|
||||
bool extSys, useCombo, fbAllOps;
|
||||
|
||||
DivConfig ayFlags;
|
||||
|
|
@ -172,6 +174,8 @@ class DivPlatformOPN: public DivPlatformFMBase {
|
|||
ayDiv(a),
|
||||
csmChan(cc),
|
||||
lfoValue(0),
|
||||
ssgVol(128),
|
||||
fmVol(256),
|
||||
extSys(isExtSys),
|
||||
useCombo(false),
|
||||
fbAllOps(false) {}
|
||||
|
|
|
|||
|
|
@ -30,17 +30,26 @@
|
|||
|
||||
void DivYM2612Interface::ymfm_set_timer(uint32_t tnum, int32_t duration_in_clocks) {
|
||||
if (tnum==1) {
|
||||
countB=duration_in_clocks;
|
||||
setB=duration_in_clocks;
|
||||
} else if (tnum==0) {
|
||||
countA=duration_in_clocks;
|
||||
setA=duration_in_clocks;
|
||||
}
|
||||
//logV("ymfm_set_timer(%d,%d)",tnum,duration_in_clocks);
|
||||
}
|
||||
|
||||
void DivYM2612Interface::clock() {
|
||||
if (countA>=0) {
|
||||
if (setA>=0) {
|
||||
countA-=144;
|
||||
if (countA<0) m_engine->engine_timer_expired(0);
|
||||
if (countA<0) {
|
||||
m_engine->engine_timer_expired(0);
|
||||
countA+=setA;
|
||||
}
|
||||
}
|
||||
if (setB>=0) {
|
||||
countB-=144;
|
||||
if (countB<0) {
|
||||
m_engine->engine_timer_expired(1);
|
||||
countB+=setB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
|
||||
class DivYM2612Interface: public ymfm::ymfm_interface {
|
||||
int setA, setB;
|
||||
int countA, countB;
|
||||
|
||||
public:
|
||||
|
|
@ -32,8 +33,8 @@ class DivYM2612Interface: public ymfm::ymfm_interface {
|
|||
void ymfm_set_timer(uint32_t tnum, int32_t duration_in_clocks);
|
||||
DivYM2612Interface():
|
||||
ymfm::ymfm_interface(),
|
||||
countA(-1),
|
||||
countB(-1) {}
|
||||
countA(0),
|
||||
countB(0) {}
|
||||
};
|
||||
|
||||
class DivPlatformGenesis: public DivPlatformOPN {
|
||||
|
|
|
|||
|
|
@ -589,6 +589,7 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
|
|||
if (opChan[i].freq>0x3fff) opChan[i].freq=0x3fff;
|
||||
immWrite(opChanOffsH[i],opChan[i].freq>>8);
|
||||
immWrite(opChanOffsL[i],opChan[i].freq&0xff);
|
||||
opChan[i].freqChanged=false;
|
||||
}
|
||||
writeMask|=(unsigned char)(opChan[i].mask && opChan[i].active)<<(4+i);
|
||||
if (opChan[i].keyOn) {
|
||||
|
|
|
|||
|
|
@ -431,6 +431,12 @@ bool fm_operator<RegisterType>::prepare()
|
|||
|
||||
// clock the key state
|
||||
clock_keystate(uint32_t(m_keyon_live != 0));
|
||||
if (m_keyon_live & (1<<KEYON_CSM)) {
|
||||
if (!(m_keyon_live & (1<<KEYON_NORMAL))) {
|
||||
clock_keystate(0);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
m_keyon_live &= ~(1 << KEYON_CSM);
|
||||
|
||||
// we're active until we're quiet after the release
|
||||
|
|
|
|||
|
|
@ -135,22 +135,27 @@ void DivPlatformTIA::tick(bool sysTick) {
|
|||
int bf=chan[i].baseFreq;
|
||||
if (!parent->song.oldArpStrategy) {
|
||||
if (!chan[i].fixedArp) {
|
||||
bf+=chan[i].arpOff;
|
||||
bf+=chan[i].arpOff<<8;
|
||||
}
|
||||
}
|
||||
chan[i].freq=dealWithFreq(chan[i].shape,bf,chan[i].pitch+chan[i].pitch2);
|
||||
if ((chan[i].shape==4 || chan[i].shape==5) && !(chan[i].baseFreq&0x80000000 && ((chan[i].baseFreq&0x7fffffff)<32))) {
|
||||
if (bf<39*256) {
|
||||
rWrite(0x15+i,6);
|
||||
chan[i].freq=dealWithFreq(6,bf,chan[i].pitch+chan[i].pitch2);
|
||||
} else if (bf<59*256) {
|
||||
rWrite(0x15+i,12);
|
||||
chan[i].freq=dealWithFreq(12,bf,chan[i].pitch+chan[i].pitch2);
|
||||
} else {
|
||||
rWrite(0x15+i,chan[i].shape);
|
||||
if (chan[i].fixedArp) {
|
||||
chan[i].freq=chan[i].baseNoteOverride&31;
|
||||
} else {
|
||||
chan[i].freq=dealWithFreq(chan[i].shape,bf,chan[i].pitch+chan[i].pitch2);
|
||||
if ((chan[i].shape==4 || chan[i].shape==5) && !(chan[i].baseFreq&0x80000000 && ((chan[i].baseFreq&0x7fffffff)<32))) {
|
||||
if (bf<39*256) {
|
||||
rWrite(0x15+i,6);
|
||||
chan[i].freq=dealWithFreq(6,bf,chan[i].pitch+chan[i].pitch2);
|
||||
} else if (bf<59*256) {
|
||||
rWrite(0x15+i,12);
|
||||
chan[i].freq=dealWithFreq(12,bf,chan[i].pitch+chan[i].pitch2);
|
||||
} else {
|
||||
rWrite(0x15+i,chan[i].shape);
|
||||
}
|
||||
}
|
||||
if (chan[i].freq>31) chan[i].freq=31;
|
||||
}
|
||||
if (chan[i].freq>31) chan[i].freq=31;
|
||||
|
||||
if (chan[i].keyOff) {
|
||||
rWrite(0x19+i,0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -210,11 +210,12 @@ void DivPlatformYM2203::acquire_combo(short** buf, size_t len) {
|
|||
);
|
||||
|
||||
os&=~3;
|
||||
os=(os*fmVol)>>8;
|
||||
|
||||
// ymfm part
|
||||
fm->generate(&fmout);
|
||||
|
||||
os+=((fmout.data[1]+fmout.data[2]+fmout.data[3])>>1);
|
||||
os+=((fmout.data[1]+fmout.data[2]+fmout.data[3])*ssgVol)>>8;
|
||||
if (os<-32768) os=-32768;
|
||||
if (os>32767) os=32767;
|
||||
|
||||
|
|
@ -255,7 +256,7 @@ void DivPlatformYM2203::acquire_ymfm(short** buf, size_t len) {
|
|||
|
||||
fm->generate(&fmout);
|
||||
|
||||
os=fmout.data[0]+((fmout.data[1]+fmout.data[2]+fmout.data[3])>>1);
|
||||
os=((fmout.data[0]*fmVol)>>8)+(((fmout.data[1]+fmout.data[2]+fmout.data[3])*ssgVol)>>8);
|
||||
if (os<-32768) os=-32768;
|
||||
if (os>32767) os=32767;
|
||||
|
||||
|
|
@ -1074,6 +1075,8 @@ void DivPlatformYM2203::setFlags(const DivConfig& flags) {
|
|||
CHECK_CUSTOM_CLOCK;
|
||||
noExtMacros=flags.getBool("noExtMacros",false);
|
||||
fbAllOps=flags.getBool("fbAllOps",false);
|
||||
ssgVol=flags.getInt("ssgVol",128);
|
||||
fmVol=flags.getInt("fmVol",256);
|
||||
rate=fm->sample_rate(chipClock);
|
||||
for (int i=0; i<6; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
|
|
|
|||
|
|
@ -374,15 +374,17 @@ void DivPlatformYM2608::acquire_combo(short** buf, size_t len) {
|
|||
|
||||
os[0]>>=1;
|
||||
os[1]>>=1;
|
||||
os[0]=(os[0]*fmVol)>>8;
|
||||
os[1]=(os[1]*fmVol)>>8;
|
||||
|
||||
// ymfm part
|
||||
fm->generate(&fmout);
|
||||
|
||||
os[0]+=fmout.data[0]+(fmout.data[2]>>1);
|
||||
os[0]+=((fmout.data[0]*fmVol)>>8)+((fmout.data[2]*ssgVol)>>8);
|
||||
if (os[0]<-32768) os[0]=-32768;
|
||||
if (os[0]>32767) os[0]=32767;
|
||||
|
||||
os[1]+=fmout.data[1]+(fmout.data[2]>>1);
|
||||
os[1]+=((fmout.data[1]*fmVol)>>8)+((fmout.data[2]*ssgVol)>>8);
|
||||
if (os[1]<-32768) os[1]=-32768;
|
||||
if (os[1]>32767) os[1]=32767;
|
||||
|
||||
|
|
@ -439,11 +441,11 @@ void DivPlatformYM2608::acquire_ymfm(short** buf, size_t len) {
|
|||
|
||||
fm->generate(&fmout);
|
||||
|
||||
os[0]=fmout.data[0]+(fmout.data[2]>>1);
|
||||
os[0]=((fmout.data[0]*fmVol)>>8)+((fmout.data[2]*ssgVol)>>8);
|
||||
if (os[0]<-32768) os[0]=-32768;
|
||||
if (os[0]>32767) os[0]=32767;
|
||||
|
||||
os[1]=fmout.data[1]+(fmout.data[2]>>1);
|
||||
os[1]=((fmout.data[1]*fmVol)>>8)+((fmout.data[2]*ssgVol)>>8);
|
||||
if (os[1]<-32768) os[1]=-32768;
|
||||
if (os[1]>32767) os[1]=32767;
|
||||
|
||||
|
|
@ -1603,6 +1605,8 @@ void DivPlatformYM2608::setFlags(const DivConfig& flags) {
|
|||
CHECK_CUSTOM_CLOCK;
|
||||
noExtMacros=flags.getBool("noExtMacros",false);
|
||||
fbAllOps=flags.getBool("fbAllOps",false);
|
||||
ssgVol=flags.getInt("ssgVol",128);
|
||||
fmVol=flags.getInt("fmVol",256);
|
||||
rate=fm->sample_rate(chipClock);
|
||||
for (int i=0; i<16; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
|
|
|
|||
|
|
@ -305,15 +305,17 @@ void DivPlatformYM2610::acquire_combo(short** buf, size_t len) {
|
|||
|
||||
os[0]>>=1;
|
||||
os[1]>>=1;
|
||||
os[0]=(os[0]*fmVol)>>8;
|
||||
os[1]=(os[1]*fmVol)>>8;
|
||||
|
||||
// ymfm part
|
||||
fm->generate(&fmout);
|
||||
|
||||
os[0]+=fmout.data[0]+(fmout.data[2]>>1);
|
||||
os[0]+=((fmout.data[0]*fmVol)>>8)+((fmout.data[2]*ssgVol)>>8);
|
||||
if (os[0]<-32768) os[0]=-32768;
|
||||
if (os[0]>32767) os[0]=32767;
|
||||
|
||||
os[1]+=fmout.data[1]+(fmout.data[2]>>1);
|
||||
os[1]+=((fmout.data[1]*fmVol)>>8)+((fmout.data[2]*ssgVol)>>8);
|
||||
if (os[1]<-32768) os[1]=-32768;
|
||||
if (os[1]>32767) os[1]=32767;
|
||||
|
||||
|
|
@ -372,11 +374,11 @@ void DivPlatformYM2610::acquire_ymfm(short** buf, size_t len) {
|
|||
|
||||
fm->generate(&fmout);
|
||||
|
||||
os[0]=fmout.data[0]+(fmout.data[2]>>1);
|
||||
os[0]+=((fmout.data[0]*fmVol)>>8)+((fmout.data[2]*ssgVol)>>8);
|
||||
if (os[0]<-32768) os[0]=-32768;
|
||||
if (os[0]>32767) os[0]=32767;
|
||||
|
||||
os[1]=fmout.data[1]+(fmout.data[2]>>1);
|
||||
os[1]+=((fmout.data[1]*fmVol)>>8)+((fmout.data[2]*ssgVol)>>8);
|
||||
if (os[1]<-32768) os[1]=-32768;
|
||||
if (os[1]>32767) os[1]=32767;
|
||||
|
||||
|
|
|
|||
|
|
@ -373,15 +373,17 @@ void DivPlatformYM2610B::acquire_combo(short** buf, size_t len) {
|
|||
|
||||
os[0]>>=1;
|
||||
os[1]>>=1;
|
||||
os[0]=(os[0]*fmVol)>>8;
|
||||
os[1]=(os[1]*fmVol)>>8;
|
||||
|
||||
// ymfm part
|
||||
fm->generate(&fmout);
|
||||
|
||||
os[0]+=fmout.data[0]+(fmout.data[2]>>1);
|
||||
os[0]+=((fmout.data[0]*fmVol)>>8)+((fmout.data[2]*ssgVol)>>8);
|
||||
if (os[0]<-32768) os[0]=-32768;
|
||||
if (os[0]>32767) os[0]=32767;
|
||||
|
||||
os[1]+=fmout.data[1]+(fmout.data[2]>>1);
|
||||
os[1]+=((fmout.data[1]*fmVol)>>8)+((fmout.data[2]*ssgVol)>>8);
|
||||
if (os[1]<-32768) os[1]=-32768;
|
||||
if (os[1]>32767) os[1]=32767;
|
||||
|
||||
|
|
@ -438,11 +440,11 @@ void DivPlatformYM2610B::acquire_ymfm(short** buf, size_t len) {
|
|||
|
||||
fm->generate(&fmout);
|
||||
|
||||
os[0]=fmout.data[0]+(fmout.data[2]>>1);
|
||||
os[0]+=((fmout.data[0]*fmVol)>>8)+((fmout.data[2]*ssgVol)>>8);
|
||||
if (os[0]<-32768) os[0]=-32768;
|
||||
if (os[0]>32767) os[0]=32767;
|
||||
|
||||
os[1]=fmout.data[1]+(fmout.data[2]>>1);
|
||||
os[1]+=((fmout.data[1]*fmVol)>>8)+((fmout.data[2]*ssgVol)>>8);
|
||||
if (os[1]<-32768) os[1]=-32768;
|
||||
if (os[1]>32767) os[1]=32767;
|
||||
|
||||
|
|
|
|||
|
|
@ -222,6 +222,8 @@ class DivPlatformYM2610Base: public DivPlatformOPN {
|
|||
CHECK_CUSTOM_CLOCK;
|
||||
noExtMacros=flags.getBool("noExtMacros",false);
|
||||
fbAllOps=flags.getBool("fbAllOps",false);
|
||||
ssgVol=flags.getInt("ssgVol",128);
|
||||
fmVol=flags.getInt("fmVol",256);
|
||||
rate=fm->sample_rate(chipClock);
|
||||
for (int i=0; i<16; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
|
|
|
|||
|
|
@ -412,11 +412,22 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
if (effectVal==-1) effectVal=0;
|
||||
|
||||
switch (effect) {
|
||||
case 0x09: // speed 1
|
||||
if (effectVal>0) speed1=effectVal;
|
||||
case 0x09: // select groove pattern/speed 1
|
||||
if (song.grooves.empty()) {
|
||||
if (effectVal>0) speeds.val[0]=effectVal;
|
||||
} else {
|
||||
if (effectVal<(short)song.grooves.size()) {
|
||||
speeds=song.grooves[effectVal];
|
||||
curSpeed=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x0f: // speed 2
|
||||
if (effectVal>0) speed2=effectVal;
|
||||
case 0x0f: // speed 1/speed 2
|
||||
if (speeds.len==2 && song.grooves.empty()) {
|
||||
if (effectVal>0) speeds.val[1]=effectVal;
|
||||
} else {
|
||||
if (effectVal>0) speeds.val[0]=effectVal;
|
||||
}
|
||||
break;
|
||||
case 0x0b: // change order
|
||||
if (changeOrd==-1 || song.jumpTreatment==0) {
|
||||
|
|
@ -1083,6 +1094,9 @@ void DivEngine::nextRow() {
|
|||
}
|
||||
|
||||
if (song.brokenSpeedSel) {
|
||||
unsigned char speed2=(speeds.len>=2)?speeds.val[1]:speeds.val[0];
|
||||
unsigned char speed1=speeds.val[0];
|
||||
|
||||
if ((curSubSong->patLen&1) && curOrder&1) {
|
||||
ticks=((curRow&1)?speed2:speed1)*(curSubSong->timeBase+1);
|
||||
nextSpeed=(curRow&1)?speed1:speed2;
|
||||
|
|
@ -1091,14 +1105,10 @@ void DivEngine::nextRow() {
|
|||
nextSpeed=(curRow&1)?speed2:speed1;
|
||||
}
|
||||
} else {
|
||||
if (speedAB) {
|
||||
ticks=speed2*(curSubSong->timeBase+1);
|
||||
nextSpeed=speed1;
|
||||
} else {
|
||||
ticks=speed1*(curSubSong->timeBase+1);
|
||||
nextSpeed=speed2;
|
||||
}
|
||||
speedAB=!speedAB;
|
||||
ticks=speeds.val[curSpeed]*(curSubSong->timeBase+1);
|
||||
curSpeed++;
|
||||
if (curSpeed>=speeds.len) curSpeed=0;
|
||||
nextSpeed=speeds.val[curSpeed];
|
||||
}
|
||||
|
||||
// post row details
|
||||
|
|
|
|||
|
|
@ -127,10 +127,20 @@ enum DivSystem {
|
|||
DIV_SYSTEM_YM2608_CSM
|
||||
};
|
||||
|
||||
struct DivGroovePattern {
|
||||
unsigned char val[16];
|
||||
unsigned char len;
|
||||
DivGroovePattern():
|
||||
len(1) {
|
||||
memset(val,6,16);
|
||||
}
|
||||
};
|
||||
|
||||
struct DivSubSong {
|
||||
String name, notes;
|
||||
unsigned char hilightA, hilightB;
|
||||
unsigned char timeBase, speed1, speed2, arpLen;
|
||||
unsigned char timeBase, arpLen;
|
||||
DivGroovePattern speeds;
|
||||
short virtualTempoN, virtualTempoD;
|
||||
bool pal;
|
||||
bool customTempo;
|
||||
|
|
@ -153,8 +163,6 @@ struct DivSubSong {
|
|||
hilightA(4),
|
||||
hilightB(16),
|
||||
timeBase(0),
|
||||
speed1(6),
|
||||
speed2(6),
|
||||
arpLen(1),
|
||||
virtualTempoN(150),
|
||||
virtualTempoD(150),
|
||||
|
|
@ -338,6 +346,7 @@ struct DivSong {
|
|||
|
||||
std::vector<DivSubSong*> subsong;
|
||||
std::vector<unsigned int> patchbay;
|
||||
std::vector<DivGroovePattern> grooves;
|
||||
|
||||
DivInstrument nullIns, nullInsOPLL, nullInsOPL, nullInsOPLDrums, nullInsQSound;
|
||||
DivWavetable nullWave;
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@
|
|||
#include "song.h"
|
||||
#include "../ta-log.h"
|
||||
|
||||
DivSysDef* DivEngine::sysDefs[256];
|
||||
DivSystem DivEngine::sysFileMapFur[256];
|
||||
DivSystem DivEngine::sysFileMapDMF[256];
|
||||
DivSysDef* DivEngine::sysDefs[DIV_MAX_CHIP_DEFS];
|
||||
DivSystem DivEngine::sysFileMapFur[DIV_MAX_CHIP_DEFS];
|
||||
DivSystem DivEngine::sysFileMapDMF[DIV_MAX_CHIP_DEFS];
|
||||
|
||||
DivSystem DivEngine::systemFromFileFur(unsigned char val) {
|
||||
return sysFileMapFur[val];
|
||||
|
|
@ -1831,7 +1831,7 @@ void DivEngine::registerSystems() {
|
|||
{DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD}
|
||||
);
|
||||
|
||||
for (int i=0; i<256; i++) {
|
||||
for (int i=0; i<DIV_MAX_CHIP_DEFS; i++) {
|
||||
if (sysDefs[i]==NULL) continue;
|
||||
if (sysDefs[i]->id!=0) {
|
||||
sysFileMapFur[sysDefs[i]->id]=(DivSystem)i;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue