Merge branch 'master' into ZSMv1
This commit is contained in:
commit
378f6a957b
3651 changed files with 495554 additions and 653 deletions
|
|
@ -524,6 +524,11 @@ class DivDispatch {
|
|||
// this is a special case definition. only use it for f-num/block-based chips.
|
||||
#define NOTE_FNUM_BLOCK(x,bits) parent->calcBaseFreqFNumBlock(chipClock,CHIP_FREQBASE,x,bits)
|
||||
|
||||
// this is for volume scaling calculation.
|
||||
#define VOL_SCALE_LINEAR_BROKEN(x,y,range) ((parent->song.newVolumeScaling)?(((x)*(y))/(range)):(CLAMP(((x)+(y))-(range),0,(range))))
|
||||
#define VOL_SCALE_LINEAR(x,y,range) (((x)*(y))/(range))
|
||||
#define VOL_SCALE_LOG(x,y,range) ((parent->song.newVolumeScaling)?(CLAMP(((x)+(y))-(range),0,(range))):(((x)*(y))/(range)))
|
||||
|
||||
// these are here for convenience.
|
||||
// it is encouraged to use these, since you get an exact value this way.
|
||||
// - NTSC colorburst: 3.58MHz
|
||||
|
|
|
|||
|
|
@ -193,6 +193,9 @@ bool DivEngine::isExporting() {
|
|||
|
||||
#ifdef HAVE_SNDFILE
|
||||
void DivEngine::runExportThread() {
|
||||
size_t fadeOutSamples=got.rate*exportFadeOut;
|
||||
size_t curFadeOutSample=0;
|
||||
bool isFadingOut=false;
|
||||
switch (exportMode) {
|
||||
case DIV_EXPORT_MODE_ONE: {
|
||||
SNDFILE* sf;
|
||||
|
|
@ -220,15 +223,33 @@ void DivEngine::runExportThread() {
|
|||
logI("rendering to file...");
|
||||
|
||||
while (playing) {
|
||||
size_t total=0;
|
||||
nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE);
|
||||
for (int i=0; i<EXPORT_BUFSIZE; i++) {
|
||||
outBuf[2][i<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][i]));
|
||||
outBuf[2][1+(i<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][i]));
|
||||
}
|
||||
if (totalProcessed>EXPORT_BUFSIZE) {
|
||||
logE("error: total processed is bigger than export bufsize! %d>%d",totalProcessed,EXPORT_BUFSIZE);
|
||||
totalProcessed=EXPORT_BUFSIZE;
|
||||
}
|
||||
if (sf_writef_float(sf,outBuf[2],totalProcessed)!=(int)totalProcessed) {
|
||||
for (int i=0; i<(int)totalProcessed; i++) {
|
||||
total++;
|
||||
if (isFadingOut) {
|
||||
double mul=(1.0-((double)curFadeOutSample/(double)fadeOutSamples));
|
||||
outBuf[2][i<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][i]))*mul;
|
||||
outBuf[2][1+(i<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][i]))*mul;
|
||||
if (++curFadeOutSample>=fadeOutSamples) {
|
||||
playing=false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
outBuf[2][i<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][i]));
|
||||
outBuf[2][1+(i<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][i]));
|
||||
if (lastLoopPos>-1 && i>=lastLoopPos && totalLoops>=exportLoopCount) {
|
||||
logD("start fading out...");
|
||||
isFadingOut=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sf_writef_float(sf,outBuf[2],total)!=(int)total) {
|
||||
logE("error: failed to write entire buffer!");
|
||||
break;
|
||||
}
|
||||
|
|
@ -286,7 +307,10 @@ void DivEngine::runExportThread() {
|
|||
float* outBuf[2];
|
||||
outBuf[0]=new float[EXPORT_BUFSIZE];
|
||||
outBuf[1]=new float[EXPORT_BUFSIZE];
|
||||
short* sysBuf=new short[EXPORT_BUFSIZE*2];
|
||||
short* sysBuf[32];
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
sysBuf[i]=new short[EXPORT_BUFSIZE*2];
|
||||
}
|
||||
|
||||
// take control of audio output
|
||||
deinitAudioBackend();
|
||||
|
|
@ -295,20 +319,45 @@ void DivEngine::runExportThread() {
|
|||
logI("rendering to files...");
|
||||
|
||||
while (playing) {
|
||||
size_t total=0;
|
||||
nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE);
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
for (int j=0; j<EXPORT_BUFSIZE; j++) {
|
||||
if (!disCont[i].dispatch->isStereo()) {
|
||||
sysBuf[j]=disCont[i].bbOut[0][j];
|
||||
} else {
|
||||
sysBuf[j<<1]=disCont[i].bbOut[0][j];
|
||||
sysBuf[1+(j<<1)]=disCont[i].bbOut[1][j];
|
||||
if (totalProcessed>EXPORT_BUFSIZE) {
|
||||
logE("error: total processed is bigger than export bufsize! %d>%d",totalProcessed,EXPORT_BUFSIZE);
|
||||
totalProcessed=EXPORT_BUFSIZE;
|
||||
}
|
||||
for (int j=0; j<(int)totalProcessed; j++) {
|
||||
total++;
|
||||
if (isFadingOut) {
|
||||
double mul=(1.0-((double)curFadeOutSample/(double)fadeOutSamples));
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
if (!disCont[i].dispatch->isStereo()) {
|
||||
sysBuf[i][j]=(double)disCont[i].bbOut[0][j]*mul;
|
||||
} else {
|
||||
sysBuf[i][j<<1]=(double)disCont[i].bbOut[0][j]*mul;
|
||||
sysBuf[i][1+(j<<1)]=(double)disCont[i].bbOut[1][j]*mul;
|
||||
}
|
||||
}
|
||||
if (++curFadeOutSample>=fadeOutSamples) {
|
||||
playing=false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
if (!disCont[i].dispatch->isStereo()) {
|
||||
sysBuf[i][j]=disCont[i].bbOut[0][j];
|
||||
} else {
|
||||
sysBuf[i][j<<1]=disCont[i].bbOut[0][j];
|
||||
sysBuf[i][1+(j<<1)]=disCont[i].bbOut[1][j];
|
||||
}
|
||||
}
|
||||
if (lastLoopPos>-1 && j>=lastLoopPos && totalLoops>=exportLoopCount) {
|
||||
logD("start fading out...");
|
||||
isFadingOut=true;
|
||||
}
|
||||
}
|
||||
if (totalProcessed>EXPORT_BUFSIZE) {
|
||||
logE("error: total processed is bigger than export bufsize! (%d) %d>%d",i,totalProcessed,EXPORT_BUFSIZE);
|
||||
}
|
||||
if (sf_writef_short(sf[i],sysBuf,totalProcessed)!=(int)totalProcessed) {
|
||||
}
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
if (sf_writef_short(sf[i],sysBuf[i],total)!=(int)total) {
|
||||
logE("error: failed to write entire buffer! (%d)",i);
|
||||
break;
|
||||
}
|
||||
|
|
@ -317,9 +366,9 @@ void DivEngine::runExportThread() {
|
|||
|
||||
delete[] outBuf[0];
|
||||
delete[] outBuf[1];
|
||||
delete[] sysBuf;
|
||||
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
delete[] sysBuf[i];
|
||||
if (sf_close(sf[i])!=0) {
|
||||
logE("could not close audio file!");
|
||||
}
|
||||
|
|
@ -382,19 +431,43 @@ void DivEngine::runExportThread() {
|
|||
}
|
||||
|
||||
curOrder=0;
|
||||
remainingLoops=loopCount;
|
||||
prevOrder=0;
|
||||
curFadeOutSample=0;
|
||||
isFadingOut=false;
|
||||
if (exportFadeOut<=0.01) {
|
||||
remainingLoops=loopCount;
|
||||
} else {
|
||||
remainingLoops=-1;
|
||||
}
|
||||
playSub(false);
|
||||
|
||||
while (playing) {
|
||||
size_t total=0;
|
||||
nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE);
|
||||
for (int j=0; j<EXPORT_BUFSIZE; j++) {
|
||||
outBuf[2][j<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][j]));
|
||||
outBuf[2][1+(j<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][j]));
|
||||
}
|
||||
if (totalProcessed>EXPORT_BUFSIZE) {
|
||||
logE("error: total processed is bigger than export bufsize! %d>%d",totalProcessed,EXPORT_BUFSIZE);
|
||||
totalProcessed=EXPORT_BUFSIZE;
|
||||
}
|
||||
if (sf_writef_float(sf,outBuf[2],totalProcessed)!=(int)totalProcessed) {
|
||||
for (int j=0; j<(int)totalProcessed; j++) {
|
||||
total++;
|
||||
if (isFadingOut) {
|
||||
double mul=(1.0-((double)curFadeOutSample/(double)fadeOutSamples));
|
||||
outBuf[2][j<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][j]))*mul;
|
||||
outBuf[2][1+(j<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][j]))*mul;
|
||||
if (++curFadeOutSample>=fadeOutSamples) {
|
||||
playing=false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
outBuf[2][j<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][j]));
|
||||
outBuf[2][1+(j<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][j]));
|
||||
if (lastLoopPos>-1 && j>=lastLoopPos && totalLoops>=exportLoopCount) {
|
||||
logD("start fading out...");
|
||||
isFadingOut=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sf_writef_float(sf,outBuf[2],total)!=(int)total) {
|
||||
logE("error: failed to write entire buffer!");
|
||||
break;
|
||||
}
|
||||
|
|
@ -448,13 +521,14 @@ void DivEngine::runExportThread() {
|
|||
}
|
||||
#endif
|
||||
|
||||
bool DivEngine::saveAudio(const char* path, int loops, DivAudioExportModes mode) {
|
||||
bool DivEngine::saveAudio(const char* path, int loops, DivAudioExportModes mode, double fadeOutTime) {
|
||||
#ifndef HAVE_SNDFILE
|
||||
logE("Furnace was not compiled with libsndfile. cannot export!");
|
||||
return false;
|
||||
#else
|
||||
exportPath=path;
|
||||
exportMode=mode;
|
||||
exportFadeOut=fadeOutTime;
|
||||
if (exportMode!=DIV_EXPORT_MODE_ONE) {
|
||||
// remove extension
|
||||
String lowerCase=exportPath;
|
||||
|
|
@ -471,7 +545,12 @@ bool DivEngine::saveAudio(const char* path, int loops, DivAudioExportModes mode)
|
|||
stop();
|
||||
repeatPattern=false;
|
||||
setOrder(0);
|
||||
remainingLoops=loops;
|
||||
if (exportFadeOut<=0.01) {
|
||||
remainingLoops=loops;
|
||||
} else {
|
||||
remainingLoops=-1;
|
||||
}
|
||||
exportLoopCount=loops;
|
||||
exportThread=new std::thread(_runExportThread,this);
|
||||
return true;
|
||||
#endif
|
||||
|
|
@ -780,6 +859,8 @@ void DivEngine::changeSong(size_t songIndex) {
|
|||
curSubSongIndex=songIndex;
|
||||
curOrder=0;
|
||||
curRow=0;
|
||||
prevOrder=0;
|
||||
prevRow=0;
|
||||
}
|
||||
|
||||
void DivEngine::swapChannelsP(int src, int dest) {
|
||||
|
|
@ -827,12 +908,51 @@ bool DivEngine::removeSubSong(int index) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void DivEngine::moveSubSongUp(size_t index) {
|
||||
if (index<1 || index>=song.subsong.size()) return;
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
|
||||
if (index==curSubSongIndex) {
|
||||
curSubSongIndex--;
|
||||
} else if (index-1==curSubSongIndex) {
|
||||
curSubSongIndex++;
|
||||
}
|
||||
|
||||
DivSubSong* prev=song.subsong[index-1];
|
||||
song.subsong[index-1]=song.subsong[index];
|
||||
song.subsong[index]=prev;
|
||||
|
||||
saveLock.unlock();
|
||||
BUSY_END;
|
||||
}
|
||||
|
||||
void DivEngine::moveSubSongDown(size_t index) {
|
||||
if (index>=song.subsong.size()-1) return;
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
|
||||
if (index==curSubSongIndex) {
|
||||
curSubSongIndex++;
|
||||
} else if (index+1==curSubSongIndex) {
|
||||
curSubSongIndex--;
|
||||
}
|
||||
|
||||
DivSubSong* prev=song.subsong[index+1];
|
||||
song.subsong[index+1]=song.subsong[index];
|
||||
song.subsong[index]=prev;
|
||||
|
||||
saveLock.unlock();
|
||||
BUSY_END;
|
||||
}
|
||||
|
||||
void DivEngine::clearSubSongs() {
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
song.clearSongData();
|
||||
changeSong(0);
|
||||
curOrder=0;
|
||||
prevOrder=0;
|
||||
saveLock.unlock();
|
||||
BUSY_END;
|
||||
}
|
||||
|
|
@ -987,6 +1107,9 @@ DivInstrument* DivEngine::getIns(int index, DivInstrumentType fallbackType) {
|
|||
case DIV_INS_OPL:
|
||||
return &song.nullInsOPL;
|
||||
break;
|
||||
case DIV_INS_OPL_DRUMS:
|
||||
return &song.nullInsOPLDrums;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1072,6 +1195,8 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) {
|
|||
int goal=curOrder;
|
||||
curOrder=0;
|
||||
curRow=0;
|
||||
prevOrder=0;
|
||||
prevRow=0;
|
||||
stepPlay=0;
|
||||
int prevDrift;
|
||||
prevDrift=clockDrift;
|
||||
|
|
@ -1085,6 +1210,8 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) {
|
|||
totalTicks=0;
|
||||
totalSeconds=0;
|
||||
totalTicksR=0;
|
||||
totalLoops=0;
|
||||
lastLoopPos=-1;
|
||||
}
|
||||
speedAB=false;
|
||||
playing=true;
|
||||
|
|
@ -1121,6 +1248,8 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) {
|
|||
if (!preserveDrift) {
|
||||
ticks=1;
|
||||
subticks=1;
|
||||
prevOrder=curOrder;
|
||||
prevRow=curRow;
|
||||
}
|
||||
skipping=false;
|
||||
cmdStream.clear();
|
||||
|
|
@ -1247,6 +1376,7 @@ unsigned int DivEngine::convertPanLinearToSplit(int val, unsigned char bits, int
|
|||
|
||||
void DivEngine::play() {
|
||||
BUSY_BEGIN_SOFT;
|
||||
curOrder=prevOrder;
|
||||
sPreview.sample=-1;
|
||||
sPreview.wave=-1;
|
||||
sPreview.pos=0;
|
||||
|
|
@ -1471,8 +1601,10 @@ int DivEngine::getEffectiveSampleRate(int rate) {
|
|||
return rate;
|
||||
}
|
||||
|
||||
void DivEngine::previewSample(int sample, int note) {
|
||||
void DivEngine::previewSample(int sample, int note, int pStart, int pEnd) {
|
||||
BUSY_BEGIN;
|
||||
sPreview.pBegin=pStart;
|
||||
sPreview.pEnd=pEnd;
|
||||
if (sample<0 || sample>=(int)song.sample.size()) {
|
||||
sPreview.sample=-1;
|
||||
sPreview.pos=0;
|
||||
|
|
@ -1488,7 +1620,7 @@ void DivEngine::previewSample(int sample, int note) {
|
|||
if (rate<100) rate=100;
|
||||
blip_set_rates(samp_bb,rate,got.rate);
|
||||
samp_prevSample=0;
|
||||
sPreview.pos=0;
|
||||
sPreview.pos=(sPreview.pBegin>=0)?sPreview.pBegin:0;
|
||||
sPreview.sample=sample;
|
||||
sPreview.wave=-1;
|
||||
BUSY_END;
|
||||
|
|
@ -1540,11 +1672,11 @@ int DivEngine::getMaxVolumeChan(int ch) {
|
|||
}
|
||||
|
||||
unsigned char DivEngine::getOrder() {
|
||||
return curOrder;
|
||||
return prevOrder;
|
||||
}
|
||||
|
||||
int DivEngine::getRow() {
|
||||
return curRow;
|
||||
return prevRow;
|
||||
}
|
||||
|
||||
size_t DivEngine::getCurrentSubSong() {
|
||||
|
|
@ -1681,6 +1813,9 @@ int DivEngine::addInstrument(int refChan) {
|
|||
case DIV_INS_OPL:
|
||||
*ins=song.nullInsOPL;
|
||||
break;
|
||||
case DIV_INS_OPL_DRUMS:
|
||||
*ins=song.nullInsOPLDrums;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1760,7 +1895,7 @@ int DivEngine::addWave() {
|
|||
return waveCount;
|
||||
}
|
||||
|
||||
bool DivEngine::addWaveFromFile(const char* path) {
|
||||
bool DivEngine::addWaveFromFile(const char* path, bool addRaw) {
|
||||
if (song.wave.size()>=256) {
|
||||
lastError="too many wavetables!";
|
||||
return false;
|
||||
|
|
@ -1838,6 +1973,9 @@ bool DivEngine::addWaveFromFile(const char* path) {
|
|||
// read as .dmw
|
||||
reader.seek(0,SEEK_SET);
|
||||
int len=reader.readI();
|
||||
if (len<=0 || len>256) {
|
||||
throw EndOfFileException(&reader,reader.size());
|
||||
}
|
||||
wave->max=(unsigned char)reader.readC();
|
||||
if (wave->max==255) { // new wavetable format
|
||||
unsigned char waveVersion=reader.readC();
|
||||
|
|
@ -1856,8 +1994,27 @@ bool DivEngine::addWaveFromFile(const char* path) {
|
|||
}
|
||||
} else {
|
||||
// read as binary
|
||||
logI("reading binary...");
|
||||
if (addRaw) {
|
||||
logI("reading binary...");
|
||||
len=reader.size();
|
||||
if (len>256) len=256;
|
||||
reader.seek(0,SEEK_SET);
|
||||
for (int i=0; i<len; i++) {
|
||||
wave->data[i]=(unsigned char)reader.readC();
|
||||
if (wave->max<wave->data[i]) wave->max=wave->data[i];
|
||||
}
|
||||
wave->len=len;
|
||||
} else {
|
||||
delete wave;
|
||||
delete[] buf;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (EndOfFileException& e) {
|
||||
// read as binary
|
||||
if (addRaw) {
|
||||
len=reader.size();
|
||||
logI("reading binary for being too small...");
|
||||
if (len>256) len=256;
|
||||
reader.seek(0,SEEK_SET);
|
||||
for (int i=0; i<len; i++) {
|
||||
|
|
@ -1865,18 +2022,11 @@ bool DivEngine::addWaveFromFile(const char* path) {
|
|||
if (wave->max<wave->data[i]) wave->max=wave->data[i];
|
||||
}
|
||||
wave->len=len;
|
||||
} else {
|
||||
delete wave;
|
||||
delete[] buf;
|
||||
return false;
|
||||
}
|
||||
} catch (EndOfFileException& e) {
|
||||
// read as binary
|
||||
len=reader.size();
|
||||
logI("reading binary for being too small...");
|
||||
if (len>256) len=256;
|
||||
reader.seek(0,SEEK_SET);
|
||||
for (int i=0; i<len; i++) {
|
||||
wave->data[i]=(unsigned char)reader.readC();
|
||||
if (wave->max<wave->data[i]) wave->max=wave->data[i];
|
||||
}
|
||||
wave->len=len;
|
||||
}
|
||||
}
|
||||
} catch (EndOfFileException& e) {
|
||||
|
|
@ -2129,6 +2279,7 @@ void DivEngine::delSample(int index) {
|
|||
void DivEngine::addOrder(bool duplicate, bool where) {
|
||||
unsigned char order[DIV_MAX_CHANS];
|
||||
if (curSubSong->ordersLen>=0xff) return;
|
||||
memset(order,0,DIV_MAX_CHANS);
|
||||
BUSY_BEGIN_SOFT;
|
||||
if (duplicate) {
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
|
|
@ -2438,7 +2589,7 @@ void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) {
|
|||
|
||||
// 2. find a free channel
|
||||
do {
|
||||
if (isViable[finalChan] && chan[finalChan].midiNote==-1 && (insInst->type==DIV_INS_OPL || getChannelType(finalChan)==finalChanType || notInViableChannel)) {
|
||||
if ((!midiPoly) || (isViable[finalChan] && chan[finalChan].midiNote==-1 && (insInst->type==DIV_INS_OPL || getChannelType(finalChan)==finalChanType || notInViableChannel))) {
|
||||
chan[finalChan].midiNote=note;
|
||||
chan[finalChan].midiAge=midiAgeCounter++;
|
||||
pendingNotes.push(DivNoteEvent(finalChan,ins,note,vol,true));
|
||||
|
|
@ -2494,10 +2645,15 @@ void DivEngine::autoNoteOffAll() {
|
|||
}
|
||||
}
|
||||
|
||||
void DivEngine::setAutoNotePoly(bool poly) {
|
||||
midiPoly=poly;
|
||||
}
|
||||
|
||||
void DivEngine::setOrder(unsigned char order) {
|
||||
BUSY_BEGIN_SOFT;
|
||||
curOrder=order;
|
||||
if (order>=curSubSong->ordersLen) curOrder=0;
|
||||
prevOrder=curOrder;
|
||||
if (playing && !freelance) {
|
||||
playSub(false);
|
||||
}
|
||||
|
|
@ -2691,6 +2847,8 @@ void DivEngine::quitDispatch() {
|
|||
tempoAccum=0;
|
||||
curRow=0;
|
||||
curOrder=0;
|
||||
prevRow=0;
|
||||
prevOrder=0;
|
||||
nextSpeed=3;
|
||||
changeOrd=-1;
|
||||
changePos=0;
|
||||
|
|
@ -2955,6 +3113,9 @@ bool DivEngine::init() {
|
|||
oscBuf[0]=new float[32768];
|
||||
oscBuf[1]=new float[32768];
|
||||
|
||||
memset(oscBuf[0],0,32768*sizeof(float));
|
||||
memset(oscBuf[1],0,32768*sizeof(float));
|
||||
|
||||
initDispatch();
|
||||
renderSamples();
|
||||
reset();
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ class DivEngine {
|
|||
bool systemsRegistered;
|
||||
bool hasLoadedSomething;
|
||||
int softLockCount;
|
||||
int subticks, ticks, curRow, curOrder, remainingLoops, nextSpeed;
|
||||
int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed;
|
||||
size_t curSubSongIndex;
|
||||
double divider;
|
||||
int cycles;
|
||||
|
|
@ -318,6 +318,7 @@ class DivEngine {
|
|||
DivChannelState chan[DIV_MAX_CHANS];
|
||||
DivAudioEngines audioEngine;
|
||||
DivAudioExportModes exportMode;
|
||||
double exportFadeOut;
|
||||
std::map<String,String> conf;
|
||||
std::queue<DivNoteEvent> pendingNotes;
|
||||
bool isMuted[DIV_MAX_CHANS];
|
||||
|
|
@ -339,16 +340,20 @@ class DivEngine {
|
|||
int sample;
|
||||
int wave;
|
||||
unsigned int pos;
|
||||
int pBegin, pEnd;
|
||||
SamplePreview():
|
||||
sample(-1),
|
||||
wave(-1),
|
||||
pos(0) {}
|
||||
pos(0),
|
||||
pBegin(-1),
|
||||
pEnd(-1) {}
|
||||
} sPreview;
|
||||
|
||||
short vibTable[64];
|
||||
int reversePitchTable[4096];
|
||||
int pitchTable[4096];
|
||||
int midiBaseChan;
|
||||
bool midiPoly;
|
||||
size_t midiAgeCounter;
|
||||
|
||||
blip_buffer_t* samp_bb;
|
||||
|
|
@ -461,7 +466,7 @@ class DivEngine {
|
|||
// dump to ZSM.
|
||||
SafeWriter* saveZSM(unsigned int zsmrate=60, bool loop=true);
|
||||
// export to an audio file
|
||||
bool saveAudio(const char* path, int loops, DivAudioExportModes mode);
|
||||
bool saveAudio(const char* path, int loops, DivAudioExportModes mode, double fadeOutTime=0.0);
|
||||
// wait for audio export to finish
|
||||
void waitAudioFile();
|
||||
// stop audio file export
|
||||
|
|
@ -527,7 +532,7 @@ class DivEngine {
|
|||
void syncReset();
|
||||
|
||||
// trigger sample preview
|
||||
void previewSample(int sample, int note=-1);
|
||||
void previewSample(int sample, int note=-1, int pStart=-1, int pEnd=-1);
|
||||
void stopSamplePreview();
|
||||
|
||||
// trigger wave preview
|
||||
|
|
@ -676,7 +681,7 @@ class DivEngine {
|
|||
int addWave();
|
||||
|
||||
// add wavetable from file
|
||||
bool addWaveFromFile(const char* path);
|
||||
bool addWaveFromFile(const char* path, bool loadRaw=true);
|
||||
|
||||
// delete wavetable
|
||||
void delWave(int index);
|
||||
|
|
@ -724,6 +729,9 @@ class DivEngine {
|
|||
void autoNoteOn(int chan, int ins, int note, int vol=-1);
|
||||
void autoNoteOff(int chan, int note, int vol=-1);
|
||||
void autoNoteOffAll();
|
||||
|
||||
// set whether autoNoteIn is mono or poly
|
||||
void setAutoNotePoly(bool poly);
|
||||
|
||||
// go to order
|
||||
void setOrder(unsigned char order);
|
||||
|
|
@ -824,6 +832,10 @@ class DivEngine {
|
|||
// remove subsong
|
||||
bool removeSubSong(int index);
|
||||
|
||||
// move subsong
|
||||
void moveSubSongUp(size_t index);
|
||||
void moveSubSongDown(size_t index);
|
||||
|
||||
// clear all subsong data
|
||||
void clearSubSongs();
|
||||
|
||||
|
|
@ -926,7 +938,12 @@ class DivEngine {
|
|||
ticks(0),
|
||||
curRow(0),
|
||||
curOrder(0),
|
||||
prevRow(0),
|
||||
prevOrder(0),
|
||||
remainingLoops(-1),
|
||||
totalLoops(0),
|
||||
lastLoopPos(0),
|
||||
exportLoopCount(0),
|
||||
nextSpeed(3),
|
||||
curSubSongIndex(0),
|
||||
divider(60),
|
||||
|
|
@ -950,7 +967,9 @@ class DivEngine {
|
|||
haltOn(DIV_HALT_NONE),
|
||||
audioEngine(DIV_AUDIO_NULL),
|
||||
exportMode(DIV_EXPORT_MODE_ONE),
|
||||
exportFadeOut(0.0),
|
||||
midiBaseChan(0),
|
||||
midiPoly(true),
|
||||
midiAgeCounter(0),
|
||||
samp_bb(NULL),
|
||||
samp_bbInLen(0),
|
||||
|
|
|
|||
|
|
@ -870,14 +870,30 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) {
|
|||
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentSTD::OpMacro& op=std.opMacros[i];
|
||||
reader.read(op.damMacro.val,op.damMacro.len);
|
||||
reader.read(op.dvbMacro.val,op.dvbMacro.len);
|
||||
reader.read(op.egtMacro.val,op.egtMacro.len);
|
||||
reader.read(op.kslMacro.val,op.kslMacro.len);
|
||||
reader.read(op.susMacro.val,op.susMacro.len);
|
||||
reader.read(op.vibMacro.val,op.vibMacro.len);
|
||||
reader.read(op.wsMacro.val,op.wsMacro.len);
|
||||
reader.read(op.ksrMacro.val,op.ksrMacro.len);
|
||||
for (int j=0; j<op.damMacro.len; j++) {
|
||||
op.damMacro.val[j]=(unsigned char)reader.readC();
|
||||
}
|
||||
for (int j=0; j<op.dvbMacro.len; j++) {
|
||||
op.dvbMacro.val[j]=(unsigned char)reader.readC();
|
||||
}
|
||||
for (int j=0; j<op.egtMacro.len; j++) {
|
||||
op.egtMacro.val[j]=(unsigned char)reader.readC();
|
||||
}
|
||||
for (int j=0; j<op.kslMacro.len; j++) {
|
||||
op.kslMacro.val[j]=(unsigned char)reader.readC();
|
||||
}
|
||||
for (int j=0; j<op.susMacro.len; j++) {
|
||||
op.susMacro.val[j]=(unsigned char)reader.readC();
|
||||
}
|
||||
for (int j=0; j<op.vibMacro.len; j++) {
|
||||
op.vibMacro.val[j]=(unsigned char)reader.readC();
|
||||
}
|
||||
for (int j=0; j<op.wsMacro.len; j++) {
|
||||
op.wsMacro.val[j]=(unsigned char)reader.readC();
|
||||
}
|
||||
for (int j=0; j<op.ksrMacro.len; j++) {
|
||||
op.ksrMacro.val[j]=(unsigned char)reader.readC();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ enum DivInstrumentType: unsigned short {
|
|||
DIV_INS_SNES=29,
|
||||
DIV_INS_SU=30,
|
||||
DIV_INS_NAMCO=31,
|
||||
DIV_INS_OPL_DRUMS=32,
|
||||
DIV_INS_MAX,
|
||||
DIV_INS_NULL
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,6 +21,12 @@
|
|||
#include "instrument.h"
|
||||
#include "engine.h"
|
||||
|
||||
void DivMacroStruct::prepare(DivInstrumentMacro& source, DivEngine* e) {
|
||||
has=had=actualHad=will=true;
|
||||
mode=source.mode;
|
||||
linger=(source.name=="vol" && e->song.volMacroLinger);
|
||||
}
|
||||
|
||||
void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tick) {
|
||||
if (!tick) {
|
||||
had=false;
|
||||
|
|
@ -46,6 +52,8 @@ void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tic
|
|||
if (pos>=source.len) {
|
||||
if (source.loop<source.len && source.loop>=0 && (source.loop>=source.rel || source.rel>=source.len)) {
|
||||
pos=source.loop;
|
||||
} else if (linger) {
|
||||
pos--;
|
||||
} else {
|
||||
has=false;
|
||||
}
|
||||
|
|
@ -93,6 +101,7 @@ void DivMacroInt::init(DivInstrument* which) {
|
|||
macroListLen=0;
|
||||
subTick=1;
|
||||
|
||||
hasRelease=false;
|
||||
released=false;
|
||||
|
||||
if (ins==NULL) return;
|
||||
|
|
@ -228,7 +237,12 @@ void DivMacroInt::init(DivInstrument* which) {
|
|||
}
|
||||
|
||||
for (size_t i=0; i<macroListLen; i++) {
|
||||
macroList[i]->prepare(*macroSource[i]);
|
||||
if (macroSource[i]!=NULL) {
|
||||
macroList[i]->prepare(*macroSource[i],e);
|
||||
hasRelease=(macroSource[i]->rel>=0 && macroSource[i]->rel<macroSource[i]->len);
|
||||
} else {
|
||||
hasRelease=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,19 +27,17 @@ class DivEngine;
|
|||
struct DivMacroStruct {
|
||||
int pos;
|
||||
int val;
|
||||
bool has, had, actualHad, finished, will;
|
||||
bool has, had, actualHad, finished, will, linger;
|
||||
unsigned int mode;
|
||||
void doMacro(DivInstrumentMacro& source, bool released, bool tick);
|
||||
void init() {
|
||||
pos=mode=0;
|
||||
has=had=actualHad=will=false;
|
||||
linger=false;
|
||||
// TODO: test whether this breaks anything?
|
||||
val=0;
|
||||
}
|
||||
void prepare(DivInstrumentMacro& source) {
|
||||
has=had=actualHad=will=true;
|
||||
mode=source.mode;
|
||||
}
|
||||
void prepare(DivInstrumentMacro& source, DivEngine* e);
|
||||
DivMacroStruct():
|
||||
pos(0),
|
||||
val(0),
|
||||
|
|
@ -48,6 +46,7 @@ struct DivMacroStruct {
|
|||
actualHad(false),
|
||||
finished(false),
|
||||
will(false),
|
||||
linger(false),
|
||||
mode(0) {}
|
||||
};
|
||||
|
||||
|
|
@ -97,6 +96,9 @@ class DivMacroInt {
|
|||
ksr() {}
|
||||
} op[4];
|
||||
|
||||
// state
|
||||
bool hasRelease;
|
||||
|
||||
/**
|
||||
* trigger macro release.
|
||||
*/
|
||||
|
|
@ -150,7 +152,8 @@ class DivMacroInt {
|
|||
ex5(),
|
||||
ex6(),
|
||||
ex7(),
|
||||
ex8() {
|
||||
ex8(),
|
||||
hasRelease(false) {
|
||||
memset(macroList,0,128*sizeof(void*));
|
||||
memset(macroSource,0,128*sizeof(void*));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -271,6 +271,9 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
|
|||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
if (chan[c.chan].useWave) {
|
||||
chan[c.chan].ws.init(ins,chan[c.chan].audLen<<1,255,chan[c.chan].insChanged);
|
||||
}
|
||||
|
|
@ -424,6 +427,10 @@ bool DivPlatformAmiga::keyOffAffectsArp(int ch) {
|
|||
return true;
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformAmiga::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
void DivPlatformAmiga::notifyInsChange(int ins) {
|
||||
for (int i=0; i<4; i++) {
|
||||
if (chan[i].ins==ins) {
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ class DivPlatformAmiga: public DivDispatch {
|
|||
void muteChannel(int ch, bool mute);
|
||||
bool isStereo();
|
||||
bool keyOffAffectsArp(int ch);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
void setFlags(unsigned int flags);
|
||||
void notifyInsChange(int ins);
|
||||
void notifyWaveChange(int wave);
|
||||
|
|
|
|||
|
|
@ -284,12 +284,12 @@ void DivPlatformArcade::tick(bool sysTick) {
|
|||
chan[i].std.next();
|
||||
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
|
||||
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127);
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -378,7 +378,7 @@ void DivPlatformArcade::tick(bool sysTick) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -432,7 +432,7 @@ void DivPlatformArcade::tick(bool sysTick) {
|
|||
if (m.tl.had) {
|
||||
op.tl=127-m.tl.val;
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -528,7 +528,7 @@ int DivPlatformArcade::dispatch(DivCommand c) {
|
|||
DivInstrumentFM::Operator op=chan[c.chan].state.op[i];
|
||||
if (isOutput[chan[c.chan].state.alg][i]) {
|
||||
if (!chan[c.chan].active || chan[c.chan].insChanged) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
|
||||
}
|
||||
} else {
|
||||
if (chan[c.chan].insChanged) {
|
||||
|
|
@ -585,7 +585,7 @@ int DivPlatformArcade::dispatch(DivCommand c) {
|
|||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
if (isOutput[chan[c.chan].state.alg][i]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -676,7 +676,7 @@ int DivPlatformArcade::dispatch(DivCommand c) {
|
|||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.tl=c.value2;
|
||||
if (isOutput[chan[c.chan].state.alg][c.value]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -876,7 +876,7 @@ void DivPlatformArcade::forceIns() {
|
|||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
DivInstrumentFM::Operator op=chan[i].state.op[j];
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -913,6 +913,10 @@ void* DivPlatformArcade::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformArcade::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformArcade::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ class DivPlatformArcade: public DivDispatch {
|
|||
void forceIns();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
void notifyInsChange(int ins);
|
||||
void setFlags(unsigned int flags);
|
||||
bool isStereo();
|
||||
|
|
|
|||
|
|
@ -315,6 +315,9 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
|||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else if (intellivision && (chan[c.chan].psgMode&4)) {
|
||||
|
|
@ -506,6 +509,10 @@ void* DivPlatformAY8910::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformAY8910::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformAY8910::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ class DivPlatformAY8910: public DivDispatch {
|
|||
void setFlags(unsigned int flags);
|
||||
bool isStereo();
|
||||
bool keyOffAffectsArp(int ch);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
bool getDCOffRequired();
|
||||
void notifyInsDeletion(void* ins);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
|
|
|
|||
|
|
@ -346,6 +346,9 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
|||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else {
|
||||
|
|
@ -536,6 +539,10 @@ void* DivPlatformAY8930::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformAY8930::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformAY8930::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ class DivPlatformAY8930: public DivDispatch {
|
|||
void setFlags(unsigned int flags);
|
||||
bool isStereo();
|
||||
bool keyOffAffectsArp(int ch);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
void notifyInsDeletion(void* ins);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
|
|
|
|||
|
|
@ -169,6 +169,9 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) {
|
|||
chan[c.chan].keyOn=true;
|
||||
rWrite(2+c.chan,(chan[c.chan].wave<<5)|chan[c.chan].vol);
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
if (chan[c.chan].wave<0) {
|
||||
chan[c.chan].wave=0;
|
||||
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
|
||||
|
|
@ -278,6 +281,10 @@ void* DivPlatformBubSysWSG::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformBubSysWSG::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformBubSysWSG::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ class DivPlatformBubSysWSG: public DivDispatch {
|
|||
void muteChannel(int ch, bool mute);
|
||||
bool isStereo();
|
||||
bool keyOffAffectsArp(int ch);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
void setFlags(unsigned int flags);
|
||||
void notifyWaveChange(int wave);
|
||||
void notifyInsDeletion(void* ins);
|
||||
|
|
|
|||
|
|
@ -491,6 +491,10 @@ void* DivPlatformC64::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformC64::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformC64::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ class DivPlatformC64: public DivDispatch {
|
|||
void setFlags(unsigned int flags);
|
||||
void notifyInsChange(int ins);
|
||||
bool getDCOffRequired();
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
void notifyInsDeletion(void* ins);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ void DivPlatformFDS::tick(bool sysTick) {
|
|||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
// ok, why are the volumes like that?
|
||||
chan[i].outVol=MIN(32,chan[i].std.vol.val)-(32-MIN(32,chan[i].vol));
|
||||
chan[i].outVol=VOL_SCALE_LINEAR_BROKEN(chan[i].vol,chan[i].std.vol.val,32);
|
||||
if (chan[i].outVol<0) chan[i].outVol=0;
|
||||
rWrite(0x4080,0x80|chan[i].outVol);
|
||||
}
|
||||
|
|
@ -285,6 +285,9 @@ int DivPlatformFDS::dispatch(DivCommand c) {
|
|||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
if (chan[c.chan].wave<0) {
|
||||
chan[c.chan].wave=0;
|
||||
ws.changeWave1(chan[c.chan].wave);
|
||||
|
|
@ -433,6 +436,10 @@ void* DivPlatformFDS::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformFDS::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformFDS::getOscBuffer(int ch) {
|
||||
return oscBuf;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ class DivPlatformFDS: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -433,6 +433,10 @@ void* DivPlatformGB::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformGB::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformGB::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ class DivPlatformGB: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -24,10 +24,13 @@
|
|||
|
||||
#include "genesisshared.h"
|
||||
|
||||
#define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6])))
|
||||
|
||||
static unsigned char konOffs[6]={
|
||||
0, 1, 2, 4, 5, 6
|
||||
};
|
||||
|
||||
#define CHIP_DIVIDER 72
|
||||
#define CHIP_FREQBASE 9440540
|
||||
|
||||
const char* DivPlatformGenesis::getEffectName(unsigned char effect) {
|
||||
|
|
@ -144,10 +147,13 @@ void DivPlatformGenesis::processDAC() {
|
|||
DivSample* s=parent->getSample(chan[i].dacSample);
|
||||
if (!isMuted[i] && s->samples>0) {
|
||||
if (parent->song.noOPN2Vol) {
|
||||
sample+=s->data8[chan[i].dacDirection?(s->samples-chan[i].dacPos-1):chan[i].dacPos];
|
||||
chan[i].dacOutput=s->data8[chan[i].dacDirection?(s->samples-chan[i].dacPos-1):chan[i].dacPos];
|
||||
} else {
|
||||
sample+=(s->data8[chan[i].dacDirection?(s->samples-chan[i].dacPos-1):chan[i].dacPos]*dacVolTable[chan[i].outVol])>>7;
|
||||
chan[i].dacOutput=(s->data8[chan[i].dacDirection?(s->samples-chan[i].dacPos-1):chan[i].dacPos]*dacVolTable[chan[i].outVol])>>7;
|
||||
}
|
||||
sample+=chan[i].dacOutput;
|
||||
} else {
|
||||
chan[i].dacOutput=0;
|
||||
}
|
||||
chan[i].dacPeriod+=chan[i].dacRate;
|
||||
if (chan[i].dacPeriod>=(chipClock/576)) {
|
||||
|
|
@ -249,7 +255,20 @@ void DivPlatformGenesis::acquire_nuked(short* bufL, short* bufR, size_t start, s
|
|||
|
||||
OPN2_Clock(&fm,o); os[0]+=o[0]; os[1]+=o[1];
|
||||
//OPN2_Write(&fm,0,0);
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fm.ch_out[i]<<7;
|
||||
if (i==5) {
|
||||
if (fm.dacen) {
|
||||
if (softPCM) {
|
||||
oscBuf[5]->data[oscBuf[5]->needle++]=chan[5].dacOutput<<7;
|
||||
oscBuf[6]->data[oscBuf[6]->needle++]=chan[6].dacOutput<<7;
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fm.dacdata<<7;
|
||||
}
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fm.ch_out[i]<<7;
|
||||
}
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fm.ch_out[i]<<7;
|
||||
}
|
||||
}
|
||||
|
||||
os[0]=(os[0]<<5);
|
||||
|
|
@ -293,7 +312,20 @@ void DivPlatformGenesis::acquire_ymfm(short* bufL, short* bufR, size_t start, si
|
|||
//OPN2_Write(&fm,0,0);
|
||||
|
||||
for (int i=0; i<6; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6;
|
||||
if (i==5) {
|
||||
if (fm_ymfm->debug_dac_enable()) {
|
||||
if (softPCM) {
|
||||
oscBuf[5]->data[oscBuf[5]->needle++]=chan[5].dacOutput<<7;
|
||||
oscBuf[6]->data[oscBuf[6]->needle++]=chan[6].dacOutput<<7;
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fm_ymfm->debug_dac_data()<<7;
|
||||
}
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6;
|
||||
}
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6;
|
||||
}
|
||||
}
|
||||
|
||||
if (os[0]<-32768) os[0]=-32768;
|
||||
|
|
@ -321,7 +353,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
chan[i].std.next();
|
||||
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
|
||||
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127);
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||
|
|
@ -329,7 +361,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -355,7 +387,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].pan=chan[i].std.panL.val&3;
|
||||
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
||||
rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
||||
}
|
||||
|
||||
if (chan[i].std.pitch.had) {
|
||||
|
|
@ -384,7 +416,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -397,11 +429,11 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.fms.had) {
|
||||
chan[i].state.fms=chan[i].std.fms.val;
|
||||
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
||||
rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
||||
}
|
||||
if (chan[i].std.ams.had) {
|
||||
chan[i].state.ams=chan[i].std.ams.val;
|
||||
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
||||
rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
||||
}
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
|
|
@ -437,7 +469,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -495,8 +527,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
for (int i=0; i<8; i++) {
|
||||
for (int i=0; i<7; i++) {
|
||||
if (i==2 && extMode) continue;
|
||||
if (chan[i].freqChanged) {
|
||||
if (parent->song.linearPitch==2) {
|
||||
|
|
@ -545,27 +576,45 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
|
||||
void DivPlatformGenesis::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
if (ch>5) return;
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[ch]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[ch].state.op[j];
|
||||
if (isMuted[ch]) {
|
||||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[ch].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[ch].outVol&0x7f))/127));
|
||||
if (ch>6) return;
|
||||
if (ch<6) {
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[ch]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[ch].state.op[j];
|
||||
if (isMuted[ch]) {
|
||||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
if (isOutput[chan[ch].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ch--;
|
||||
}
|
||||
rWrite(chanOffs[ch]+ADDR_LRAF,(isMuted[ch]?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4));
|
||||
rWrite(chanOffs[ch]+ADDR_LRAF,(IS_REALLY_MUTED(ch)?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4));
|
||||
}
|
||||
|
||||
int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
if (c.chan==7 && extMode && softPCM) { // CSM
|
||||
chan[c.chan].macroInit(ins);
|
||||
chan[c.chan].insChanged=false;
|
||||
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].portaPause=false;
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
}
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].active=true;
|
||||
break;
|
||||
}
|
||||
if (c.chan>=5) {
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
chan[c.chan].dacMode=1;
|
||||
|
|
@ -634,7 +683,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
} else {
|
||||
if (isOutput[chan[c.chan].state.alg][i]) {
|
||||
if (!chan[c.chan].active || chan[c.chan].insChanged) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
|
||||
}
|
||||
} else {
|
||||
if (chan[c.chan].insChanged) {
|
||||
|
|
@ -653,7 +702,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
}
|
||||
if (chan[c.chan].insChanged) {
|
||||
rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3));
|
||||
rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4));
|
||||
rWrite(chanOffs[c.chan]+ADDR_LRAF,(IS_REALLY_MUTED(c.chan)?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4));
|
||||
}
|
||||
chan[c.chan].insChanged=false;
|
||||
|
||||
|
|
@ -668,7 +717,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
if (c.chan>=5) {
|
||||
if (c.chan>=5 && c.chan<7) {
|
||||
chan[c.chan].dacSample=-1;
|
||||
if (dumpWrites) addWrite(0xffff0002,0);
|
||||
if (parent->song.brokenDACMode) {
|
||||
|
|
@ -706,7 +755,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[c.chan].state.alg][i]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -731,7 +780,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
} else {
|
||||
chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1);
|
||||
}
|
||||
rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4));
|
||||
rWrite(chanOffs[c.chan]+ADDR_LRAF,(IS_REALLY_MUTED(c.chan)?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_PITCH: {
|
||||
|
|
@ -763,6 +812,29 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
if (c.chan==7) {
|
||||
int destFreq=NOTE_PERIODIC(c.value2);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
if (chan[c.chan].baseFreq>=destFreq) {
|
||||
chan[c.chan].baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].baseFreq-=c.value;
|
||||
if (chan[c.chan].baseFreq<=destFreq) {
|
||||
chan[c.chan].baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
}
|
||||
chan[c.chan].freqChanged=true;
|
||||
if (return2) {
|
||||
chan[c.chan].inPorta=false;
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) {
|
||||
int destFreq=parent->calcBaseFreq(1,1,c.value2,false);
|
||||
bool return2=false;
|
||||
|
|
@ -809,7 +881,9 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) {
|
||||
if (c.chan==7) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
} else if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) {
|
||||
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
|
||||
} else {
|
||||
chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11);
|
||||
|
|
@ -847,7 +921,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[c.chan].state.alg][c.value]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -1038,7 +1112,7 @@ void DivPlatformGenesis::forceIns() {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -1051,7 +1125,7 @@ void DivPlatformGenesis::forceIns() {
|
|||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
|
||||
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
||||
rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
||||
if (chan[i].active) {
|
||||
chan[i].keyOn=true;
|
||||
chan[i].freqChanged=true;
|
||||
|
|
@ -1071,6 +1145,10 @@ void* DivPlatformGenesis::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformGenesis::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformGenesis::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
bool dacReady;
|
||||
bool dacDirection;
|
||||
unsigned char sampleBank;
|
||||
signed char dacOutput;
|
||||
void macroInit(DivInstrument* which) {
|
||||
std.init(which);
|
||||
pitch2=0;
|
||||
|
|
@ -85,7 +86,8 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
dacDelay(0),
|
||||
dacReady(true),
|
||||
dacDirection(false),
|
||||
sampleBank(0) {}
|
||||
sampleBank(0),
|
||||
dacOutput(0) {}
|
||||
};
|
||||
Channel chan[10];
|
||||
DivDispatchOscBuffer* oscBuf[10];
|
||||
|
|
@ -128,6 +130,7 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "genesisshared.h"
|
||||
|
||||
#define CHIP_DIVIDER 72
|
||||
#define CHIP_FREQBASE 9440540
|
||||
|
||||
int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
||||
|
|
@ -54,7 +55,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
rWrite(baseAddr+0x40,127);
|
||||
} else {
|
||||
if (opChan[ch].insChanged) {
|
||||
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127));
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127));
|
||||
}
|
||||
}
|
||||
if (opChan[ch].insChanged) {
|
||||
|
|
@ -92,7 +93,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
if (isOpMuted[ch]) {
|
||||
rWrite(baseAddr+0x40,127);
|
||||
} else {
|
||||
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127));
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -179,6 +180,11 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
rWrite(0x22,lfoValue);
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_FB: {
|
||||
chan[2].state.fb=c.value&7;
|
||||
rWrite(chanOffs[2]+ADDR_FB_ALG,(chan[2].state.alg&7)|(chan[2].state.fb<<3));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_MULT: { // TODO
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
|
|
@ -193,7 +199,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
if (isOpMuted[ch]) {
|
||||
rWrite(baseAddr+0x40,127);
|
||||
} else if (isOutput[chan[2].state.alg][c.value]) {
|
||||
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127));
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+0x40,op.tl);
|
||||
}
|
||||
|
|
@ -376,8 +382,8 @@ void DivPlatformGenesisExt::muteChannel(int ch, bool mute) {
|
|||
rWrite(baseAddr+0x40,127);
|
||||
immWrite(baseAddr+0x40,127);
|
||||
} else if (isOutput[chan[2].state.alg][ordch]) {
|
||||
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch-2].vol&0x7f))/127));
|
||||
immWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch-2].vol&0x7f))/127));
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127));
|
||||
immWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+0x40,op.tl);
|
||||
immWrite(baseAddr+0x40,op.tl);
|
||||
|
|
@ -441,9 +447,43 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
|
|||
opChan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
|
||||
if (extMode && softPCM) {
|
||||
if (chan[7].freqChanged) {
|
||||
chan[7].freq=parent->calcFreq(chan[7].baseFreq,chan[7].pitch,true,0,chan[7].pitch2,chipClock,CHIP_DIVIDER);
|
||||
if (chan[7].freq<1) chan[7].freq=1;
|
||||
if (chan[7].freq>1024) chan[7].freq=1024;
|
||||
int wf=0x400-chan[7].freq;
|
||||
immWrite(0x24,wf>>2);
|
||||
immWrite(0x25,wf&3);
|
||||
chan[7].freqChanged=false;
|
||||
}
|
||||
|
||||
if (chan[7].keyOff || chan[7].keyOn) {
|
||||
writeNoteOn=true;
|
||||
for (int i=0; i<4; i++) {
|
||||
writeMask|=opChan[i].active<<(4+i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (writeNoteOn) {
|
||||
if (chan[7].active) { // CSM
|
||||
writeMask^=0xf0;
|
||||
}
|
||||
immWrite(0x28,writeMask);
|
||||
}
|
||||
|
||||
if (extMode && softPCM) {
|
||||
if (chan[7].keyOn) {
|
||||
immWrite(0x27,0x81);
|
||||
chan[7].keyOn=false;
|
||||
}
|
||||
if (chan[7].keyOff) {
|
||||
immWrite(0x27,0x40);
|
||||
chan[7].keyOff=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformGenesisExt::forceIns() {
|
||||
|
|
@ -455,7 +495,7 @@ void DivPlatformGenesisExt::forceIns() {
|
|||
if (isOpMuted[j]) {
|
||||
rWrite(baseAddr+0x40,127);
|
||||
} else if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[j].vol&0x7f))/127));
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[j].vol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+0x40,op.tl);
|
||||
}
|
||||
|
|
@ -464,7 +504,7 @@ void DivPlatformGenesisExt::forceIns() {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -503,6 +543,12 @@ void* DivPlatformGenesisExt::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformGenesisExt::getChanMacroInt(int ch) {
|
||||
if (ch>=6) return &chan[ch-3].std;
|
||||
if (ch>=2) return NULL; // currently not implemented
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformGenesisExt::getOscBuffer(int ch) {
|
||||
if (ch>=6) return oscBuf[ch-3];
|
||||
if (ch<3) return oscBuf[ch];
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
|
|||
public:
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
void reset();
|
||||
void forceIns();
|
||||
|
|
|
|||
|
|
@ -297,6 +297,9 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
|||
chan[c.chan].active=true;
|
||||
WRITE_VOLUME(c.chan,(isMuted[c.chan]?0:(chan[c.chan].vol&127)));
|
||||
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY));
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
|
|
@ -421,6 +424,10 @@ void* DivPlatformLynx::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformLynx::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformLynx::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ class DivPlatformLynx: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ void DivPlatformMMC5::tick(bool sysTick) {
|
|||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
// ok, why are the volumes like that?
|
||||
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
|
||||
chan[i].outVol=VOL_SCALE_LINEAR_BROKEN(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15);
|
||||
if (chan[i].outVol<0) chan[i].outVol=0;
|
||||
rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6));
|
||||
}
|
||||
|
|
@ -241,6 +241,9 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
|
|||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
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;
|
||||
}
|
||||
rWrite(0x5000+c.chan*4,0x30|chan[c.chan].vol|((chan[c.chan].duty&3)<<6));
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
|
|
@ -350,6 +353,10 @@ void* DivPlatformMMC5::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformMMC5::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformMMC5::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ class DivPlatformMMC5: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -31,50 +31,73 @@ const char** DivPlatformMSM6258::getRegisterSheet() {
|
|||
}
|
||||
|
||||
const char* DivPlatformMSM6258::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x20:
|
||||
return "20xx: Set frequency divider (0-2)";
|
||||
break;
|
||||
case 0x21:
|
||||
return "21xx: Select clock rate (0: full; 1: half)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformMSM6258::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
short* outs[2]={
|
||||
&msmOut,
|
||||
NULL
|
||||
};
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
short* outs[2]={
|
||||
&bufL[h],
|
||||
NULL
|
||||
};
|
||||
if (!writes.empty()) {
|
||||
QueuedWrite& w=writes.front();
|
||||
switch (w.addr) {
|
||||
case 0:
|
||||
msm->ctrl_w(w.val);
|
||||
break;
|
||||
}
|
||||
writes.pop();
|
||||
}
|
||||
|
||||
if (sample>=0 && sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(sample);
|
||||
unsigned char nextData=(s->dataVOX[samplePos]>>4)|(s->dataVOX[samplePos]<<4);
|
||||
if (msm->data_w(nextData)) {
|
||||
samplePos++;
|
||||
if (samplePos>=(int)s->lengthVOX) {
|
||||
sample=-1;
|
||||
samplePos=0;
|
||||
msm->ctrl_w(1);
|
||||
if (--msmClockCount<0) {
|
||||
if (--msmDividerCount<=0) {
|
||||
if (!writes.empty()) {
|
||||
QueuedWrite& w=writes.front();
|
||||
switch (w.addr) {
|
||||
case 0:
|
||||
msm->ctrl_w(w.val);
|
||||
break;
|
||||
case 2:
|
||||
msmPan=w.val;
|
||||
break;
|
||||
case 8:
|
||||
msmClock=w.val;
|
||||
break;
|
||||
case 12:
|
||||
msmDivider=4-(w.val&3);
|
||||
if (msmDivider<2) msmDivider=2;
|
||||
break;
|
||||
}
|
||||
writes.pop();
|
||||
}
|
||||
|
||||
if (sample>=0 && sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(sample);
|
||||
unsigned char nextData=(s->dataVOX[samplePos]>>4)|(s->dataVOX[samplePos]<<4);
|
||||
if (msm->data_w(nextData)) {
|
||||
samplePos++;
|
||||
if (samplePos>=(int)s->lengthVOX) {
|
||||
sample=-1;
|
||||
samplePos=0;
|
||||
msm->ctrl_w(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msm->sound_stream_update(outs,1);
|
||||
msmDividerCount=msmDivider;
|
||||
}
|
||||
msmClockCount=msmClock;
|
||||
}
|
||||
|
||||
msm->sound_stream_update(outs,1);
|
||||
if (isMuted[0]) {
|
||||
bufL[h]=0;
|
||||
bufR[h]=0;
|
||||
oscBuf[0]->data[oscBuf[0]->needle++]=0;
|
||||
} else {
|
||||
bufL[h]=(msmPan&2)?msmOut:0;
|
||||
bufR[h]=(msmPan&1)?msmOut:0;
|
||||
oscBuf[0]->data[oscBuf[0]->needle++]=msmPan?msmOut:0;
|
||||
}
|
||||
|
||||
/*if (++updateOsc>=22) {
|
||||
updateOsc=0;
|
||||
// TODO: per-channel osc
|
||||
for (int i=0; i<1; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=msm->m_voice[i].m_muted?0:(msm->m_voice[i].m_out<<6);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -176,6 +199,23 @@ int DivPlatformMSM6258::dispatch(DivCommand c) {
|
|||
sampleBank=parent->song.sample.size()/12;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_FREQ:
|
||||
rateSel=c.value&3;
|
||||
rWrite(12,rateSel);
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_MODE:
|
||||
clockSel=c.value&1;
|
||||
rWrite(8,clockSel);
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
if (c.value==0 && c.value2==0) {
|
||||
chan[c.chan].pan=3;
|
||||
} else {
|
||||
chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1);
|
||||
}
|
||||
rWrite(2,chan[c.chan].pan);
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
break;
|
||||
}
|
||||
|
|
@ -205,12 +245,19 @@ void DivPlatformMSM6258::forceIns() {
|
|||
for (int i=0; i<1; i++) {
|
||||
chan[i].insChanged=true;
|
||||
}
|
||||
rWrite(12,rateSel);
|
||||
rWrite(8,clockSel);
|
||||
rWrite(2,chan[0].pan);
|
||||
}
|
||||
|
||||
void* DivPlatformMSM6258::getChanState(int ch) {
|
||||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformMSM6258::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformMSM6258::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
@ -234,6 +281,14 @@ void DivPlatformMSM6258::poke(std::vector<DivRegWrite>& wlist) {
|
|||
void DivPlatformMSM6258::reset() {
|
||||
while (!writes.empty()) writes.pop();
|
||||
msm->device_reset();
|
||||
msmClock=chipClock;
|
||||
msmDivider=2;
|
||||
msmDividerCount=0;
|
||||
msmClock=0;
|
||||
msmClockCount=0;
|
||||
msmPan=3;
|
||||
rateSel=2;
|
||||
clockSel=0;
|
||||
if (dumpWrites) {
|
||||
addWrite(0xffffffff,0);
|
||||
}
|
||||
|
|
@ -253,6 +308,10 @@ void DivPlatformMSM6258::reset() {
|
|||
delay=0;
|
||||
}
|
||||
|
||||
bool DivPlatformMSM6258::isStereo() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DivPlatformMSM6258::keyOffAffectsArp(int ch) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -307,15 +366,23 @@ void DivPlatformMSM6258::renderSamples() {
|
|||
}
|
||||
|
||||
void DivPlatformMSM6258::setFlags(unsigned int flags) {
|
||||
if (flags&1) {
|
||||
chipClock=4096000;
|
||||
} else {
|
||||
chipClock=4000000;
|
||||
switch (flags) {
|
||||
case 3:
|
||||
chipClock=8192000;
|
||||
break;
|
||||
case 2:
|
||||
chipClock=8000000;
|
||||
break;
|
||||
case 1:
|
||||
chipClock=4096000;
|
||||
break;
|
||||
default:
|
||||
chipClock=4000000;
|
||||
break;
|
||||
}
|
||||
rate=chipClock/256;
|
||||
rate=chipClock/128;
|
||||
for (int i=0; i<1; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]->rate=rate/256;
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,9 @@ class DivPlatformMSM6258: public DivDispatch {
|
|||
|
||||
unsigned char* adpcmMem;
|
||||
size_t adpcmMemLen;
|
||||
unsigned char sampleBank;
|
||||
unsigned char sampleBank, msmPan, msmDivider, rateSel, msmClock, clockSel;
|
||||
signed char msmDividerCount, msmClockCount;
|
||||
short msmOut;
|
||||
|
||||
int delay, updateOsc, sample, samplePos;
|
||||
|
||||
|
|
@ -102,6 +104,7 @@ class DivPlatformMSM6258: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
@ -109,6 +112,7 @@ class DivPlatformMSM6258: public DivDispatch {
|
|||
void forceIns();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool isStereo();
|
||||
bool keyOffAffectsArp(int ch);
|
||||
void notifyInsChange(int ins);
|
||||
void notifyInsDeletion(void* ins);
|
||||
|
|
|
|||
|
|
@ -23,13 +23,18 @@
|
|||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#define rWrite(v) if (!skipRegisterWrites) {writes.emplace(0,v); if (dumpWrites) {addWrite(0,v);} }
|
||||
#define rWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
|
||||
|
||||
const char** DivPlatformMSM6295::getRegisterSheet() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* DivPlatformMSM6295::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x20:
|
||||
return "20xx: Set chip output rate (0: clock/132; 1: clock/165)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -42,7 +47,28 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t
|
|||
if (delay<=0) {
|
||||
if (!writes.empty()) {
|
||||
QueuedWrite& w=writes.front();
|
||||
msm->command_w(w.val);
|
||||
switch (w.addr) {
|
||||
case 0: // command
|
||||
msm->command_w(w.val);
|
||||
break;
|
||||
case 8: // chip clock select (VGM)
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
break;
|
||||
case 12: // rate select
|
||||
msm->ss_w(!w.val);
|
||||
break;
|
||||
case 14: // enable bankswitch
|
||||
break;
|
||||
case 15: // set bank base
|
||||
break;
|
||||
case 16: // switch bank
|
||||
case 17:
|
||||
case 18:
|
||||
case 19:
|
||||
break;
|
||||
}
|
||||
writes.pop();
|
||||
delay=32;
|
||||
}
|
||||
|
|
@ -92,9 +118,9 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
rWrite((8<<c.chan)); // turn off
|
||||
rWrite(0x80|chan[c.chan].sample); // set phrase
|
||||
rWrite((16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
|
||||
rWrite(0,(8<<c.chan)); // turn off
|
||||
rWrite(0,0x80|chan[c.chan].sample); // set phrase
|
||||
rWrite(0,(16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
|
@ -107,9 +133,9 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
|
|||
}
|
||||
//DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||
chan[c.chan].sample=12*sampleBank+c.value%12;
|
||||
rWrite((8<<c.chan)); // turn off
|
||||
rWrite(0x80|chan[c.chan].sample); // set phrase
|
||||
rWrite((16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
|
||||
rWrite(0,(8<<c.chan)); // turn off
|
||||
rWrite(0,0x80|chan[c.chan].sample); // set phrase
|
||||
rWrite(0,(16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -117,14 +143,14 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
|
|||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
rWrite((8<<c.chan)); // turn off
|
||||
rWrite(0,(8<<c.chan)); // turn off
|
||||
chan[c.chan].macroInit(NULL);
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
rWrite((8<<c.chan)); // turn off
|
||||
rWrite(0,(8<<c.chan)); // turn off
|
||||
chan[c.chan].std.release();
|
||||
break;
|
||||
case DIV_CMD_ENV_RELEASE:
|
||||
|
|
@ -153,6 +179,10 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
|
|||
case DIV_CMD_NOTE_PORTA: {
|
||||
return 2;
|
||||
}
|
||||
case DIV_CMD_SAMPLE_FREQ:
|
||||
rateSel=c.value;
|
||||
rWrite(12,!rateSel);
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_BANK:
|
||||
sampleBank=c.value;
|
||||
if (sampleBank>(parent->song.sample.size()/12)) {
|
||||
|
|
@ -190,12 +220,17 @@ void DivPlatformMSM6295::forceIns() {
|
|||
for (int i=0; i<4; i++) {
|
||||
chan[i].insChanged=true;
|
||||
}
|
||||
rWrite(12,!rateSel);
|
||||
}
|
||||
|
||||
void* DivPlatformMSM6295::getChanState(int ch) {
|
||||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformMSM6295::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformMSM6295::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
@ -219,6 +254,7 @@ void DivPlatformMSM6295::poke(std::vector<DivRegWrite>& wlist) {
|
|||
void DivPlatformMSM6295::reset() {
|
||||
while (!writes.empty()) writes.pop();
|
||||
msm->reset();
|
||||
msm->ss_w(false);
|
||||
if (dumpWrites) {
|
||||
addWrite(0xffffffff,0);
|
||||
}
|
||||
|
|
@ -232,6 +268,7 @@ void DivPlatformMSM6295::reset() {
|
|||
}
|
||||
|
||||
sampleBank=0;
|
||||
rateSel=false;
|
||||
|
||||
delay=0;
|
||||
}
|
||||
|
|
@ -240,6 +277,10 @@ bool DivPlatformMSM6295::keyOffAffectsArp(int ch) {
|
|||
return false;
|
||||
}
|
||||
|
||||
float DivPlatformMSM6295::getPostAmp() {
|
||||
return 3.0f;
|
||||
}
|
||||
|
||||
void DivPlatformMSM6295::notifyInsChange(int ins) {
|
||||
for (int i=0; i<4; i++) {
|
||||
if (chan[i].ins==ins) {
|
||||
|
|
@ -302,14 +343,52 @@ void DivPlatformMSM6295::renderSamples() {
|
|||
}
|
||||
|
||||
void DivPlatformMSM6295::setFlags(unsigned int flags) {
|
||||
if (flags&1) {
|
||||
chipClock=8448000;
|
||||
} else {
|
||||
chipClock=8000000;
|
||||
switch (flags) {
|
||||
case 0:
|
||||
chipClock=4000000/4;
|
||||
break;
|
||||
case 1:
|
||||
chipClock=4224000/4;
|
||||
break;
|
||||
case 2:
|
||||
chipClock=4000000;
|
||||
break;
|
||||
case 3:
|
||||
chipClock=4224000;
|
||||
break;
|
||||
case 4:
|
||||
chipClock=COLOR_NTSC;
|
||||
break;
|
||||
case 5:
|
||||
chipClock=COLOR_NTSC/2.0;
|
||||
break;
|
||||
case 6:
|
||||
chipClock=COLOR_NTSC*2.0/7.0;
|
||||
break;
|
||||
case 7:
|
||||
chipClock=COLOR_NTSC/4.0;
|
||||
break;
|
||||
case 8:
|
||||
chipClock=4000000/2;
|
||||
break;
|
||||
case 9:
|
||||
chipClock=4224000/2;
|
||||
break;
|
||||
case 10:
|
||||
chipClock=875000;
|
||||
break;
|
||||
case 11:
|
||||
chipClock=937500;
|
||||
break;
|
||||
case 12:
|
||||
chipClock=1500000;
|
||||
break;
|
||||
default:
|
||||
chipClock=4000000/4;
|
||||
break;
|
||||
}
|
||||
rate=chipClock/((flags&2)?6:24);
|
||||
rate=chipClock/3;
|
||||
for (int i=0; i<4; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]->rate=rate/22;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ class DivPlatformMSM6295: public DivDispatch {
|
|||
int delay, updateOsc;
|
||||
|
||||
bool extMode;
|
||||
bool rateSel;
|
||||
|
||||
short oldWrites[512];
|
||||
short pendingWrites[512];
|
||||
|
|
@ -111,6 +112,7 @@ class DivPlatformMSM6295: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
@ -119,6 +121,7 @@ class DivPlatformMSM6295: public DivDispatch {
|
|||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool keyOffAffectsArp(int ch);
|
||||
float getPostAmp();
|
||||
void notifyInsChange(int ins);
|
||||
void notifyInsDeletion(void* ins);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
|
|
|
|||
|
|
@ -625,6 +625,10 @@ void* DivPlatformN163::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformN163::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformN163::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ class DivPlatformN163: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -349,6 +349,9 @@ int DivPlatformNamcoWSG::dispatch(DivCommand c) {
|
|||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
if (chan[c.chan].wave<0) {
|
||||
chan[c.chan].wave=0;
|
||||
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
|
||||
|
|
@ -464,6 +467,10 @@ void* DivPlatformNamcoWSG::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformNamcoWSG::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformNamcoWSG::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ class DivPlatformNamcoWSG: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ void DivPlatformNES::tick(bool sysTick) {
|
|||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
// ok, why are the volumes like that?
|
||||
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
|
||||
chan[i].outVol=VOL_SCALE_LINEAR_BROKEN(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15);
|
||||
if (chan[i].outVol<0) chan[i].outVol=0;
|
||||
if (i==2) { // triangle
|
||||
rWrite(0x4000+i*4,(chan[i].outVol==0)?0:255);
|
||||
|
|
@ -446,6 +446,9 @@ int DivPlatformNES::dispatch(DivCommand c) {
|
|||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
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;
|
||||
}
|
||||
if (c.chan==2) {
|
||||
rWrite(0x4000+c.chan*4,0xff);
|
||||
} else {
|
||||
|
|
@ -607,6 +610,10 @@ void* DivPlatformNES::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformNES::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformNES::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ class DivPlatformNES: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -342,7 +342,7 @@ void DivPlatformOPL::tick(bool sysTick) {
|
|||
chan[i].std.next();
|
||||
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=(chan[i].vol*MIN(63,chan[i].std.vol.val))/63;
|
||||
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(63,chan[i].std.vol.val),63);
|
||||
for (int j=0; j<ops; j++) {
|
||||
unsigned char slot=slots[j][i];
|
||||
if (slot==255) continue;
|
||||
|
|
@ -353,7 +353,7 @@ void DivPlatformOPL::tick(bool sysTick) {
|
|||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
} else {
|
||||
if (isOutputL[ops==4][chan[i].state.alg][j] || i>melodicChans) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[i].outVol&0x3f))/63))|(op.ksl<<6));
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[i].outVol&0x3f,63))|(op.ksl<<6));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
|
||||
}
|
||||
|
|
@ -480,7 +480,7 @@ void DivPlatformOPL::tick(bool sysTick) {
|
|||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
} else {
|
||||
if (isOutputL[ops==4][chan[i].state.alg][j] || i>melodicChans) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[i].outVol&0x3f))/63))|(op.ksl<<6));
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[i].outVol&0x3f,63))|(op.ksl<<6));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
|
||||
}
|
||||
|
|
@ -689,7 +689,7 @@ void DivPlatformOPL::muteChannel(int ch, bool mute) {
|
|||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
} else {
|
||||
if (isOutputL[ops==4][chan[ch].state.alg][i] || ch>melodicChans) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[ch].outVol&0x3f))/63))|(op.ksl<<6));
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[ch].outVol&0x3f,63))|(op.ksl<<6));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
|
||||
}
|
||||
|
|
@ -784,10 +784,23 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPL);
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,c.chan>melodicChans?DIV_INS_OPL_DRUMS:DIV_INS_OPL);
|
||||
|
||||
if (chan[c.chan].insChanged) {
|
||||
chan[c.chan].state=ins->fm;
|
||||
if (c.chan>melodicChans && ins->type==DIV_INS_OPL_DRUMS) {
|
||||
for (int i=0; i<4; i++) {
|
||||
chan[melodicChans+i+1].state.alg=ins->fm.alg;
|
||||
chan[melodicChans+i+1].state.fb=ins->fm.fb;
|
||||
chan[melodicChans+i+1].state.opllPreset=ins->fm.opllPreset;
|
||||
chan[melodicChans+i+1].state.fixedDrums=ins->fm.fixedDrums;
|
||||
chan[melodicChans+i+1].state.kickFreq=ins->fm.kickFreq;
|
||||
chan[melodicChans+i+1].state.snareHatFreq=ins->fm.snareHatFreq;
|
||||
chan[melodicChans+i+1].state.tomTopFreq=ins->fm.tomTopFreq;
|
||||
chan[melodicChans+i+1].state.op[0]=ins->fm.op[i];
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].state=ins->fm;
|
||||
}
|
||||
}
|
||||
|
||||
chan[c.chan].macroInit(ins);
|
||||
|
|
@ -795,49 +808,81 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
if (chan[c.chan].insChanged) {
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
chan[c.chan].fourOp=(ops==4);
|
||||
if (chan[c.chan].fourOp) {
|
||||
chan[c.chan+1].macroInit(NULL);
|
||||
}
|
||||
update4OpMask=true;
|
||||
for (int i=0; i<ops; i++) {
|
||||
unsigned char slot=slots[i][c.chan];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[i]:i];
|
||||
if (c.chan>melodicChans && ins->type==DIV_INS_OPL_DRUMS) {
|
||||
for (int i=0; i<4; i++) {
|
||||
int ch=melodicChans+1+i;
|
||||
unsigned char slot=slots[0][ch];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[ch].state.op[0];
|
||||
chan[ch].fourOp=false;
|
||||
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
} else {
|
||||
if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6));
|
||||
if (isMuted[ch]) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[ch].outVol&0x3f,63))|(op.ksl<<6));
|
||||
}
|
||||
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
|
||||
if (oplType>1) {
|
||||
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
|
||||
}
|
||||
|
||||
if (isMuted[ch]) {
|
||||
oldWrites[chanMap[ch]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1));
|
||||
} else {
|
||||
oldWrites[chanMap[ch]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1)|((chan[ch].pan&3)<<4));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
chan[c.chan].fourOp=(ops==4);
|
||||
if (chan[c.chan].fourOp) {
|
||||
chan[c.chan+1].macroInit(NULL);
|
||||
}
|
||||
update4OpMask=true;
|
||||
for (int i=0; i<ops; i++) {
|
||||
unsigned char slot=slots[i][c.chan];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[i]:i];
|
||||
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
} else {
|
||||
if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
|
||||
}
|
||||
}
|
||||
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
|
||||
if (oplType>1) {
|
||||
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
|
||||
}
|
||||
}
|
||||
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
|
||||
if (oplType>1) {
|
||||
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
|
||||
}
|
||||
}
|
||||
|
||||
if (isMuted[c.chan]) {
|
||||
oldWrites[chanMap[c.chan]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&1)|(chan[c.chan].state.fb<<1));
|
||||
if (ops==4) {
|
||||
oldWrites[chanMap[c.chan+1]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[c.chan+1]+ADDR_LR_FB_ALG,((chan[c.chan].state.alg>>1)&1)|(chan[c.chan].state.fb<<1));
|
||||
}
|
||||
} else {
|
||||
oldWrites[chanMap[c.chan]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&1)|(chan[c.chan].state.fb<<1)|((chan[c.chan].pan&3)<<4));
|
||||
if (ops==4) {
|
||||
oldWrites[chanMap[c.chan+1]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[c.chan+1]+ADDR_LR_FB_ALG,((chan[c.chan].state.alg>>1)&1)|(chan[c.chan].state.fb<<1)|((chan[c.chan].pan&3)<<4));
|
||||
if (isMuted[c.chan]) {
|
||||
oldWrites[chanMap[c.chan]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&1)|(chan[c.chan].state.fb<<1));
|
||||
if (ops==4) {
|
||||
oldWrites[chanMap[c.chan+1]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[c.chan+1]+ADDR_LR_FB_ALG,((chan[c.chan].state.alg>>1)&1)|(chan[c.chan].state.fb<<1));
|
||||
}
|
||||
} else {
|
||||
oldWrites[chanMap[c.chan]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&1)|(chan[c.chan].state.fb<<1)|((chan[c.chan].pan&3)<<4));
|
||||
if (ops==4) {
|
||||
oldWrites[chanMap[c.chan+1]+ADDR_LR_FB_ALG]=-1;
|
||||
rWrite(chanMap[c.chan+1]+ADDR_LR_FB_ALG,((chan[c.chan].state.alg>>1)&1)|(chan[c.chan].state.fb<<1)|((chan[c.chan].pan&3)<<4));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -845,20 +890,32 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
chan[c.chan].insChanged=false;
|
||||
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
if (c.chan>=melodicChans && chan[c.chan].state.opllPreset==16 && chan[c.chan].state.fixedDrums) { // drums
|
||||
if (c.chan==melodicChans) {
|
||||
chan[c.chan].fixedFreq=(chan[c.chan].state.kickFreq&1023)<<(chan[c.chan].state.kickFreq>>10);
|
||||
} else if (c.chan==melodicChans+1 || c.chan==melodicChans+4) {
|
||||
chan[c.chan].fixedFreq=(chan[c.chan].state.snareHatFreq&1023)<<(chan[c.chan].state.snareHatFreq>>10);
|
||||
} else if (c.chan==melodicChans+2 || c.chan==melodicChans+3) {
|
||||
chan[c.chan].fixedFreq=(chan[c.chan].state.tomTopFreq&1023)<<(chan[c.chan].state.tomTopFreq>>10);
|
||||
if (c.chan>melodicChans && ins->type==DIV_INS_OPL_DRUMS && chan[c.chan].state.fixedDrums) {
|
||||
chan[melodicChans+1].fixedFreq=(chan[melodicChans+1].state.snareHatFreq&1023)<<(chan[melodicChans+1].state.snareHatFreq>>10);
|
||||
chan[melodicChans+2].fixedFreq=(chan[melodicChans+2].state.tomTopFreq&1023)<<(chan[melodicChans+2].state.tomTopFreq>>10);
|
||||
chan[melodicChans+3].fixedFreq=chan[melodicChans+2].fixedFreq;
|
||||
chan[melodicChans+4].fixedFreq=chan[melodicChans+1].fixedFreq;
|
||||
|
||||
chan[melodicChans+1].freqChanged=true;
|
||||
chan[melodicChans+2].freqChanged=true;
|
||||
chan[melodicChans+3].freqChanged=true;
|
||||
chan[melodicChans+4].freqChanged=true;
|
||||
} else {
|
||||
if (c.chan>=melodicChans && (chan[c.chan].state.opllPreset==16 || ins->type==DIV_INS_OPL_DRUMS) && chan[c.chan].state.fixedDrums) { // drums
|
||||
if (c.chan==melodicChans) {
|
||||
chan[c.chan].fixedFreq=(chan[c.chan].state.kickFreq&1023)<<(chan[c.chan].state.kickFreq>>10);
|
||||
} else if (c.chan==melodicChans+1 || c.chan==melodicChans+4) {
|
||||
chan[c.chan].fixedFreq=(chan[c.chan].state.snareHatFreq&1023)<<(chan[c.chan].state.snareHatFreq>>10);
|
||||
} else if (c.chan==melodicChans+2 || c.chan==melodicChans+3) {
|
||||
chan[c.chan].fixedFreq=(chan[c.chan].state.tomTopFreq&1023)<<(chan[c.chan].state.tomTopFreq>>10);
|
||||
} else {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
chan[c.chan].fixedFreq=0;
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
chan[c.chan].fixedFreq=0;
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
chan[c.chan].fixedFreq=0;
|
||||
}
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
|
@ -914,7 +971,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
} else {
|
||||
if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6));
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
|
||||
}
|
||||
|
|
@ -1063,7 +1120,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
} else {
|
||||
if (isOutputL[ops==4][chan[c.chan].state.alg][c.value] || c.chan>melodicChans) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6));
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
|
||||
}
|
||||
|
|
@ -1293,7 +1350,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
} else {
|
||||
if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6));
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
|
||||
}
|
||||
|
|
@ -1310,7 +1367,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
} else {
|
||||
if (isOutputL[ops==4][chan[c.chan].state.alg][c.value] || c.chan>melodicChans) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6));
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
|
||||
}
|
||||
|
|
@ -1384,7 +1441,7 @@ void DivPlatformOPL::forceIns() {
|
|||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
} else {
|
||||
if (isOutputL[ops==4][chan[i].state.alg][j] || i>melodicChans) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[i].outVol&0x3f))/63))|(op.ksl<<6));
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[i].outVol&0x3f,63))|(op.ksl<<6));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
|
||||
}
|
||||
|
|
@ -1426,6 +1483,10 @@ void* DivPlatformOPL::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformOPL::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformOPL::getOscBuffer(int ch) {
|
||||
if (ch>=18) return NULL;
|
||||
return oscBuf[ch];
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ class DivPlatformOPL: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -149,9 +149,9 @@ void DivPlatformOPLL::tick(bool sysTick) {
|
|||
chan[i].std.next();
|
||||
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=(chan[i].vol*MIN(15,chan[i].std.vol.val))/15;
|
||||
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(15,chan[i].std.vol.val),15);
|
||||
if (i<9) {
|
||||
rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4));
|
||||
rWrite(0x30+i,((15-VOL_SCALE_LOG(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -174,7 +174,7 @@ void DivPlatformOPLL::tick(bool sysTick) {
|
|||
if (chan[i].std.wave.had && chan[i].state.opllPreset!=16) {
|
||||
chan[i].state.opllPreset=chan[i].std.wave.val;
|
||||
if (i<9) {
|
||||
rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4));
|
||||
rWrite(0x30+i,((15-VOL_SCALE_LOG(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -244,7 +244,7 @@ void DivPlatformOPLL::tick(bool sysTick) {
|
|||
op.tl=((j==1)?15:63)-m.tl.val;
|
||||
if (j==1) {
|
||||
if (i<9) {
|
||||
rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4));
|
||||
rWrite(0x30+i,((15-VOL_SCALE_LOG(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4));
|
||||
}
|
||||
} else {
|
||||
rWrite(0x02,(chan[i].state.op[0].ksl<<6)|(op.tl&63));
|
||||
|
|
@ -384,21 +384,6 @@ int DivPlatformOPLL::toFreq(int freq) {
|
|||
|
||||
void DivPlatformOPLL::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
/*
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[ch]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[ch].state.op[j];
|
||||
if (isMuted[ch]) {
|
||||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[ch].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[ch].outVol&0x7f))/127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
}
|
||||
}
|
||||
rWrite(chanOffs[ch]+ADDR_LRAF,(isMuted[ch]?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4));*/
|
||||
}
|
||||
|
||||
int DivPlatformOPLL::dispatch(DivCommand c) {
|
||||
|
|
@ -483,7 +468,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
}
|
||||
}
|
||||
if (c.chan<9) {
|
||||
rWrite(0x30+c.chan,((15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15)&15)|(chan[c.chan].state.opllPreset<<4));
|
||||
rWrite(0x30+c.chan,((15-VOL_SCALE_LOG(chan[c.chan].outVol,15-chan[c.chan].state.op[1].tl,15))&15)|(chan[c.chan].state.opllPreset<<4));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -553,7 +538,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
break;
|
||||
} else if (c.chan<6 || !drums) {
|
||||
if (c.chan<9) {
|
||||
rWrite(0x30+c.chan,((15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15)&15)|(chan[c.chan].state.opllPreset<<4));
|
||||
rWrite(0x30+c.chan,((15-VOL_SCALE_LOG(chan[c.chan].outVol,15-chan[c.chan].state.op[1].tl,15))&15)|(chan[c.chan].state.opllPreset<<4));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -647,7 +632,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
DivInstrumentFM::Operator& car=chan[c.chan].state.op[1];
|
||||
car.tl=c.value2&15;
|
||||
if (c.chan<9) {
|
||||
rWrite(0x30+c.chan,((15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15)&15)|(chan[c.chan].state.opllPreset<<4));
|
||||
rWrite(0x30+c.chan,((15-VOL_SCALE_LOG(chan[c.chan].outVol,15-chan[c.chan].state.op[1].tl,15))&15)|(chan[c.chan].state.opllPreset<<4));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -862,7 +847,7 @@ void DivPlatformOPLL::forceIns() {
|
|||
rWrite(0x07,(car.sl<<4)|(car.rr));
|
||||
}
|
||||
if (i<9) {
|
||||
rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4));
|
||||
rWrite(0x30+i,((15-VOL_SCALE_LOG(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4));
|
||||
}
|
||||
if (!(i>=6 && properDrums)) {
|
||||
if (chan[i].active) {
|
||||
|
|
@ -911,6 +896,10 @@ void* DivPlatformOPLL::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformOPLL::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformOPLL::getOscBuffer(int ch) {
|
||||
if (ch>=9) return NULL;
|
||||
return oscBuf[ch];
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ class DivPlatformOPLL: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ void DivPlatformPCE::tick(bool sysTick) {
|
|||
for (int i=0; i<6; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=((chan[i].vol&31)*MIN(31,chan[i].std.vol.val))>>5;
|
||||
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol&31,MIN(31,chan[i].std.vol.val),31);
|
||||
if (chan[i].furnaceDac && chan[i].pcm) {
|
||||
// ignore for now
|
||||
} else {
|
||||
|
|
@ -328,6 +328,9 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
chan[c.chan].keyOn=true;
|
||||
chWrite(c.chan,0x04,0x80|chan[c.chan].vol);
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
if (chan[c.chan].wave<0) {
|
||||
chan[c.chan].wave=0;
|
||||
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
|
||||
|
|
@ -474,6 +477,10 @@ void* DivPlatformPCE::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformPCE::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformPCE::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ class DivPlatformPCE: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "pcspkr.h"
|
||||
#include "../engine.h"
|
||||
#include "../../ta-log.h"
|
||||
#include <math.h>
|
||||
|
||||
#ifdef __linux__
|
||||
|
|
@ -28,6 +29,8 @@
|
|||
#include <unistd.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/kd.h>
|
||||
#include <time.h>
|
||||
#include <sys/io.h>
|
||||
#endif
|
||||
|
||||
#define PCSPKR_DIVIDER 4
|
||||
|
|
@ -38,6 +41,137 @@ const char* regCheatSheetPCSpeaker[]={
|
|||
NULL
|
||||
};
|
||||
|
||||
void _pcSpeakerThread(void* inst) {
|
||||
((DivPlatformPCSpeaker*)inst)->pcSpeakerThread();
|
||||
}
|
||||
|
||||
void DivPlatformPCSpeaker::pcSpeakerThread() {
|
||||
std::unique_lock<std::mutex> unique(realOutSelfLock);
|
||||
RealQueueVal r(0,0,0);
|
||||
logD("starting PC speaker out thread");
|
||||
while (!realOutQuit) {
|
||||
realQueueLock.lock();
|
||||
if (realQueue.empty()) {
|
||||
realQueueLock.unlock();
|
||||
realOutCond.wait(unique);
|
||||
continue;
|
||||
} else {
|
||||
r=realQueue.front();
|
||||
realQueue.pop();
|
||||
}
|
||||
realQueueLock.unlock();
|
||||
#ifdef __linux__
|
||||
static struct timespec ts, tSleep, rSleep;
|
||||
if (clock_gettime(CLOCK_MONOTONIC,&ts)<0) {
|
||||
logW("could not get time!");
|
||||
tSleep.tv_sec=0;
|
||||
tSleep.tv_nsec=0;
|
||||
} else {
|
||||
tSleep.tv_sec=r.tv_sec-ts.tv_sec;
|
||||
tSleep.tv_nsec=r.tv_nsec-ts.tv_nsec;
|
||||
if (tSleep.tv_nsec<0) {
|
||||
tSleep.tv_sec--;
|
||||
tSleep.tv_nsec+=1000000000;
|
||||
}
|
||||
}
|
||||
|
||||
if (tSleep.tv_nsec>0 || tSleep.tv_sec>0) {
|
||||
nanosleep(&tSleep,&rSleep);
|
||||
}
|
||||
if (beepFD>=0) {
|
||||
switch (realOutMethod) {
|
||||
case 0: { // evdev
|
||||
static struct input_event ie;
|
||||
ie.time.tv_sec=r.tv_sec;
|
||||
ie.time.tv_usec=r.tv_nsec/1000;
|
||||
ie.type=EV_SND;
|
||||
ie.code=SND_TONE;
|
||||
if (r.val>0) {
|
||||
ie.value=chipClock/r.val;
|
||||
} else {
|
||||
ie.value=0;
|
||||
}
|
||||
if (write(beepFD,&ie,sizeof(struct input_event))<0) {
|
||||
logW("error while writing frequency! %s",strerror(errno));
|
||||
} else {
|
||||
//logV("writing freq: %d",r.val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: // KIOCSOUND (on tty)
|
||||
if (ioctl(beepFD,KIOCSOUND,r.val)<0) {
|
||||
logW("ioctl error! %s",strerror(errno));
|
||||
}
|
||||
break;
|
||||
case 2: { // /dev/port
|
||||
unsigned char bOut;
|
||||
bOut=0;
|
||||
if (r.val==0) {
|
||||
lseek(beepFD,0x61,SEEK_SET);
|
||||
if (read(beepFD,&bOut,1)<1) {
|
||||
logW("read from 0x61: %s",strerror(errno));
|
||||
}
|
||||
bOut&=(~3);
|
||||
lseek(beepFD,0x61,SEEK_SET);
|
||||
if (write(beepFD,&bOut,1)<1) {
|
||||
logW("write to 0x61: %s",strerror(errno));
|
||||
}
|
||||
} else {
|
||||
lseek(beepFD,0x43,SEEK_SET);
|
||||
bOut=0xb6;
|
||||
if (write(beepFD,&bOut,1)<1) {
|
||||
logW("write to 0x43: %s",strerror(errno));
|
||||
}
|
||||
lseek(beepFD,0x42,SEEK_SET);
|
||||
bOut=r.val&0xff;
|
||||
if (write(beepFD,&bOut,1)<1) {
|
||||
logW("write to 0x42: %s",strerror(errno));
|
||||
}
|
||||
lseek(beepFD,0x42,SEEK_SET);
|
||||
bOut=r.val>>8;
|
||||
if (write(beepFD,&bOut,1)<1) {
|
||||
logW("write to 0x42: %s",strerror(errno));
|
||||
}
|
||||
lseek(beepFD,0x61,SEEK_SET);
|
||||
if (read(beepFD,&bOut,1)<1) {
|
||||
logW("read from 0x61: %s",strerror(errno));
|
||||
}
|
||||
bOut|=3;
|
||||
lseek(beepFD,0x61,SEEK_SET);
|
||||
if (write(beepFD,&bOut,1)<1) {
|
||||
logW("write to 0x61: %s",strerror(errno));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: // KIOCSOUND (on stdout)
|
||||
if (ioctl(beepFD,KIOCSOUND,r.val)<0) {
|
||||
logW("ioctl error! %s",strerror(errno));
|
||||
}
|
||||
break;
|
||||
case 4: // outb()
|
||||
if (r.val==0) {
|
||||
outb(inb(0x61)&(~3),0x61);
|
||||
realOutEnabled=false;
|
||||
} else {
|
||||
outb(0xb6,0x43);
|
||||
outb(r.val&0xff,0x42);
|
||||
outb(r.val>>8,0x42);
|
||||
if (!realOutEnabled) {
|
||||
outb(inb(0x61)|3,0x61);
|
||||
realOutEnabled=true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
//logV("not writing because fd is less than 0");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
logD("stopping PC speaker out thread");
|
||||
}
|
||||
|
||||
const char** DivPlatformPCSpeaker::getRegisterSheet() {
|
||||
return regCheatSheetPCSpeaker;
|
||||
}
|
||||
|
|
@ -126,25 +260,28 @@ void DivPlatformPCSpeaker::acquire_piezo(short* bufL, short* bufR, size_t start,
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformPCSpeaker::beepFreq(int freq) {
|
||||
void DivPlatformPCSpeaker::beepFreq(int freq, int delay) {
|
||||
realQueueLock.lock();
|
||||
#ifdef __linux__
|
||||
static struct input_event ie;
|
||||
if (beepFD>=0) {
|
||||
gettimeofday(&ie.time,NULL);
|
||||
ie.type=EV_SND;
|
||||
ie.code=SND_TONE;
|
||||
if (freq>0) {
|
||||
ie.value=chipClock/freq;
|
||||
} else {
|
||||
ie.value=0;
|
||||
}
|
||||
if (write(beepFD,&ie,sizeof(struct input_event))<0) {
|
||||
perror("error while writing frequency!");
|
||||
} else {
|
||||
//printf("writing freq: %d\n",freq);
|
||||
struct timespec ts;
|
||||
double addition=1000000000.0*(double)delay/(double)rate;
|
||||
addition+=1500000000.0*((double)parent->getAudioDescGot().bufsize/parent->getAudioDescGot().rate);
|
||||
if (clock_gettime(CLOCK_MONOTONIC,&ts)<0) {
|
||||
ts.tv_sec=0;
|
||||
ts.tv_nsec=0;
|
||||
} else {
|
||||
ts.tv_nsec+=addition;
|
||||
while (ts.tv_nsec>=1000000000) {
|
||||
ts.tv_sec++;
|
||||
ts.tv_nsec-=1000000000;
|
||||
}
|
||||
}
|
||||
realQueue.push(RealQueueVal(ts.tv_sec,ts.tv_nsec,freq));
|
||||
#else
|
||||
realQueue.push(RealQueueVal(0,0,freq));
|
||||
#endif
|
||||
realQueueLock.unlock();
|
||||
realOutCond.notify_one();
|
||||
}
|
||||
|
||||
void DivPlatformPCSpeaker::acquire_real(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
|
|
@ -152,7 +289,7 @@ void DivPlatformPCSpeaker::acquire_real(short* bufL, short* bufR, size_t start,
|
|||
if (lastOn!=on || lastFreq!=freq) {
|
||||
lastOn=on;
|
||||
lastFreq=freq;
|
||||
beepFreq((on && !isMuted[0])?freq:0);
|
||||
beepFreq((on && !isMuted[0])?freq:0,start);
|
||||
}
|
||||
for (size_t i=start; i<start+len; i++) {
|
||||
if (on) {
|
||||
|
|
@ -251,6 +388,9 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) {
|
|||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
chan[c.chan].active=false;
|
||||
|
|
@ -345,6 +485,10 @@ void* DivPlatformPCSpeaker::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformPCSpeaker::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformPCSpeaker::getOscBuffer(int ch) {
|
||||
return oscBuf;
|
||||
}
|
||||
|
|
@ -382,18 +526,51 @@ void DivPlatformPCSpeaker::reset() {
|
|||
low=0;
|
||||
band=0;
|
||||
|
||||
if (speakerType==3) {
|
||||
//if (speakerType==3) {
|
||||
#ifdef __linux__
|
||||
if (beepFD==-1) {
|
||||
beepFD=open("/dev/input/by-path/platform-pcspkr-event-spkr",O_WRONLY);
|
||||
switch (realOutMethod) {
|
||||
case 0: // evdev
|
||||
beepFD=open("/dev/input/by-path/platform-pcspkr-event-spkr",O_WRONLY);
|
||||
break;
|
||||
case 1: // KIOCSOUND (on tty)
|
||||
beepFD=open("/dev/tty1",O_WRONLY);
|
||||
break;
|
||||
case 2: // /dev/port
|
||||
beepFD=open("/dev/port",O_WRONLY);
|
||||
break;
|
||||
case 3: // KIOCSOUND (on stdout)
|
||||
beepFD=STDOUT_FILENO;
|
||||
break;
|
||||
case 4: // outb()
|
||||
beepFD=-1;
|
||||
if (ioperm(0x61,8,1)<0) {
|
||||
logW("ioperm 0x61: %s",strerror(errno));
|
||||
break;
|
||||
}
|
||||
if (ioperm(0x43,8,1)<0) {
|
||||
logW("ioperm 0x43: %s",strerror(errno));
|
||||
break;
|
||||
}
|
||||
if (ioperm(0x42,8,1)<0) {
|
||||
logW("ioperm 0x42: %s",strerror(errno));
|
||||
break;
|
||||
}
|
||||
beepFD=STDOUT_FILENO;
|
||||
break;
|
||||
}
|
||||
if (beepFD<0) {
|
||||
perror("error while opening PC speaker");
|
||||
logW("error while opening PC speaker! %s",strerror(errno));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
beepFreq(0);
|
||||
} else {
|
||||
/*} else {
|
||||
beepFreq(0);
|
||||
}*/
|
||||
|
||||
if (realOutThread==NULL) {
|
||||
realOutThread=new std::thread(_pcSpeakerThread,this);
|
||||
}
|
||||
|
||||
memset(regPool,0,2);
|
||||
|
|
@ -433,6 +610,10 @@ int DivPlatformPCSpeaker::init(DivEngine* p, int channels, int sugRate, unsigned
|
|||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
beepFD=-1;
|
||||
realOutQuit=false;
|
||||
realOutThread=NULL;
|
||||
realOutMethod=parent->getConfInt("pcSpeakerOutMethod",0);
|
||||
realOutEnabled=false;
|
||||
for (int i=0; i<1; i++) {
|
||||
isMuted[i]=false;
|
||||
}
|
||||
|
|
@ -447,8 +628,14 @@ void DivPlatformPCSpeaker::quit() {
|
|||
if (speakerType==3) {
|
||||
beepFreq(0);
|
||||
}
|
||||
if (realOutThread!=NULL) {
|
||||
realOutQuit=true;
|
||||
realOutCond.notify_one();
|
||||
realOutThread->join();
|
||||
delete realOutThread;
|
||||
}
|
||||
#ifdef __linux__
|
||||
if (beepFD>=0) close(beepFD);
|
||||
if (beepFD>=0 && realOutMethod<3) close(beepFD);
|
||||
#endif
|
||||
delete oscBuf;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@
|
|||
|
||||
#include "../dispatch.h"
|
||||
#include "../macroInt.h"
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
class DivPlatformPCSpeaker: public DivDispatch {
|
||||
struct Channel {
|
||||
|
|
@ -57,9 +61,23 @@ class DivPlatformPCSpeaker: public DivDispatch {
|
|||
};
|
||||
Channel chan[1];
|
||||
DivDispatchOscBuffer* oscBuf;
|
||||
std::thread* realOutThread;
|
||||
std::mutex realOutSelfLock;
|
||||
std::condition_variable realOutCond;
|
||||
bool realOutQuit;
|
||||
struct RealQueueVal {
|
||||
int tv_sec, tv_nsec;
|
||||
unsigned short val;
|
||||
RealQueueVal(int sec, int nsec, unsigned short v):
|
||||
tv_sec(sec),
|
||||
tv_nsec(nsec),
|
||||
val(v) {}
|
||||
};
|
||||
std::queue<RealQueueVal> realQueue;
|
||||
std::mutex realQueueLock;
|
||||
bool isMuted[1];
|
||||
bool on, flip, lastOn;
|
||||
int pos, speakerType, beepFD;
|
||||
bool on, flip, lastOn, realOutEnabled;
|
||||
int pos, speakerType, beepFD, realOutMethod;
|
||||
float low, band;
|
||||
float low2, high2, band2;
|
||||
float low3, band3;
|
||||
|
|
@ -68,7 +86,7 @@ class DivPlatformPCSpeaker: public DivDispatch {
|
|||
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
||||
void beepFreq(int freq);
|
||||
void beepFreq(int freq, int delay=0);
|
||||
|
||||
void acquire_unfilt(short* bufL, short* bufR, size_t start, size_t len);
|
||||
void acquire_cone(short* bufL, short* bufR, size_t start, size_t len);
|
||||
|
|
@ -76,9 +94,11 @@ class DivPlatformPCSpeaker: public DivDispatch {
|
|||
void acquire_real(short* bufL, short* bufR, size_t start, size_t len);
|
||||
|
||||
public:
|
||||
void pcSpeakerThread();
|
||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -149,6 +149,9 @@ int DivPlatformPET::dispatch(DivCommand c) {
|
|||
chan.active=true;
|
||||
chan.keyOn=true;
|
||||
chan.macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan.std.vol.will) {
|
||||
chan.outVol=chan.vol;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
|
|
@ -246,6 +249,10 @@ void* DivPlatformPET::getChanState(int ch) {
|
|||
return &chan;
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformPET::getChanMacroInt(int ch) {
|
||||
return &chan.std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformPET::getOscBuffer(int ch) {
|
||||
return oscBuf;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ class DivPlatformPET: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -404,6 +404,9 @@ int DivPlatformQSound::dispatch(DivCommand c) {
|
|||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
|
|
@ -527,6 +530,10 @@ void* DivPlatformQSound::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformQSound::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformQSound::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ class DivPlatformQSound: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -189,6 +189,9 @@ int DivPlatformRF5C68::dispatch(DivCommand c) {
|
|||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
|
|
@ -297,6 +300,10 @@ void* DivPlatformRF5C68::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformRF5C68::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformRF5C68::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ class DivPlatformRF5C68: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ void DivPlatformSAA1099::tick(bool sysTick) {
|
|||
for (int i=0; i<6; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
|
||||
chan[i].outVol=VOL_SCALE_LINEAR_BROKEN(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15);
|
||||
if (chan[i].outVol<0) chan[i].outVol=0;
|
||||
if (isMuted[i]) {
|
||||
rWrite(i,0);
|
||||
|
|
@ -264,6 +264,9 @@ int DivPlatformSAA1099::dispatch(DivCommand c) {
|
|||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(c.chan,0);
|
||||
} else {
|
||||
|
|
@ -398,6 +401,10 @@ void* DivPlatformSAA1099::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformSAA1099::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformSAA1099::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ class DivPlatformSAA1099: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -184,6 +184,9 @@ int DivPlatformSCC::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
if (!isMuted[c.chan]) {
|
||||
rWrite(regBase+15,regPool[regBase+15]|(1<<c.chan));
|
||||
}
|
||||
|
|
@ -307,6 +310,10 @@ void* DivPlatformSCC::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformSCC::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformSCC::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ class DivPlatformSCC: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
// TODO: new macro formula
|
||||
#include "segapcm.h"
|
||||
#include "../engine.h"
|
||||
#include <string.h>
|
||||
|
|
@ -84,10 +85,17 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
|
|||
for (int i=0; i<16; i++) {
|
||||
chan[i].std.next();
|
||||
|
||||
// TODO: fix
|
||||
/*if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
|
||||
}*/
|
||||
if (parent->song.newSegaPCM) {
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=(chan[i].vol*MIN(64,chan[i].std.vol.val))>>6;
|
||||
chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127;
|
||||
chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127;
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10002+(i<<3),chan[i].chVolL);
|
||||
addWrite(0x10003+(i<<3),chan[i].chVolR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
|
|
@ -106,14 +114,24 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
|
|||
}
|
||||
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].chVolL=chan[i].std.panL.val&127;
|
||||
if (parent->song.newSegaPCM) {
|
||||
chan[i].chPanL=chan[i].std.panL.val&127;
|
||||
chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127;
|
||||
} else {
|
||||
chan[i].chVolL=chan[i].std.panL.val&127;
|
||||
}
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10002+(i<<3),chan[i].chVolL);
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.panR.had) {
|
||||
chan[i].chVolR=chan[i].std.panR.val&127;
|
||||
if (parent->song.newSegaPCM) {
|
||||
chan[i].chPanR=chan[i].std.panR.val&127;
|
||||
chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127;
|
||||
} else {
|
||||
chan[i].chVolR=chan[i].std.panR.val&127;
|
||||
}
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10003+(i<<3),chan[i].chVolR);
|
||||
}
|
||||
|
|
@ -169,6 +187,9 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
addWrite(0x10086+(c.chan<<3),3);
|
||||
}
|
||||
chan[c.chan].macroInit(NULL);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
break;
|
||||
}
|
||||
chan[c.chan].pcm.pos=0;
|
||||
|
|
@ -257,8 +278,13 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
if (!chan[c.chan].std.vol.has) {
|
||||
chan[c.chan].outVol=c.value;
|
||||
}
|
||||
chan[c.chan].chVolL=c.value;
|
||||
chan[c.chan].chVolR=c.value;
|
||||
if (parent->song.newSegaPCM) {
|
||||
chan[c.chan].chVolL=(c.value*chan[c.chan].chPanL)/127;
|
||||
chan[c.chan].chVolR=(c.value*chan[c.chan].chPanR)/127;
|
||||
} else {
|
||||
chan[c.chan].chVolL=c.value;
|
||||
chan[c.chan].chVolR=c.value;
|
||||
}
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10002+(c.chan<<3),chan[c.chan].chVolL);
|
||||
addWrite(0x10003+(c.chan<<3),chan[c.chan].chVolR);
|
||||
|
|
@ -276,8 +302,15 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
chan[c.chan].ins=c.value;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
chan[c.chan].chVolL=c.value>>1;
|
||||
chan[c.chan].chVolR=c.value2>>1;
|
||||
if (parent->song.newSegaPCM) {
|
||||
chan[c.chan].chPanL=c.value>>1;
|
||||
chan[c.chan].chPanR=c.value2>>1;
|
||||
chan[c.chan].chVolL=(chan[c.chan].outVol*chan[c.chan].chPanL)/127;
|
||||
chan[c.chan].chVolR=(chan[c.chan].outVol*chan[c.chan].chPanR)/127;
|
||||
} else {
|
||||
chan[c.chan].chVolL=c.value>>1;
|
||||
chan[c.chan].chVolR=c.value2>>1;
|
||||
}
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10002+(c.chan<<3),chan[c.chan].chVolL);
|
||||
addWrite(0x10003+(c.chan<<3),chan[c.chan].chVolR);
|
||||
|
|
@ -367,6 +400,10 @@ void* DivPlatformSegaPCM::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformSegaPCM::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformSegaPCM::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ class DivPlatformSegaPCM: public DivDispatch {
|
|||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM;
|
||||
int vol, outVol;
|
||||
unsigned char chVolL, chVolR;
|
||||
unsigned char chPanL, chPanR;
|
||||
|
||||
struct PCMChannel {
|
||||
int sample;
|
||||
|
|
@ -46,7 +47,29 @@ class DivPlatformSegaPCM: public DivDispatch {
|
|||
std.init(which);
|
||||
pitch2=0;
|
||||
}
|
||||
Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), note(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), inPorta(false), portaPause(false), furnacePCM(false), vol(0), outVol(0), chVolL(127), chVolR(127) {}
|
||||
Channel():
|
||||
freqH(0),
|
||||
freqL(0),
|
||||
freq(0),
|
||||
baseFreq(0),
|
||||
pitch(0),
|
||||
pitch2(0),
|
||||
note(0),
|
||||
ins(-1),
|
||||
active(false),
|
||||
insChanged(true),
|
||||
freqChanged(false),
|
||||
keyOn(false),
|
||||
keyOff(false),
|
||||
inPorta(false),
|
||||
portaPause(false),
|
||||
furnacePCM(false),
|
||||
vol(0),
|
||||
outVol(0),
|
||||
chVolL(127),
|
||||
chVolR(127),
|
||||
chPanL(127),
|
||||
chPanR(127) {}
|
||||
};
|
||||
Channel chan[16];
|
||||
DivDispatchOscBuffer* oscBuf[16];
|
||||
|
|
@ -78,6 +101,7 @@ class DivPlatformSegaPCM: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -69,14 +69,13 @@ void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_
|
|||
if (o<-32768) o=-32768;
|
||||
if (o>32767) o=32767;
|
||||
bufL[h]=o;
|
||||
/*
|
||||
for (int i=0; i<4; i++) {
|
||||
if (isMuted[i]) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=0;
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=sn->get_channel_output(i);
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=sn_nuked.vol_table[sn_nuked.volume_out[i]];
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -245,6 +244,9 @@ int DivPlatformSMS::dispatch(DivCommand c) {
|
|||
chan[c.chan].active=true;
|
||||
rWrite(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;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
chan[c.chan].active=false;
|
||||
|
|
@ -316,6 +318,8 @@ int DivPlatformSMS::dispatch(DivCommand c) {
|
|||
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
// TODO: pre porta cancel arp compat flag
|
||||
//if (chan[c.chan].inPorta) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
|
||||
break;
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
return 15;
|
||||
|
|
@ -348,6 +352,10 @@ void* DivPlatformSMS::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformSMS::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformSMS::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ class DivPlatformSMS: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
void reset();
|
||||
void forceIns();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
License: BSD-3-Clause
|
||||
see https://github.com/cam900/vgsound_emu/LICENSE for more details
|
||||
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
|
||||
|
||||
Copyright holder(s): cam900
|
||||
Modifiers and Contributors for Furnace: cam900
|
||||
Konami K005289 emulation core
|
||||
|
||||
This chip is used at infamous Konami Bubble System, for part of Wavetable sound generator.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
License: BSD-3-Clause
|
||||
see https://github.com/cam900/vgsound_emu/LICENSE for more details
|
||||
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
|
||||
|
||||
Copyright holder(s): cam900
|
||||
Modifiers and Contributors for Furnace: cam900
|
||||
Konami K005289 emulation core
|
||||
|
||||
See k005289.cpp for more info.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
License: BSD-3-Clause
|
||||
see https://github.com/cam900/vgsound_emu/LICENSE for more details
|
||||
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
|
||||
|
||||
Copyright holder(s): cam900
|
||||
Modifiers and Contributors for Furnace: cam900, tildearrow
|
||||
Namco 163 Sound emulation core
|
||||
|
||||
This chip is one of NES mapper with sound expansion, This one is by Namco.
|
||||
|
|
@ -99,7 +100,7 @@ void n163_core::tick()
|
|||
m_ram[m_voice_cycle + 3] = bitfield(accum, 8, 8);
|
||||
m_ram[m_voice_cycle + 5] = bitfield(accum, 16, 8);
|
||||
|
||||
const u8 prev_voice_cycle = m_voice_cycle;
|
||||
const u8 prev_voice_cycle = m_voice_cycle;
|
||||
|
||||
// update voice cycle
|
||||
bool flush = m_multiplex ? true : false;
|
||||
|
|
@ -112,8 +113,8 @@ void n163_core::tick()
|
|||
}
|
||||
|
||||
// output 4 bit waveform and volume, multiplexed
|
||||
const u8 chan_index = ((0x78-prev_voice_cycle)>>3)&7;
|
||||
m_ch_out[chan_index]=wave * volume;
|
||||
const u8 chan_index = ((0x78-prev_voice_cycle)>>3)&7;
|
||||
m_ch_out[chan_index]=wave * volume;
|
||||
m_acc += m_ch_out[chan_index];
|
||||
if (flush)
|
||||
{
|
||||
|
|
@ -127,12 +128,12 @@ void n163_core::reset()
|
|||
// reset this chip
|
||||
m_disable = false;
|
||||
m_multiplex = true;
|
||||
memset(m_ram,0,sizeof(m_ram));
|
||||
memset(m_ram,0,sizeof(m_ram));
|
||||
m_voice_cycle = 0x78;
|
||||
m_addr_latch.reset();
|
||||
m_out = 0;
|
||||
m_acc = 0;
|
||||
memset(m_ch_out,0,sizeof(m_ch_out));
|
||||
memset(m_ch_out,0,sizeof(m_ch_out));
|
||||
}
|
||||
|
||||
// accessor
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
License: BSD-3-Clause
|
||||
see https://github.com/cam900/vgsound_emu/LICENSE for more details
|
||||
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
|
||||
|
||||
Copyright holder(s): cam900
|
||||
Modifiers and Contributors for Furnace: cam900, tildearrow
|
||||
Namco 163 Sound emulation core
|
||||
*/
|
||||
|
||||
|
|
@ -46,11 +47,11 @@ public:
|
|||
// sound output pin
|
||||
s16 out() { return m_out; }
|
||||
|
||||
// get channel output
|
||||
s16 chan_out(u8 ch) { return m_ch_out[ch]; }
|
||||
// get channel output
|
||||
s16 chan_out(u8 ch) { return m_ch_out[ch]; }
|
||||
|
||||
// get voice cycle
|
||||
u8 voice_cycle() { return m_voice_cycle; }
|
||||
// get voice cycle
|
||||
u8 voice_cycle() { return m_voice_cycle; }
|
||||
|
||||
// register pool
|
||||
u8 reg(u8 addr) { return m_ram[addr & 0x7f]; }
|
||||
|
|
@ -63,7 +64,7 @@ private:
|
|||
addr_latch_t()
|
||||
: addr(0)
|
||||
, incr(0)
|
||||
{ };
|
||||
{ }
|
||||
|
||||
void reset()
|
||||
{
|
||||
|
|
@ -80,7 +81,7 @@ private:
|
|||
u8 m_voice_cycle = 0x78; // Voice cycle for processing
|
||||
addr_latch_t m_addr_latch; // address latch
|
||||
s16 m_out = 0; // output
|
||||
s16 m_ch_out[8] = {0}; // per channel output
|
||||
s16 m_ch_out[8] = {0}; // per channel output
|
||||
// demultiplex related
|
||||
bool m_multiplex = true; // multiplex flag, but less noisy = inaccurate!
|
||||
s16 m_acc = 0; // accumulated output
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
License: BSD-3-Clause
|
||||
see https://github.com/cam900/vgsound_emu/blob/main/LICENSE for more details
|
||||
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
|
||||
|
||||
Copyright holder(s): cam900
|
||||
Modifiers and Contributors for Furnace: tildearrow
|
||||
OKI MSM6295 emulation core
|
||||
|
||||
It is 4 channel ADPCM playback chip from OKI semiconductor.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
License: BSD-3-Clause
|
||||
see https://github.com/cam900/vgsound_emu/blob/main/LICENSE for more details
|
||||
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
|
||||
|
||||
Copyright holder(s): cam900
|
||||
Modifiers and Contributors for Furnace: tildearrow
|
||||
OKI MSM6295 emulation core
|
||||
|
||||
See msm6295.cpp for more info.
|
||||
|
|
@ -71,7 +72,7 @@ public:
|
|||
msm6295_core &m_host;
|
||||
u16 m_clock = 0; // clock counter
|
||||
bool m_busy = false; // busy status
|
||||
bool m_muted = false; // muted
|
||||
bool m_muted = false; // muted
|
||||
u8 m_command = 0; // current command
|
||||
u32 m_addr = 0; // current address
|
||||
s8 m_nibble = 0; // current nibble
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
License: BSD-3-Clause
|
||||
see https://github.com/cam900/vgsound_emu/blob/main/LICENSE for more details
|
||||
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
|
||||
|
||||
Copyright holders: cam900
|
||||
Copyright holder(s): cam900
|
||||
Modifiers and Contributors for Furnace: tildearrow
|
||||
Various core utilities for vgsound_emu
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
License: BSD-3-Clause
|
||||
see https://github.com/cam900/vgsound_emu/blob/main/LICENSE for more details
|
||||
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
|
||||
|
||||
Copyright holder(s): cam900
|
||||
Modifiers and Contributors for Furnace: tildearrow
|
||||
Dialogic ADPCM core
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
/*
|
||||
License: BSD-3-Clause
|
||||
see https://github.com/cam900/vgsound_emu/LICENSE for more details
|
||||
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
|
||||
|
||||
Copyright holder(s): cam900
|
||||
Contributor(s): Natt Akuma, James Alan Nguyen, Laurens Holst
|
||||
Modifiers and Contributors for Furnace: Natt Akuma, tildearrow, Grauw
|
||||
Konami SCC emulation core
|
||||
|
||||
Konami SCC means "Sound Creative Chip", it's actually MSX MegaROM/RAM Mapper with 5 channel Wavetable sound generator.
|
||||
|
|
@ -373,12 +375,12 @@ void scc_core::reset()
|
|||
|
||||
m_test.reset();
|
||||
m_out = 0;
|
||||
memset(m_reg,0,sizeof(m_reg));
|
||||
memset(m_reg,0,sizeof(m_reg));
|
||||
}
|
||||
|
||||
void scc_core::voice_t::reset()
|
||||
{
|
||||
memset(wave,0,sizeof(wave));
|
||||
memset(wave,0,sizeof(wave));
|
||||
enable = false;
|
||||
pitch = 0;
|
||||
volume = 0;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
/*
|
||||
License: BSD-3-Clause
|
||||
see https://github.com/cam900/vgsound_emu/LICENSE for more details
|
||||
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
|
||||
|
||||
Copyright holder(s): cam900
|
||||
Contributor(s): Natt Akuma, James Alan Nguyen, Laurens Holst
|
||||
Modifiers and Contributors for Furnace: Natt Akuma, tildearrow, Grauw
|
||||
Konami SCC emulation core
|
||||
|
||||
See scc.cpp for more info.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
License: BSD-3-Clause
|
||||
see https://github.com/cam900/vgsound_emu/LICENSE for more details
|
||||
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
|
||||
|
||||
Copyright holder(s): cam900
|
||||
Modifiers and Contributors for Furnace: cam900, tildearrow
|
||||
Konami VRC VI sound emulation core
|
||||
|
||||
It's one of NES mapper with built-in sound chip, and also one of 2 Konami VRCs with this feature. (rest one has OPLL derivatives.)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
License: BSD-3-Clause
|
||||
see https://github.com/cam900/vgsound_emu/LICENSE for more details
|
||||
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
|
||||
|
||||
Copyright holder(s): cam900
|
||||
Modifiers and Contributors for Furnace: cam900, tildearrow
|
||||
Konami VRC VI sound emulation core
|
||||
|
||||
See vrcvi.cpp to more infos.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
License: BSD-3-Clause
|
||||
see https://github.com/cam900/vgsound_emu/LICENSE for more details
|
||||
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
|
||||
|
||||
Copyright holders: cam900
|
||||
Copyright holder(s): cam900
|
||||
Modifiers and Contributors for Furnace: cam900, tildearrow
|
||||
Seta/Allumer X1-010 Emulation core
|
||||
|
||||
the chip has 16 voices, all voices can be switchable to Wavetable or PCM sample playback mode.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
License: BSD-3-Clause
|
||||
see https://github.com/cam900/vgsound_emu/LICENSE for more details
|
||||
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
|
||||
|
||||
Copyright holders: cam900
|
||||
Copyright holder(s): cam900
|
||||
Modifiers and Contributors for Furnace: cam900, tildearrow
|
||||
Seta/Allumer X1-010 Emulation core
|
||||
|
||||
See x1_010.cpp for more info.
|
||||
|
|
@ -63,7 +64,7 @@ public:
|
|||
|
||||
// getters
|
||||
s32 output(u8 channel) { return m_out[channel & 1]; }
|
||||
s32 chan_out(u8 channel) { return (m_voice[channel].data * (m_voice[channel].vol_out[0]+m_voice[channel].vol_out[1]))<<2; }
|
||||
s32 chan_out(u8 channel) { return (m_voice[channel].data * (m_voice[channel].vol_out[0]+m_voice[channel].vol_out[1]))<<2; }
|
||||
|
||||
// internal state
|
||||
void reset();
|
||||
|
|
|
|||
|
|
@ -778,6 +778,10 @@ public:
|
|||
// get the engine
|
||||
fm_engine* debug_engine() { return &m_fm; }
|
||||
|
||||
// get DAC state
|
||||
uint16_t debug_dac_data() { return m_dac_data; }
|
||||
uint8_t debug_dac_enable() { return m_dac_enable; }
|
||||
|
||||
protected:
|
||||
// simulate the DAC discontinuity
|
||||
constexpr int32_t dac_discontinuity(int32_t value) const { return (value < 0) ? (value - 2) : (value + 3); }
|
||||
|
|
|
|||
|
|
@ -264,6 +264,9 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
|
|||
chan[c.chan].keyOn=true;
|
||||
chWrite(c.chan,0x02,chan[c.chan].vol);
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
chan[c.chan].insChanged=false;
|
||||
break;
|
||||
}
|
||||
|
|
@ -481,6 +484,10 @@ void* DivPlatformSoundUnit::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformSoundUnit::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformSoundUnit::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ class DivPlatformSoundUnit: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -313,6 +313,9 @@ int DivPlatformSwan::dispatch(DivCommand c) {
|
|||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
if (chan[c.chan].wave<0) {
|
||||
chan[c.chan].wave=0;
|
||||
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
|
||||
|
|
@ -461,6 +464,10 @@ void* DivPlatformSwan::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformSwan::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformSwan::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ class DivPlatformSwan: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ void DivPlatformTIA::tick(bool sysTick) {
|
|||
for (int i=0; i<2; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
|
||||
chan[i].outVol=VOL_SCALE_LINEAR_BROKEN(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15);
|
||||
if (chan[i].outVol<0) chan[i].outVol=0;
|
||||
if (isMuted[i]) {
|
||||
rWrite(0x19+i,0);
|
||||
|
|
@ -170,6 +170,9 @@ int DivPlatformTIA::dispatch(DivCommand c) {
|
|||
chan[c.chan].keyOn=true;
|
||||
rWrite(0x15+c.chan,chan[c.chan].shape);
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x19+c.chan,0);
|
||||
} else {
|
||||
|
|
@ -290,6 +293,10 @@ void* DivPlatformTIA::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformTIA::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformTIA::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ class DivPlatformTIA: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ void DivPlatformTX81Z::tick(bool sysTick) {
|
|||
chan[i].std.next();
|
||||
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
|
||||
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127);
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||
|
|
@ -278,7 +278,7 @@ void DivPlatformTX81Z::tick(bool sysTick) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -354,7 +354,7 @@ void DivPlatformTX81Z::tick(bool sysTick) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -407,7 +407,7 @@ void DivPlatformTX81Z::tick(bool sysTick) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -499,7 +499,7 @@ void DivPlatformTX81Z::muteChannel(int ch, bool mute) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[ch].state.alg][i]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[ch].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -529,7 +529,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
|
|||
} else {
|
||||
if (isOutput[chan[c.chan].state.alg][i]) {
|
||||
if (!chan[c.chan].active || chan[c.chan].insChanged) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
|
||||
}
|
||||
} else {
|
||||
if (chan[c.chan].insChanged) {
|
||||
|
|
@ -594,7 +594,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[c.chan].state.alg][i]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -694,7 +694,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[c.chan].state.alg][c.value]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -985,7 +985,7 @@ void DivPlatformTX81Z::forceIns() {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -1027,6 +1027,10 @@ void* DivPlatformTX81Z::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformTX81Z::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformTX81Z::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ class DivPlatformTX81Z: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -285,6 +285,9 @@ int DivPlatformVERA::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VERA));
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
chan[c.chan].active=false;
|
||||
|
|
@ -396,6 +399,10 @@ void* DivPlatformVERA::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformVERA::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformVERA::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ class DivPlatformVERA: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -278,6 +278,10 @@ void* DivPlatformVIC20::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformVIC20::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformVIC20::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ class DivPlatformVIC20: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -264,6 +264,9 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
//chan[c.chan].keyOn=true;
|
||||
chan[c.chan].furnaceDac=true;
|
||||
} else {
|
||||
|
|
@ -435,6 +438,10 @@ void* DivPlatformVRC6::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformVRC6::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformVRC6::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ class DivPlatformVRC6: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -609,6 +609,9 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
|
|||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].envChanged=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
if (chan[c.chan].wave<0) {
|
||||
chan[c.chan].wave=0;
|
||||
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
|
||||
|
|
@ -839,6 +842,10 @@ void* DivPlatformX1_010::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformX1_010::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformX1_010::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ class DivPlatformX1_010: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -338,7 +338,7 @@ void DivPlatformYM2203::tick(bool sysTick) {
|
|||
chan[i].std.next();
|
||||
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
|
||||
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127);
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||
|
|
@ -346,7 +346,7 @@ void DivPlatformYM2203::tick(bool sysTick) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -396,7 +396,7 @@ void DivPlatformYM2203::tick(bool sysTick) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -441,7 +441,7 @@ void DivPlatformYM2203::tick(bool sysTick) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -553,7 +553,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) {
|
|||
} else {
|
||||
if (isOutput[chan[c.chan].state.alg][i]) {
|
||||
if (!chan[c.chan].active || chan[c.chan].insChanged) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
|
||||
}
|
||||
} else {
|
||||
if (chan[c.chan].insChanged) {
|
||||
|
|
@ -612,7 +612,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[c.chan].state.alg][i]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -690,7 +690,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[c.chan].state.alg][c.value]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -882,7 +882,7 @@ void DivPlatformYM2203::muteChannel(int ch, bool mute) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[ch].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[ch].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -899,7 +899,7 @@ void DivPlatformYM2203::forceIns() {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -933,6 +933,11 @@ void* DivPlatformYM2203::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformYM2203::getChanMacroInt(int ch) {
|
||||
if (ch>=3) return ay->getChanMacroInt(ch-3);
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformYM2203::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ class DivPlatformYM2203: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) {
|
|||
rWrite(baseAddr+0x40,127);
|
||||
} else {
|
||||
if (opChan[ch].insChanged) {
|
||||
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127));
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127));
|
||||
}
|
||||
}
|
||||
if (opChan[ch].insChanged) {
|
||||
|
|
@ -84,7 +84,7 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) {
|
|||
if (isOpMuted[ch]) {
|
||||
rWrite(baseAddr+0x40,127);
|
||||
} else {
|
||||
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127));
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -155,6 +155,11 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) {
|
|||
rWrite(0x22,(c.value&7)|((c.value>>4)<<3));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_FB: {
|
||||
chan[2].state.fb=c.value&7;
|
||||
rWrite(chanOffs[2]+ADDR_FB_ALG,(chan[2].state.alg&7)|(chan[2].state.fb<<3));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_MULT: { // TODO
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
|
|
@ -411,7 +416,7 @@ void DivPlatformYM2203Ext::muteChannel(int ch, bool mute) {
|
|||
if (isOpMuted[ch-2]) {
|
||||
rWrite(baseAddr+0x40,127);
|
||||
} else if (isOutput[ins->fm.alg][ordch]) {
|
||||
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch-2].vol&0x7f))/127));
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+0x40,op.tl);
|
||||
}
|
||||
|
|
@ -426,7 +431,7 @@ void DivPlatformYM2203Ext::forceIns() {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -466,6 +471,12 @@ void* DivPlatformYM2203Ext::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformYM2203Ext::getChanMacroInt(int ch) {
|
||||
if (ch>=6) return ay->getChanMacroInt(ch-6);
|
||||
if (ch>=2) return NULL; // currently not implemented
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformYM2203Ext::getOscBuffer(int ch) {
|
||||
if (ch>=6) return oscBuf[ch-3];
|
||||
if (ch<3) return oscBuf[ch];
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class DivPlatformYM2203Ext: public DivPlatformYM2203 {
|
|||
public:
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
void reset();
|
||||
void forceIns();
|
||||
|
|
|
|||
|
|
@ -500,12 +500,12 @@ void DivPlatformYM2608::tick(bool sysTick) {
|
|||
chan[i].std.next();
|
||||
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
|
||||
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127);
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -559,7 +559,7 @@ void DivPlatformYM2608::tick(bool sysTick) {
|
|||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -609,7 +609,7 @@ void DivPlatformYM2608::tick(bool sysTick) {
|
|||
if (m.tl.had) {
|
||||
op.tl=127-m.tl.val;
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -836,7 +836,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
|||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
if (isOutput[chan[c.chan].state.alg][i]) {
|
||||
if (!chan[c.chan].active || chan[c.chan].insChanged) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
|
||||
}
|
||||
} else {
|
||||
if (chan[c.chan].insChanged) {
|
||||
|
|
@ -916,7 +916,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
|||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
if (isOutput[chan[c.chan].state.alg][i]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -1020,7 +1020,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
|||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.tl=c.value2;
|
||||
if (isOutput[chan[c.chan].state.alg][c.value]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -1223,7 +1223,7 @@ void DivPlatformYM2608::forceIns() {
|
|||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
}
|
||||
|
|
@ -1257,6 +1257,11 @@ void* DivPlatformYM2608::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformYM2608::getChanMacroInt(int ch) {
|
||||
if (ch>=6 && ch<9) return ay->getChanMacroInt(ch-6);
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformYM2608::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ class DivPlatformYM2608: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue