Merge branch 'master' of https://github.com/tildearrow/furnace into sample_macro
# Conflicts: # src/engine/fileOps.cpp # src/engine/platform/lynx.cpp # src/engine/platform/rf5c68.cpp # src/engine/platform/su.cpp # src/engine/platform/x1_010.h # src/engine/platform/ym2610.cpp # src/engine/platform/ym2610.h # src/engine/platform/ym2610b.cpp # src/engine/platform/ym2610b.h # src/engine/sysDef.cpp # src/gui/insEdit.cpp Add effect command for ADPCM-A global volume, X1-010 Sample bank slot
This commit is contained in:
commit
54dbd0690c
148 changed files with 4114 additions and 3610 deletions
|
|
@ -420,13 +420,6 @@ class DivDispatch {
|
|||
*/
|
||||
virtual bool getWantPreNote();
|
||||
|
||||
/**
|
||||
* get a description of a dispatch-specific effect.
|
||||
* @param effect the effect.
|
||||
* @return the description, or NULL if effect is invalid.
|
||||
*/
|
||||
virtual const char* getEffectName(unsigned char effect);
|
||||
|
||||
/**
|
||||
* set the chip flags.
|
||||
* @param flags the flags. see song.h for possible values.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "dispatch.h"
|
||||
#include "song.h"
|
||||
#define _USE_MATH_DEFINES
|
||||
#include "engine.h"
|
||||
#include "instrument.h"
|
||||
|
|
@ -124,8 +125,15 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
|
|||
if ((effect&0xf0)==0x90) {
|
||||
return "9xxx: Set sample offset*256";
|
||||
} else if (chan>=0 && chan<chans) {
|
||||
const char* ret=disCont[dispatchOfChan[chan]].dispatch->getEffectName(effect);
|
||||
if (ret!=NULL) return ret;
|
||||
DivSysDef* sysDef=sysDefs[sysOfChan[chan]];
|
||||
auto iter=sysDef->effectHandlers.find(effect);
|
||||
if (iter!=sysDef->effectHandlers.end()) {
|
||||
return iter->second.description;
|
||||
}
|
||||
iter=sysDef->postEffectHandlers.find(effect);
|
||||
if (iter!=sysDef->postEffectHandlers.end()) {
|
||||
return iter->second.description;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -1380,6 +1388,115 @@ bool DivEngine::removeSystem(int index, bool preserveOrder) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DivEngine::swapSystem(int src, int dest, bool preserveOrder) {
|
||||
if (src==dest) {
|
||||
lastError="source and destination are equal";
|
||||
return false;
|
||||
}
|
||||
if (src<0 || src>=song.systemLen) {
|
||||
lastError="invalid source index";
|
||||
return false;
|
||||
}
|
||||
if (dest<0 || dest>=song.systemLen) {
|
||||
lastError="invalid destination index";
|
||||
return false;
|
||||
}
|
||||
//int chanCount=chans;
|
||||
quitDispatch();
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
|
||||
if (!preserveOrder) {
|
||||
// move channels
|
||||
unsigned char unswappedChannels[DIV_MAX_CHANS];
|
||||
unsigned char swappedChannels[DIV_MAX_CHANS];
|
||||
std::vector<std::vector<int>> swapList;
|
||||
std::vector<int> chanList;
|
||||
|
||||
int tchans=0;
|
||||
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
tchans+=getChannelCount(song.system[i]);
|
||||
}
|
||||
|
||||
memset(unswappedChannels,0,DIV_MAX_CHANS);
|
||||
memset(swappedChannels,0,DIV_MAX_CHANS);
|
||||
|
||||
for (int i=0; i<tchans; i++) {
|
||||
unswappedChannels[i]=i;
|
||||
}
|
||||
|
||||
// prepare swap list
|
||||
int index=0;
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
chanList.clear();
|
||||
for (int j=0; j<getChannelCount(song.system[i]); j++) {
|
||||
chanList.push_back(index);
|
||||
index++;
|
||||
}
|
||||
swapList.push_back(chanList);
|
||||
}
|
||||
swapList[src].swap(swapList[dest]);
|
||||
|
||||
// unfold it
|
||||
index=0;
|
||||
for (std::vector<int>& i: swapList) {
|
||||
for (int& j: i) {
|
||||
swappedChannels[index++]=j;
|
||||
}
|
||||
}
|
||||
|
||||
logV("swap list:");
|
||||
for (int i=0; i<tchans; i++) {
|
||||
logV("- %d -> %d",unswappedChannels[i],swappedChannels[i]);
|
||||
}
|
||||
|
||||
// swap channels
|
||||
bool allComplete=false;
|
||||
while (!allComplete) {
|
||||
logD("doing swap...");
|
||||
allComplete=true;
|
||||
for (int i=0; i<tchans; i++) {
|
||||
if (unswappedChannels[i]!=swappedChannels[i]) {
|
||||
swapChannels(i,swappedChannels[i]);
|
||||
allComplete=false;
|
||||
logD("> %d -> %d",unswappedChannels[i],unswappedChannels[swappedChannels[i]]);
|
||||
unswappedChannels[i]^=unswappedChannels[swappedChannels[i]];
|
||||
unswappedChannels[swappedChannels[i]]^=unswappedChannels[i];
|
||||
unswappedChannels[i]^=unswappedChannels[swappedChannels[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DivSystem srcSystem=song.system[src];
|
||||
|
||||
song.system[src]=song.system[dest];
|
||||
song.system[dest]=srcSystem;
|
||||
|
||||
song.systemVol[src]^=song.systemVol[dest];
|
||||
song.systemVol[dest]^=song.systemVol[src];
|
||||
song.systemVol[src]^=song.systemVol[dest];
|
||||
|
||||
song.systemPan[src]^=song.systemPan[dest];
|
||||
song.systemPan[dest]^=song.systemPan[src];
|
||||
song.systemPan[src]^=song.systemPan[dest];
|
||||
|
||||
song.systemFlags[src]^=song.systemFlags[dest];
|
||||
song.systemFlags[dest]^=song.systemFlags[src];
|
||||
song.systemFlags[src]^=song.systemFlags[dest];
|
||||
|
||||
recalcChans();
|
||||
saveLock.unlock();
|
||||
BUSY_END;
|
||||
initDispatch();
|
||||
BUSY_BEGIN;
|
||||
renderSamples();
|
||||
reset();
|
||||
BUSY_END;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DivEngine::poke(int sys, unsigned int addr, unsigned short val) {
|
||||
if (sys<0 || sys>=song.systemLen) return;
|
||||
BUSY_BEGIN;
|
||||
|
|
@ -1655,6 +1772,15 @@ int DivEngine::calcFreq(int base, int pitch, bool period, int octave, int pitch2
|
|||
base+((pitch*octave)>>1)+pitch2;
|
||||
}
|
||||
|
||||
int DivEngine::calcArp(int note, int arp, int offset) {
|
||||
if (arp<0) {
|
||||
if (!(arp&0x40000000)) return (arp|0x40000000)+offset;
|
||||
} else {
|
||||
if (arp&0x40000000) return (arp&(~0x40000000))+offset;
|
||||
}
|
||||
return note+arp;
|
||||
}
|
||||
|
||||
int DivEngine::convertPanSplitToLinear(unsigned int val, unsigned char bits, int range) {
|
||||
int panL=val>>bits;
|
||||
int panR=val&((1<<bits)-1);
|
||||
|
|
@ -2192,11 +2318,13 @@ void DivEngine::delInstrument(int index) {
|
|||
song.ins.erase(song.ins.begin()+index);
|
||||
song.insLen=song.ins.size();
|
||||
for (int i=0; i<chans; i++) {
|
||||
for (int j=0; j<256; j++) {
|
||||
if (curPat[i].data[j]==NULL) continue;
|
||||
for (int k=0; k<curSubSong->patLen; k++) {
|
||||
if (curPat[i].data[j]->data[k][2]>index) {
|
||||
curPat[i].data[j]->data[k][2]--;
|
||||
for (size_t j=0; j<song.subsong.size(); j++) {
|
||||
for (int k=0; k<256; k++) {
|
||||
if (song.subsong[j]->pat[i].data[k]==NULL) continue;
|
||||
for (int l=0; l<song.subsong[j]->patLen; l++) {
|
||||
if (song.subsong[j]->pat[i].data[k]->data[l][2]>index) {
|
||||
song.subsong[j]->pat[i].data[k]->data[l][2]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2207,7 +2335,10 @@ void DivEngine::delInstrument(int index) {
|
|||
}
|
||||
|
||||
int DivEngine::addWave() {
|
||||
if (song.wave.size()>=256) return -1;
|
||||
if (song.wave.size()>=256) {
|
||||
lastError="too many wavetables!";
|
||||
return -1;
|
||||
}
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
DivWavetable* wave=new DivWavetable;
|
||||
|
|
@ -2219,50 +2350,62 @@ int DivEngine::addWave() {
|
|||
return waveCount;
|
||||
}
|
||||
|
||||
bool DivEngine::addWaveFromFile(const char* path, bool addRaw) {
|
||||
int DivEngine::addWavePtr(DivWavetable* which) {
|
||||
if (song.wave.size()>=256) {
|
||||
lastError="too many wavetables!";
|
||||
return false;
|
||||
delete which;
|
||||
return -1;
|
||||
}
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
int waveCount=(int)song.wave.size();
|
||||
song.wave.push_back(which);
|
||||
song.waveLen=waveCount+1;
|
||||
saveLock.unlock();
|
||||
BUSY_END;
|
||||
return song.waveLen;
|
||||
}
|
||||
|
||||
DivWavetable* DivEngine::waveFromFile(const char* path, bool addRaw) {
|
||||
FILE* f=ps_fopen(path,"rb");
|
||||
if (f==NULL) {
|
||||
lastError=fmt::sprintf("%s",strerror(errno));
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
unsigned char* buf;
|
||||
ssize_t len;
|
||||
if (fseek(f,0,SEEK_END)!=0) {
|
||||
fclose(f);
|
||||
lastError=fmt::sprintf("could not seek to end: %s",strerror(errno));
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
len=ftell(f);
|
||||
if (len<0) {
|
||||
fclose(f);
|
||||
lastError=fmt::sprintf("could not determine file size: %s",strerror(errno));
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
if (len==(SIZE_MAX>>1)) {
|
||||
fclose(f);
|
||||
lastError="file size is invalid!";
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
if (len==0) {
|
||||
fclose(f);
|
||||
lastError="file is empty";
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
if (fseek(f,0,SEEK_SET)!=0) {
|
||||
fclose(f);
|
||||
lastError=fmt::sprintf("could not seek to beginning: %s",strerror(errno));
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
buf=new unsigned char[len];
|
||||
if (fread(buf,1,len,f)!=(size_t)len) {
|
||||
logW("did not read entire wavetable file buffer!");
|
||||
delete[] buf;
|
||||
lastError=fmt::sprintf("could not read entire file: %s",strerror(errno));
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
|
|
@ -2290,7 +2433,7 @@ bool DivEngine::addWaveFromFile(const char* path, bool addRaw) {
|
|||
lastError="invalid wavetable header/data!";
|
||||
delete wave;
|
||||
delete[] buf;
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
|
|
@ -2331,7 +2474,7 @@ bool DivEngine::addWaveFromFile(const char* path, bool addRaw) {
|
|||
} else {
|
||||
delete wave;
|
||||
delete[] buf;
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} catch (EndOfFileException& e) {
|
||||
|
|
@ -2349,7 +2492,7 @@ bool DivEngine::addWaveFromFile(const char* path, bool addRaw) {
|
|||
} else {
|
||||
delete wave;
|
||||
delete[] buf;
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2357,17 +2500,10 @@ bool DivEngine::addWaveFromFile(const char* path, bool addRaw) {
|
|||
delete wave;
|
||||
delete[] buf;
|
||||
lastError="premature end of file";
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
int waveCount=(int)song.wave.size();
|
||||
song.wave.push_back(wave);
|
||||
song.waveLen=waveCount+1;
|
||||
saveLock.unlock();
|
||||
BUSY_END;
|
||||
return true;
|
||||
return wave;
|
||||
}
|
||||
|
||||
void DivEngine::delWave(int index) {
|
||||
|
|
@ -2383,7 +2519,10 @@ void DivEngine::delWave(int index) {
|
|||
}
|
||||
|
||||
int DivEngine::addSample() {
|
||||
if (song.sample.size()>=256) return -1;
|
||||
if (song.sample.size()>=256) {
|
||||
lastError="too many samples!";
|
||||
return -1;
|
||||
}
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
DivSample* sample=new DivSample;
|
||||
|
|
@ -2400,11 +2539,28 @@ int DivEngine::addSample() {
|
|||
return sampleCount;
|
||||
}
|
||||
|
||||
int DivEngine::addSampleFromFile(const char* path) {
|
||||
int DivEngine::addSamplePtr(DivSample* which) {
|
||||
if (song.sample.size()>=256) {
|
||||
lastError="too many samples!";
|
||||
delete which;
|
||||
return -1;
|
||||
}
|
||||
int sampleCount=(int)song.sample.size();
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
song.sample.push_back(which);
|
||||
song.sampleLen=sampleCount+1;
|
||||
saveLock.unlock();
|
||||
renderSamples();
|
||||
BUSY_END;
|
||||
return sampleCount;
|
||||
}
|
||||
|
||||
DivSample* DivEngine::sampleFromFile(const char* path) {
|
||||
if (song.sample.size()>=256) {
|
||||
lastError="too many samples!";
|
||||
return NULL;
|
||||
}
|
||||
BUSY_BEGIN;
|
||||
warnings="";
|
||||
|
||||
|
|
@ -2437,7 +2593,6 @@ int DivEngine::addSampleFromFile(const char* path) {
|
|||
if (extS==".dmc") { // read as .dmc
|
||||
size_t len=0;
|
||||
DivSample* sample=new DivSample;
|
||||
int sampleCount=(int)song.sample.size();
|
||||
sample->name=stripPath;
|
||||
|
||||
FILE* f=ps_fopen(path,"rb");
|
||||
|
|
@ -2445,7 +2600,7 @@ int DivEngine::addSampleFromFile(const char* path) {
|
|||
BUSY_END;
|
||||
lastError=fmt::sprintf("could not open file! (%s)",strerror(errno));
|
||||
delete sample;
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fseek(f,0,SEEK_END)<0) {
|
||||
|
|
@ -2453,7 +2608,7 @@ int DivEngine::addSampleFromFile(const char* path) {
|
|||
BUSY_END;
|
||||
lastError=fmt::sprintf("could not get file length! (%s)",strerror(errno));
|
||||
delete sample;
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len=ftell(f);
|
||||
|
|
@ -2463,7 +2618,7 @@ int DivEngine::addSampleFromFile(const char* path) {
|
|||
BUSY_END;
|
||||
lastError="file is empty!";
|
||||
delete sample;
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (len==(SIZE_MAX>>1)) {
|
||||
|
|
@ -2471,7 +2626,7 @@ int DivEngine::addSampleFromFile(const char* path) {
|
|||
BUSY_END;
|
||||
lastError="file is invalid!";
|
||||
delete sample;
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fseek(f,0,SEEK_SET)<0) {
|
||||
|
|
@ -2479,7 +2634,7 @@ int DivEngine::addSampleFromFile(const char* path) {
|
|||
BUSY_END;
|
||||
lastError=fmt::sprintf("could not seek to beginning of file! (%s)",strerror(errno));
|
||||
delete sample;
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sample->rate=33144;
|
||||
|
|
@ -2492,22 +2647,16 @@ int DivEngine::addSampleFromFile(const char* path) {
|
|||
BUSY_END;
|
||||
lastError=fmt::sprintf("could not read file! (%s)",strerror(errno));
|
||||
delete sample;
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
saveLock.lock();
|
||||
song.sample.push_back(sample);
|
||||
song.sampleLen=sampleCount+1;
|
||||
saveLock.unlock();
|
||||
renderSamples();
|
||||
BUSY_END;
|
||||
return sampleCount;
|
||||
return sample;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef HAVE_SNDFILE
|
||||
lastError="Furnace was not compiled with libsndfile!";
|
||||
return -1;
|
||||
return NULL;
|
||||
#else
|
||||
SF_INFO si;
|
||||
SFWrapper sfWrap;
|
||||
|
|
@ -2519,15 +2668,15 @@ int DivEngine::addSampleFromFile(const char* path) {
|
|||
if (err==SF_ERR_SYSTEM) {
|
||||
lastError=fmt::sprintf("could not open file! (%s %s)",sf_error_number(err),strerror(errno));
|
||||
} else {
|
||||
lastError=fmt::sprintf("could not open file! (%s)",sf_error_number(err));
|
||||
lastError=fmt::sprintf("could not open file! (%s)\nif this is raw sample data, you may import it by right-clicking the Load Sample icon and selecting \"import raw\".",sf_error_number(err));
|
||||
}
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
if (si.frames>16777215) {
|
||||
lastError="this sample is too big! max sample size is 16777215.";
|
||||
sfWrap.doClose();
|
||||
BUSY_END;
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
void* buf=NULL;
|
||||
sf_count_t sampleLen=sizeof(short);
|
||||
|
|
@ -2628,16 +2777,181 @@ int DivEngine::addSampleFromFile(const char* path) {
|
|||
if (sample->centerRate<4000) sample->centerRate=4000;
|
||||
if (sample->centerRate>64000) sample->centerRate=64000;
|
||||
sfWrap.doClose();
|
||||
saveLock.lock();
|
||||
song.sample.push_back(sample);
|
||||
song.sampleLen=sampleCount+1;
|
||||
saveLock.unlock();
|
||||
renderSamples();
|
||||
BUSY_END;
|
||||
return sampleCount;
|
||||
return sample;
|
||||
#endif
|
||||
}
|
||||
|
||||
DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth, int channels, bool bigEndian, bool unsign) {
|
||||
if (song.sample.size()>=256) {
|
||||
lastError="too many samples!";
|
||||
return NULL;
|
||||
}
|
||||
if (channels<1) {
|
||||
lastError="invalid channel count";
|
||||
return NULL;
|
||||
}
|
||||
if (depth!=DIV_SAMPLE_DEPTH_8BIT && depth!=DIV_SAMPLE_DEPTH_16BIT) {
|
||||
if (channels!=1) {
|
||||
lastError="channel count has to be 1 for non-8/16-bit format";
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
BUSY_BEGIN;
|
||||
warnings="";
|
||||
|
||||
const char* pathRedux=strrchr(path,DIR_SEPARATOR);
|
||||
if (pathRedux==NULL) {
|
||||
pathRedux=path;
|
||||
} else {
|
||||
pathRedux++;
|
||||
}
|
||||
String stripPath;
|
||||
const char* pathReduxEnd=strrchr(pathRedux,'.');
|
||||
if (pathReduxEnd==NULL) {
|
||||
stripPath=pathRedux;
|
||||
} else {
|
||||
for (const char* i=pathRedux; i!=pathReduxEnd && (*i); i++) {
|
||||
stripPath+=*i;
|
||||
}
|
||||
}
|
||||
|
||||
size_t len=0;
|
||||
size_t lenDivided=0;
|
||||
DivSample* sample=new DivSample;
|
||||
sample->name=stripPath;
|
||||
|
||||
FILE* f=ps_fopen(path,"rb");
|
||||
if (f==NULL) {
|
||||
BUSY_END;
|
||||
lastError=fmt::sprintf("could not open file! (%s)",strerror(errno));
|
||||
delete sample;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fseek(f,0,SEEK_END)<0) {
|
||||
fclose(f);
|
||||
BUSY_END;
|
||||
lastError=fmt::sprintf("could not get file length! (%s)",strerror(errno));
|
||||
delete sample;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len=ftell(f);
|
||||
|
||||
if (len==0) {
|
||||
fclose(f);
|
||||
BUSY_END;
|
||||
lastError="file is empty!";
|
||||
delete sample;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (len==(SIZE_MAX>>1)) {
|
||||
fclose(f);
|
||||
BUSY_END;
|
||||
lastError="file is invalid!";
|
||||
delete sample;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fseek(f,0,SEEK_SET)<0) {
|
||||
fclose(f);
|
||||
BUSY_END;
|
||||
lastError=fmt::sprintf("could not seek to beginning of file! (%s)",strerror(errno));
|
||||
delete sample;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lenDivided=len/channels;
|
||||
|
||||
unsigned int samples=lenDivided;
|
||||
switch (depth) {
|
||||
case DIV_SAMPLE_DEPTH_1BIT:
|
||||
case DIV_SAMPLE_DEPTH_1BIT_DPCM:
|
||||
samples=lenDivided*8;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_YMZ_ADPCM:
|
||||
case DIV_SAMPLE_DEPTH_QSOUND_ADPCM:
|
||||
case DIV_SAMPLE_DEPTH_ADPCM_A:
|
||||
case DIV_SAMPLE_DEPTH_ADPCM_B:
|
||||
case DIV_SAMPLE_DEPTH_VOX:
|
||||
samples=lenDivided*2;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_8BIT:
|
||||
samples=lenDivided;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_BRR:
|
||||
samples=16*((lenDivided+8)/9);
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_16BIT:
|
||||
samples=(lenDivided+1)/2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (samples>16777215) {
|
||||
fclose(f);
|
||||
BUSY_END;
|
||||
lastError="this sample is too big! max sample size is 16777215.";
|
||||
delete sample;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sample->rate=32000;
|
||||
sample->centerRate=32000;
|
||||
sample->depth=depth;
|
||||
sample->init(samples);
|
||||
|
||||
unsigned char* buf=new unsigned char[len];
|
||||
if (fread(buf,1,len,f)==0) {
|
||||
fclose(f);
|
||||
BUSY_END;
|
||||
lastError=fmt::sprintf("could not read file! (%s)",strerror(errno));
|
||||
delete[] buf;
|
||||
delete sample;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
// import sample
|
||||
size_t pos=0;
|
||||
if (depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
for (unsigned int i=0; i<samples; i++) {
|
||||
int accum=0;
|
||||
for (int j=0; j<channels; j++) {
|
||||
if (pos+1>=len) break;
|
||||
if (bigEndian) {
|
||||
accum+=(short)(((short)((buf[pos]<<8)|buf[pos+1]))^(unsign?0x8000:0));
|
||||
} else {
|
||||
accum+=(short)(((short)(buf[pos]|(buf[pos+1]<<8)))^(unsign?0x8000:0));
|
||||
}
|
||||
pos+=2;
|
||||
}
|
||||
accum/=channels;
|
||||
sample->data16[i]=accum;
|
||||
}
|
||||
} else if (depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
for (unsigned int i=0; i<samples; i++) {
|
||||
int accum=0;
|
||||
for (int j=0; j<channels; j++) {
|
||||
if (pos>=len) break;
|
||||
accum+=(signed char)(buf[pos++]^(unsign?0x80:0));
|
||||
}
|
||||
accum/=channels;
|
||||
sample->data8[i]=accum;
|
||||
}
|
||||
} else {
|
||||
memcpy(sample->getCurBuf(),buf,len);
|
||||
}
|
||||
delete[] buf;
|
||||
|
||||
BUSY_END;
|
||||
return sample;
|
||||
}
|
||||
|
||||
void DivEngine::delSample(int index) {
|
||||
BUSY_BEGIN;
|
||||
sPreview.sample=-1;
|
||||
|
|
@ -2816,13 +3130,15 @@ void DivEngine::moveOrderDown() {
|
|||
|
||||
void DivEngine::exchangeIns(int one, int two) {
|
||||
for (int i=0; i<chans; i++) {
|
||||
for (int j=0; j<256; j++) {
|
||||
if (curPat[i].data[j]==NULL) continue;
|
||||
for (int k=0; k<curSubSong->patLen; k++) {
|
||||
if (curPat[i].data[j]->data[k][2]==one) {
|
||||
curPat[i].data[j]->data[k][2]=two;
|
||||
} else if (curPat[i].data[j]->data[k][2]==two) {
|
||||
curPat[i].data[j]->data[k][2]=one;
|
||||
for (size_t j=0; j<song.subsong.size(); j++) {
|
||||
for (int k=0; k<256; k++) {
|
||||
if (song.subsong[j]->pat[i].data[k]==NULL) continue;
|
||||
for (int l=0; l<curSubSong->patLen; l++) {
|
||||
if (song.subsong[j]->pat[i].data[k]->data[l][2]==one) {
|
||||
song.subsong[j]->pat[i].data[k]->data[l][2]=two;
|
||||
} else if (song.subsong[j]->pat[i].data[k]->data[l][2]==two) {
|
||||
song.subsong[j]->pat[i].data[k]->data[l][2]=one;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2912,7 +3228,7 @@ bool DivEngine::moveSampleDown(int which) {
|
|||
void DivEngine::noteOn(int chan, int ins, int note, int vol) {
|
||||
if (chan<0 || chan>=chans) return;
|
||||
BUSY_BEGIN;
|
||||
pendingNotes.push(DivNoteEvent(chan,ins,note,vol,true));
|
||||
pendingNotes.push_back(DivNoteEvent(chan,ins,note,vol,true));
|
||||
if (!playing) {
|
||||
reset();
|
||||
freelance=true;
|
||||
|
|
@ -2924,7 +3240,7 @@ void DivEngine::noteOn(int chan, int ins, int note, int vol) {
|
|||
void DivEngine::noteOff(int chan) {
|
||||
if (chan<0 || chan>=chans) return;
|
||||
BUSY_BEGIN;
|
||||
pendingNotes.push(DivNoteEvent(chan,-1,-1,-1,false));
|
||||
pendingNotes.push_back(DivNoteEvent(chan,-1,-1,-1,false));
|
||||
if (!playing) {
|
||||
reset();
|
||||
freelance=true;
|
||||
|
|
@ -2976,7 +3292,7 @@ void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) {
|
|||
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));
|
||||
pendingNotes.push_back(DivNoteEvent(finalChan,ins,note,vol,true));
|
||||
return;
|
||||
}
|
||||
if (++finalChan>=chans) {
|
||||
|
|
@ -2997,7 +3313,7 @@ void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) {
|
|||
|
||||
chan[candidate].midiNote=note;
|
||||
chan[candidate].midiAge=midiAgeCounter++;
|
||||
pendingNotes.push(DivNoteEvent(candidate,ins,note,vol,true));
|
||||
pendingNotes.push_back(DivNoteEvent(candidate,ins,note,vol,true));
|
||||
}
|
||||
|
||||
void DivEngine::autoNoteOff(int ch, int note, int vol) {
|
||||
|
|
@ -3009,7 +3325,7 @@ void DivEngine::autoNoteOff(int ch, int note, int vol) {
|
|||
//if (ch<0 || ch>=chans) return;
|
||||
for (int i=0; i<chans; i++) {
|
||||
if (chan[i].midiNote==note) {
|
||||
pendingNotes.push(DivNoteEvent(i,-1,-1,-1,false));
|
||||
pendingNotes.push_back(DivNoteEvent(i,-1,-1,-1,false));
|
||||
chan[i].midiNote=-1;
|
||||
}
|
||||
}
|
||||
|
|
@ -3023,7 +3339,7 @@ void DivEngine::autoNoteOffAll() {
|
|||
}
|
||||
for (int i=0; i<chans; i++) {
|
||||
if (chan[i].midiNote!=-1) {
|
||||
pendingNotes.push(DivNoteEvent(i,-1,-1,-1,false));
|
||||
pendingNotes.push_back(DivNoteEvent(i,-1,-1,-1,false));
|
||||
chan[i].midiNote=-1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@
|
|||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
#include <deque>
|
||||
|
||||
#define addWarning(x) \
|
||||
if (warnings.empty()) { \
|
||||
|
|
@ -45,8 +46,8 @@
|
|||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||
|
||||
#define DIV_VERSION "dev106"
|
||||
#define DIV_ENGINE_VERSION 106
|
||||
#define DIV_VERSION "dev112"
|
||||
#define DIV_ENGINE_VERSION 112
|
||||
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
|
|
@ -194,7 +195,29 @@ struct DivDispatchContainer {
|
|||
dcOffCompensation(false) {}
|
||||
};
|
||||
|
||||
typedef std::function<bool(int,unsigned char,unsigned char)> EffectProcess;
|
||||
typedef int EffectValConversion(unsigned char,unsigned char);
|
||||
|
||||
struct EffectHandler {
|
||||
DivDispatchCmds dispatchCmd;
|
||||
const char* description;
|
||||
EffectValConversion* val;
|
||||
EffectValConversion* val2;
|
||||
EffectHandler(
|
||||
DivDispatchCmds dispatchCmd_,
|
||||
const char* description_,
|
||||
EffectValConversion val_=NULL,
|
||||
EffectValConversion val2_=NULL
|
||||
):
|
||||
dispatchCmd(dispatchCmd_),
|
||||
description(description_),
|
||||
val(val_),
|
||||
val2(val2_) {}
|
||||
};
|
||||
|
||||
struct DivDoNotHandleEffect {
|
||||
};
|
||||
|
||||
typedef std::unordered_map<unsigned char,const EffectHandler> EffectHandlerMap;
|
||||
|
||||
struct DivSysDef {
|
||||
const char* name;
|
||||
|
|
@ -211,8 +234,8 @@ struct DivSysDef {
|
|||
// 0: primary
|
||||
// 1: alternate (usually PCM)
|
||||
DivInstrumentType chanInsType[DIV_MAX_CHANS][2];
|
||||
EffectProcess effectFunc;
|
||||
EffectProcess postEffectFunc;
|
||||
const EffectHandlerMap effectHandlers;
|
||||
const EffectHandlerMap postEffectHandlers;
|
||||
DivSysDef(
|
||||
const char* sysName, const char* sysNameJ, unsigned char fileID, unsigned char fileID_DMF, int chans,
|
||||
bool isFMChip, bool isSTDChip, unsigned int vgmVer, bool compound, const char* desc,
|
||||
|
|
@ -221,8 +244,8 @@ struct DivSysDef {
|
|||
std::initializer_list<int> chTypes,
|
||||
std::initializer_list<DivInstrumentType> chInsType1,
|
||||
std::initializer_list<DivInstrumentType> chInsType2={},
|
||||
EffectProcess fxHandler=[](int,unsigned char,unsigned char) -> bool {return false;},
|
||||
EffectProcess postFxHandler=[](int,unsigned char,unsigned char) -> bool {return false;}):
|
||||
const EffectHandlerMap fxHandlers_={},
|
||||
const EffectHandlerMap postFxHandlers_={}):
|
||||
name(sysName),
|
||||
nameJ(sysNameJ),
|
||||
description(desc),
|
||||
|
|
@ -233,8 +256,8 @@ struct DivSysDef {
|
|||
isSTD(isSTDChip),
|
||||
isCompound(compound),
|
||||
vgmVersion(vgmVer),
|
||||
effectFunc(fxHandler),
|
||||
postEffectFunc(postFxHandler) {
|
||||
effectHandlers(fxHandlers_),
|
||||
postEffectHandlers(postFxHandlers_) {
|
||||
memset(chanNames,0,DIV_MAX_CHANS*sizeof(void*));
|
||||
memset(chanShortNames,0,DIV_MAX_CHANS*sizeof(void*));
|
||||
memset(chanTypes,0,DIV_MAX_CHANS*sizeof(int));
|
||||
|
|
@ -334,7 +357,7 @@ class DivEngine {
|
|||
DivAudioExportModes exportMode;
|
||||
double exportFadeOut;
|
||||
std::map<String,String> conf;
|
||||
std::queue<DivNoteEvent> pendingNotes;
|
||||
std::deque<DivNoteEvent> pendingNotes;
|
||||
bool isMuted[DIV_MAX_CHANS];
|
||||
std::mutex isBusy, saveLock;
|
||||
String configPath;
|
||||
|
|
@ -533,6 +556,9 @@ class DivEngine {
|
|||
// calculate frequency/period
|
||||
int calcFreq(int base, int pitch, bool period=false, int octave=0, int pitch2=0, double clock=1.0, double divider=1.0, int blockBits=0);
|
||||
|
||||
// calculate arpeggio
|
||||
int calcArp(int note, int arp, int offset=0);
|
||||
|
||||
// convert panning formats
|
||||
int convertPanSplitToLinear(unsigned int val, unsigned char bits, int range);
|
||||
int convertPanSplitToLinearLR(unsigned char left, unsigned char right, int range);
|
||||
|
|
@ -603,6 +629,9 @@ class DivEngine {
|
|||
// get japanese system name
|
||||
const char* getSystemNameJ(DivSystem sys);
|
||||
|
||||
// get sys definition
|
||||
const DivSysDef* getSystemDef(DivSystem sys);
|
||||
|
||||
// convert sample rate format
|
||||
int fileToDivRate(int frate);
|
||||
int divToFileRate(int drate);
|
||||
|
|
@ -708,8 +737,11 @@ class DivEngine {
|
|||
// add wavetable
|
||||
int addWave();
|
||||
|
||||
// add wavetable from file
|
||||
bool addWaveFromFile(const char* path, bool loadRaw=true);
|
||||
// add wavetable from pointer
|
||||
int addWavePtr(DivWavetable* which);
|
||||
|
||||
// get wavetable from file
|
||||
DivWavetable* waveFromFile(const char* path, bool loadRaw=true);
|
||||
|
||||
// delete wavetable
|
||||
void delWave(int index);
|
||||
|
|
@ -717,8 +749,14 @@ class DivEngine {
|
|||
// add sample
|
||||
int addSample();
|
||||
|
||||
// add sample from file
|
||||
int addSampleFromFile(const char* path);
|
||||
// add sample from pointer
|
||||
int addSamplePtr(DivSample* which);
|
||||
|
||||
// get sample from file
|
||||
DivSample* sampleFromFile(const char* path);
|
||||
|
||||
// get raw sample
|
||||
DivSample* sampleFromFileRaw(const char* path, DivSampleDepth depth, int channels, bool bigEndian, bool unsign);
|
||||
|
||||
// delete sample
|
||||
void delSample(int index);
|
||||
|
|
@ -875,6 +913,9 @@ class DivEngine {
|
|||
|
||||
// remove system
|
||||
bool removeSystem(int index, bool preserveOrder=true);
|
||||
|
||||
// move system
|
||||
bool swapSystem(int src, int dest, bool preserveOrder=true);
|
||||
|
||||
// write to register on system
|
||||
void poke(int sys, unsigned int addr, unsigned short val);
|
||||
|
|
|
|||
|
|
@ -145,7 +145,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
ds.loopModality=0;
|
||||
ds.properNoiseLayout=false;
|
||||
ds.waveDutyIsVol=false;
|
||||
ds.resetMacroOnPorta=true;
|
||||
// TODO: WHAT?! geodude.dmf fails when this is true
|
||||
// but isn't that how Defle behaves???
|
||||
ds.resetMacroOnPorta=false;
|
||||
ds.legacyVolumeSlides=true;
|
||||
ds.compatibleArpeggio=true;
|
||||
ds.noteOffResetsSlides=true;
|
||||
|
|
@ -175,6 +177,8 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
ds.brokenOutVol=true; // ???
|
||||
ds.e1e2StopOnSameNote=true;
|
||||
ds.brokenPortaArp=false;
|
||||
ds.snNoLowPeriods=true;
|
||||
ds.delayBehavior=0;
|
||||
|
||||
// 1.1 compat flags
|
||||
if (ds.version>24) {
|
||||
|
|
@ -505,6 +509,14 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
for (int j=0; j<ins->std.arpMacro.len; j++) {
|
||||
ins->std.arpMacro.val[j]-=12;
|
||||
}
|
||||
} else {
|
||||
ins->std.arpMacro.mode=0;
|
||||
for (int j=0; j<ins->std.arpMacro.len; j++) {
|
||||
ins->std.arpMacro.val[j]^=0x40000000;
|
||||
}
|
||||
if (ins->std.arpMacro.loop==255 && ins->std.arpMacro.len<255) {
|
||||
ins->std.arpMacro.val[ins->std.arpMacro.len++]=0;
|
||||
}
|
||||
}
|
||||
|
||||
ins->std.dutyMacro.len=reader.readC();
|
||||
|
|
@ -825,6 +837,13 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
data=new short[length];
|
||||
reader.read(data,length*2);
|
||||
}
|
||||
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
// convert to big-endian
|
||||
for (int pos=0; pos<length; pos++) {
|
||||
data[pos]=(short)((((unsigned short)data[pos])<<8)|(((unsigned short)data[pos])>>8));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pitch!=5) {
|
||||
logD("%d: scaling from %d...",i,pitch);
|
||||
|
|
@ -1056,6 +1075,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
if (ds.version<101) {
|
||||
ds.brokenPortaArp=true;
|
||||
}
|
||||
if (ds.version<108) {
|
||||
ds.snNoLowPeriods=true;
|
||||
}
|
||||
if (ds.version<110) {
|
||||
ds.delayBehavior=1;
|
||||
}
|
||||
ds.isDMF=false;
|
||||
|
||||
reader.readS(); // reserved
|
||||
|
|
@ -1323,9 +1348,15 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
}
|
||||
|
||||
// pointers
|
||||
reader.read(insPtr,ds.insLen*4);
|
||||
reader.read(wavePtr,ds.waveLen*4);
|
||||
reader.read(samplePtr,ds.sampleLen*4);
|
||||
for (int i=0; i<ds.insLen; i++) {
|
||||
insPtr[i]=reader.readI();
|
||||
}
|
||||
for (int i=0; i<ds.waveLen; i++) {
|
||||
wavePtr[i]=reader.readI();
|
||||
}
|
||||
for (int i=0; i<ds.sampleLen; i++) {
|
||||
samplePtr[i]=reader.readI();
|
||||
}
|
||||
for (int i=0; i<numberOfPats; i++) patPtr.push_back(reader.readI());
|
||||
|
||||
logD("reading orders (%d)...",subSong->ordersLen);
|
||||
|
|
@ -1462,7 +1493,17 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
} else {
|
||||
reader.readC();
|
||||
}
|
||||
for (int i=0; i<7; i++) {
|
||||
if (ds.version>=108) {
|
||||
ds.snNoLowPeriods=reader.readC();
|
||||
} else {
|
||||
reader.readC();
|
||||
}
|
||||
if (ds.version>=110) {
|
||||
ds.delayBehavior=reader.readC();
|
||||
} else {
|
||||
reader.readC();
|
||||
}
|
||||
for (int i=0; i<5; i++) {
|
||||
reader.readC();
|
||||
}
|
||||
}
|
||||
|
|
@ -1705,11 +1746,36 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
if (ds.version>=58) { // modern sample
|
||||
sample->init(sample->samples);
|
||||
reader.read(sample->getCurBuf(),sample->getCurBufLen());
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
// convert 16-bit samples to big-endian
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
unsigned char* sampleBuf=(unsigned char*)sample->getCurBuf();
|
||||
size_t sampleBufLen=sample->getCurBufLen();
|
||||
for (size_t pos=0; pos<sampleBufLen; pos+=2) {
|
||||
sampleBuf[pos]^=sampleBuf[pos+1];
|
||||
sampleBuf[pos+1]^=sampleBuf[pos];
|
||||
sampleBuf[pos]^=sampleBuf[pos+1];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else { // legacy sample
|
||||
int length=sample->samples;
|
||||
short* data=new short[length];
|
||||
reader.read(data,2*length);
|
||||
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
// convert 16-bit samples to big-endian
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
unsigned char* sampleBuf=(unsigned char*)sample->getCurBuf();
|
||||
size_t sampleBufLen=sample->getCurBufLen();
|
||||
for (size_t pos=0; pos<sampleBufLen; pos+=2) {
|
||||
sampleBuf[pos]^=sampleBuf[pos+1];
|
||||
sampleBuf[pos+1]^=sampleBuf[pos];
|
||||
sampleBuf[pos]^=sampleBuf[pos+1];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pitch!=5) {
|
||||
logD("%d: scaling from %d...",i,pitch);
|
||||
}
|
||||
|
|
@ -1872,6 +1938,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
ds.noSlidesOnFirstTick=true;
|
||||
ds.rowResetsArpPos=true;
|
||||
ds.ignoreJumpAtEnd=false;
|
||||
ds.delayBehavior=0;
|
||||
|
||||
int insCount=31;
|
||||
bool bypassLimits=false;
|
||||
|
|
@ -2265,6 +2332,95 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
return success;
|
||||
}
|
||||
|
||||
unsigned char fcXORTriangle[32]={
|
||||
0xc0, 0xc0, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, 0x00, 0xf8, 0xf0, 0xe8, 0xe0, 0xd8, 0xd0, 0xc8,
|
||||
0xc0, 0xb8, 0xb0, 0xa8, 0xa0, 0x98, 0x90, 0x88, 0x80, 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8
|
||||
};
|
||||
|
||||
unsigned char fcCustom1[32]={
|
||||
0x45, 0x45, 0x79, 0x7d, 0x7a, 0x77, 0x70, 0x66, 0x61, 0x58, 0x53, 0x4d, 0x2c, 0x20, 0x18, 0x12,
|
||||
0x04, 0xdb, 0xd3, 0xcd, 0xc6, 0xbc, 0xb5, 0xae, 0xa8, 0xa3, 0x9d, 0x99, 0x93, 0x8e, 0x8b, 0x8a
|
||||
};
|
||||
|
||||
unsigned char fcCustom2[32]={
|
||||
0x45, 0x45, 0x79, 0x7d, 0x7a, 0x77, 0x70, 0x66, 0x5b, 0x4b, 0x43, 0x37, 0x2c, 0x20, 0x18, 0x12,
|
||||
0x04, 0xf8, 0xe8, 0xdb, 0xcf, 0xc6, 0xbe, 0xb0, 0xa8, 0xa4, 0x9e, 0x9a, 0x95, 0x94, 0x8d, 0x83
|
||||
};
|
||||
|
||||
unsigned char fcTinyTriangle[16]={
|
||||
0x00, 0x00, 0x40, 0x60, 0x7f, 0x60, 0x40, 0x20, 0x00, 0xe0, 0xc0, 0xa0, 0x80, 0xa0, 0xc0, 0xe0
|
||||
};
|
||||
|
||||
void generateFCPresetWave(int index, DivWavetable* wave) {
|
||||
wave->max=255;
|
||||
wave->len=32;
|
||||
|
||||
switch (index) {
|
||||
case 0x00: case 0x01: case 0x02: case 0x03:
|
||||
case 0x04: case 0x05: case 0x06: case 0x07:
|
||||
case 0x08: case 0x09: case 0x0a: case 0x0b:
|
||||
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
|
||||
// XOR triangle
|
||||
for (int i=0; i<32; i++) {
|
||||
wave->data[i]=(unsigned char)((fcXORTriangle[i]^0x80)^(((index+15)<i)?0x87:0x00));
|
||||
}
|
||||
break;
|
||||
case 0x10: case 0x11: case 0x12: case 0x13:
|
||||
case 0x14: case 0x15: case 0x16: case 0x17:
|
||||
case 0x18: case 0x19: case 0x1a: case 0x1b:
|
||||
case 0x1c: case 0x1d: case 0x1e: case 0x1f:
|
||||
// pulse
|
||||
for (int i=0; i<32; i++) {
|
||||
wave->data[i]=(index>i)?0x01:0xff;
|
||||
}
|
||||
break;
|
||||
case 0x20: case 0x21: case 0x22: case 0x23:
|
||||
case 0x24: case 0x25: case 0x26: case 0x27:
|
||||
// tiny pulse
|
||||
for (int i=0; i<32; i++) {
|
||||
wave->data[i]=((index-0x18)>(i&15))?0x01:0xff;
|
||||
}
|
||||
break;
|
||||
case 0x28:
|
||||
case 0x2e:
|
||||
// saw
|
||||
for (int i=0; i<32; i++) {
|
||||
wave->data[i]=i<<3;
|
||||
}
|
||||
break;
|
||||
case 0x29:
|
||||
case 0x2f:
|
||||
// tiny saw
|
||||
for (int i=0; i<32; i++) {
|
||||
wave->data[i]=(i<<4)&0xff;
|
||||
}
|
||||
break;
|
||||
case 0x2a:
|
||||
// custom 1
|
||||
for (int i=0; i<32; i++) {
|
||||
wave->data[i]=fcCustom1[i]^0x80;
|
||||
}
|
||||
break;
|
||||
case 0x2b:
|
||||
// custom 2
|
||||
for (int i=0; i<32; i++) {
|
||||
wave->data[i]=fcCustom2[i]^0x80;
|
||||
}
|
||||
break;
|
||||
case 0x2c: case 0x2d:
|
||||
// tiny triangle
|
||||
for (int i=0; i<32; i++) {
|
||||
wave->data[i]=fcTinyTriangle[i&15]^0x80;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (int i=0; i<32; i++) {
|
||||
wave->data[i]=i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
||||
struct InvalidHeaderException {};
|
||||
bool success=false;
|
||||
|
|
@ -2275,8 +2431,8 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
unsigned int patPtr, freqMacroPtr, volMacroPtr, samplePtr, wavePtr;
|
||||
unsigned int seqLen, patLen, freqMacroLen, volMacroLen, sampleLen;
|
||||
|
||||
unsigned char waveLen[40];
|
||||
unsigned char waveLoopLen[40];
|
||||
unsigned char waveLen[80];
|
||||
//unsigned char waveLoopLen[40];
|
||||
|
||||
struct FCSequence {
|
||||
unsigned char pat[4];
|
||||
|
|
@ -2305,9 +2461,11 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
ds.tuning=436.0;
|
||||
ds.version=DIV_VERSION_FC;
|
||||
//ds.linearPitch=0;
|
||||
//ds.pitchMacroIsLinear=false;
|
||||
//ds.noSlidesOnFirstTick=true;
|
||||
//ds.rowResetsArpPos=true;
|
||||
//ds.ignoreJumpAtEnd=false;
|
||||
ds.pitchSlideSpeed=8;
|
||||
ds.ignoreJumpAtEnd=false;
|
||||
|
||||
// load here
|
||||
if (!reader.seek(0,SEEK_SET)) {
|
||||
|
|
@ -2366,25 +2524,25 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
wavePtr=0;
|
||||
}
|
||||
|
||||
logD("patPtr: %d",patPtr);
|
||||
logD("patPtr: %x",patPtr);
|
||||
logD("patLen: %d",patLen);
|
||||
logD("freqMacroPtr: %d",freqMacroPtr);
|
||||
logD("freqMacroPtr: %x",freqMacroPtr);
|
||||
logD("freqMacroLen: %d",freqMacroLen);
|
||||
logD("volMacroPtr: %d",volMacroPtr);
|
||||
logD("volMacroPtr: %x",volMacroPtr);
|
||||
logD("volMacroLen: %d",volMacroLen);
|
||||
logD("samplePtr: %d",samplePtr);
|
||||
logD("samplePtr: %x",samplePtr);
|
||||
if (isFC14) {
|
||||
logD("wavePtr: %d",wavePtr);
|
||||
logD("wavePtr: %x",wavePtr);
|
||||
} else {
|
||||
logD("sampleLen: %d",sampleLen);
|
||||
}
|
||||
|
||||
// sample info
|
||||
logD("samples:");
|
||||
logD("samples: (%x)",reader.tell());
|
||||
for (int i=0; i<10; i++) {
|
||||
sample[i].loopLen=reader.readS_BE();
|
||||
sample[i].len=reader.readS_BE();
|
||||
sample[i].loopStart=reader.readS_BE();
|
||||
sample[i].loopLen=reader.readS_BE();
|
||||
|
||||
logD("- %d: %d (%d, %d)",i,sample[i].len,sample[i].loopStart,sample[i].loopLen);
|
||||
}
|
||||
|
|
@ -2392,11 +2550,10 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
// wavetable lengths
|
||||
if (isFC14) {
|
||||
logD("wavetables:");
|
||||
for (int i=0; i<40; i++) {
|
||||
waveLen[i]=reader.readC();
|
||||
waveLoopLen[i]=reader.readC();
|
||||
for (int i=0; i<80; i++) {
|
||||
waveLen[i]=(unsigned char)reader.readC();
|
||||
|
||||
logD("- %d: %.4x (%.4x)",i,waveLen[i],waveLoopLen[i]);
|
||||
logD("- %d: %.4x",i,waveLen[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2485,12 +2642,19 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
DivSample* s=new DivSample;
|
||||
s->depth=DIV_SAMPLE_DEPTH_8BIT;
|
||||
if (sample[i].len>0) {
|
||||
s->init(sample[i].len);
|
||||
s->init(sample[i].len*2);
|
||||
}
|
||||
s->loopStart=sample[i].loopStart*2;
|
||||
s->loopEnd=(sample[i].loopStart+sample[i].loopLen)*2;
|
||||
s->loop=(s->loopStart>=0)&&(s->loopEnd>=0);
|
||||
reader.read(s->data8,sample[i].len);
|
||||
s->name=fmt::sprintf("Sample %d",i+1);
|
||||
if (sample[i].loopLen>1) {
|
||||
s->loopStart=sample[i].loopStart;
|
||||
s->loopEnd=sample[i].loopStart+(sample[i].loopLen*2);
|
||||
s->loop=(s->loopStart>=0)&&(s->loopEnd>=0);
|
||||
}
|
||||
reader.read(s->data8,sample[i].len*2);
|
||||
ds.sample.push_back(s);
|
||||
}
|
||||
ds.sampleLen=(int)ds.sample.size();
|
||||
|
|
@ -2504,11 +2668,11 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
return false;
|
||||
}
|
||||
logD("reading wavetables...");
|
||||
for (int i=0; i<40; i++) {
|
||||
for (int i=0; i<80; i++) {
|
||||
DivWavetable* w=new DivWavetable;
|
||||
w->min=0;
|
||||
w->max=255;
|
||||
w->len=MIN(256,waveLoopLen[i]*2);
|
||||
w->len=MIN(256,waveLen[i]*2);
|
||||
|
||||
for (int i=0; i<256; i++) {
|
||||
w->data[i]=128;
|
||||
|
|
@ -2517,19 +2681,24 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
if (waveLen[i]>0) {
|
||||
signed char* waveArray=new signed char[waveLen[i]*2];
|
||||
reader.read(waveArray,waveLen[i]*2);
|
||||
int howMany=MIN(waveLen[i]*2,waveLoopLen[i]*2);
|
||||
int howMany=waveLen[i]*2;
|
||||
if (howMany>256) howMany=256;
|
||||
for (int i=0; i<howMany; i++) {
|
||||
w->data[i]=waveArray[i]+128;
|
||||
}
|
||||
delete[] waveArray;
|
||||
} else {
|
||||
w->len=32;
|
||||
for (int i=0; i<32; i++) {
|
||||
w->data[i]=(i*255)/31;
|
||||
}
|
||||
logV("empty wave %d",i);
|
||||
generateFCPresetWave(i,w);
|
||||
}
|
||||
|
||||
ds.wave.push_back(w);
|
||||
}
|
||||
} else {
|
||||
// generate preset waves
|
||||
for (int i=0; i<48; i++) {
|
||||
DivWavetable* w=new DivWavetable;
|
||||
generateFCPresetWave(i,w);
|
||||
ds.wave.push_back(w);
|
||||
}
|
||||
}
|
||||
|
|
@ -2545,6 +2714,16 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
ds.subsong[0]->speed1=3;
|
||||
ds.subsong[0]->speed2=3;
|
||||
|
||||
int lastIns[4];
|
||||
int lastNote[4];
|
||||
signed char lastTranspose[4];
|
||||
bool isSliding[4];
|
||||
|
||||
memset(lastIns,-1,4*sizeof(int));
|
||||
memset(lastNote,-1,4*sizeof(int));
|
||||
memset(lastTranspose,0,4);
|
||||
memset(isSliding,0,4*sizeof(bool));
|
||||
|
||||
for (unsigned int i=0; i<seqLen; i++) {
|
||||
for (int j=0; j<4; j++) {
|
||||
ds.subsong[0]->orders.ord[j][i]=i;
|
||||
|
|
@ -2557,11 +2736,11 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
}
|
||||
|
||||
bool ignoreNext=false;
|
||||
bool isSliding=false;
|
||||
|
||||
for (int k=0; k<32; k++) {
|
||||
FCPattern& fp=pat[seq[i].pat[j]];
|
||||
if (fp.note[k]>0 && fp.note[k]<0x49) {
|
||||
lastNote[j]=fp.note[k];
|
||||
short note=(fp.note[k]+seq[i].transpose[j])%12;
|
||||
short octave=2+((fp.note[k]+seq[i].transpose[j])/12);
|
||||
if (fp.note[k]>=0x3d) octave-=6;
|
||||
|
|
@ -2572,23 +2751,48 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
octave&=0xff;
|
||||
p->data[k][0]=note;
|
||||
p->data[k][1]=octave;
|
||||
if (isSliding) {
|
||||
isSliding=false;
|
||||
if (isSliding[j]) {
|
||||
isSliding[j]=false;
|
||||
p->data[k][4]=2;
|
||||
p->data[k][5]=0;
|
||||
}
|
||||
} else if (fp.note[k]==0x49) {
|
||||
if (k>0) {
|
||||
p->data[k-1][4]=0x0d;
|
||||
p->data[k-1][5]=0;
|
||||
}
|
||||
} else if (k==0 && lastTranspose[j]!=seq[i].transpose[j]) {
|
||||
p->data[0][2]=lastIns[j];
|
||||
p->data[0][4]=0x03;
|
||||
p->data[0][5]=0xff;
|
||||
lastTranspose[j]=seq[i].transpose[j];
|
||||
|
||||
short note=(lastNote[j]+seq[i].transpose[j])%12;
|
||||
short octave=2+((lastNote[j]+seq[i].transpose[j])/12);
|
||||
if (lastNote[j]>=0x3d) octave-=6;
|
||||
if (note==0) {
|
||||
note=12;
|
||||
octave--;
|
||||
}
|
||||
octave&=0xff;
|
||||
p->data[k][0]=note;
|
||||
p->data[k][1]=octave;
|
||||
}
|
||||
if (fp.val[k]) {
|
||||
if (ignoreNext) {
|
||||
ignoreNext=false;
|
||||
} else {
|
||||
if (fp.val[k]&0xe0) {
|
||||
if (fp.val[k]==0xf0) {
|
||||
p->data[k][0]=100;
|
||||
p->data[k][1]=0;
|
||||
p->data[k][2]=-1;
|
||||
} else if (fp.val[k]&0xe0) {
|
||||
if (fp.val[k]&0x40) {
|
||||
p->data[k][4]=2;
|
||||
p->data[k][5]=0;
|
||||
isSliding=false;
|
||||
isSliding[j]=false;
|
||||
} else if (fp.val[k]&0x80) {
|
||||
isSliding=true;
|
||||
isSliding[j]=true;
|
||||
if (k<31) {
|
||||
if (fp.val[k+1]&0x20) {
|
||||
p->data[k][4]=2;
|
||||
|
|
@ -2604,9 +2808,13 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
p->data[k][2]=fp.val[k]&0x3f;
|
||||
p->data[k][2]=(fp.val[k]+seq[i].offsetIns[j])&0x3f;
|
||||
lastIns[j]=p->data[k][2];
|
||||
}
|
||||
}
|
||||
} else if (fp.note[k]>0 && fp.note[k]<0x49) {
|
||||
p->data[k][2]=seq[i].offsetIns[j];
|
||||
lastIns[j]=p->data[k][2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2620,17 +2828,23 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
ins->type=DIV_INS_AMIGA;
|
||||
ins->name=fmt::sprintf("Instrument %d",i);
|
||||
ins->amiga.useWave=true;
|
||||
//unsigned char seqSpeed=m.val[0];
|
||||
unsigned char seqSpeed=m.val[0];
|
||||
unsigned char freqMacro=m.val[1];
|
||||
//unsigned char vibSpeed=m.val[2];
|
||||
//unsigned char vibDepth=m.val[3];
|
||||
//unsigned char vibDelay=m.val[4];
|
||||
unsigned char vibSpeed=m.val[2];
|
||||
unsigned char vibDepth=m.val[3];
|
||||
unsigned char vibDelay=m.val[4];
|
||||
|
||||
unsigned char lastVal=m.val[5];
|
||||
|
||||
signed char loopMap[64];
|
||||
memset(loopMap,-1,64);
|
||||
|
||||
signed char loopMapFreq[64];
|
||||
memset(loopMapFreq,-1,64);
|
||||
|
||||
signed char loopMapWave[64];
|
||||
memset(loopMapWave,-1,64);
|
||||
|
||||
// volume sequence
|
||||
ins->std.volMacro.len=0;
|
||||
for (int j=5; j<64; j++) {
|
||||
|
|
@ -2647,8 +2861,9 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
// TODO: <= or <?
|
||||
for (int k=0; k<=susTime; k++) {
|
||||
ins->std.volMacro.val[ins->std.volMacro.len]=lastVal;
|
||||
if (++ins->std.volMacro.len>=128) break;
|
||||
if (++ins->std.volMacro.len>=255) break;
|
||||
}
|
||||
if (ins->std.volMacro.len>=255) break;
|
||||
} else if (m.val[j]==0xe9 || m.val[j]==0xea) { // volume slide
|
||||
if (++j>=64) break;
|
||||
signed char slideStep=m.val[j];
|
||||
|
|
@ -2667,12 +2882,16 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
}
|
||||
}
|
||||
ins->std.volMacro.val[ins->std.volMacro.len]=lastVal;
|
||||
if (++ins->std.volMacro.len>=128) break;
|
||||
if (++ins->std.volMacro.len>=255) break;
|
||||
}
|
||||
} else {
|
||||
ins->std.volMacro.val[ins->std.volMacro.len]=m.val[j];
|
||||
lastVal=m.val[j];
|
||||
if (++ins->std.volMacro.len>=128) break;
|
||||
// TODO: replace with upcoming macro speed
|
||||
for (int k=0; k<MAX(1,seqSpeed); k++) {
|
||||
ins->std.volMacro.val[ins->std.volMacro.len]=m.val[j];
|
||||
lastVal=m.val[j];
|
||||
if (++ins->std.volMacro.len>=255) break;
|
||||
}
|
||||
if (ins->std.volMacro.len>=255) break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2682,6 +2901,8 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
if (freqMacro<freqMacros.size()) {
|
||||
FCMacro& fm=freqMacros[freqMacro];
|
||||
for (int j=0; j<64; j++) {
|
||||
loopMapFreq[j]=ins->std.arpMacro.len;
|
||||
loopMapWave[j]=ins->std.waveMacro.len;
|
||||
if (fm.val[j]==0xe1) {
|
||||
break;
|
||||
} else if (fm.val[j]==0xe2 || fm.val[j]==0xe4) {
|
||||
|
|
@ -2696,33 +2917,80 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
ins->std.waveMacro.val[ins->std.waveMacro.len]=wave-10;
|
||||
ins->std.waveMacro.open=true;
|
||||
lastVal=wave;
|
||||
if (++ins->std.waveMacro.len>=128) break;
|
||||
if (++ins->std.arpMacro.len>=128) break;
|
||||
//if (++ins->std.arpMacro.len>=255) break;
|
||||
}
|
||||
} else if (fm.val[j]==0xe0) {
|
||||
logV("unhandled loop!");
|
||||
if (++j>=64) break;
|
||||
ins->std.arpMacro.loop=loopMapFreq[fm.val[j]&63];
|
||||
ins->std.waveMacro.loop=loopMapWave[fm.val[j]&63];
|
||||
break;
|
||||
} else if (fm.val[j]==0xe3) {
|
||||
logV("unhandled vibrato!");
|
||||
} else if (fm.val[j]==0xe8) {
|
||||
logV("unhandled sustain!");
|
||||
} else if (fm.val[j]==0xe7) {
|
||||
logV("unhandled newseq!");
|
||||
if (++j>=64) break;
|
||||
fm=freqMacros[MIN(fm.val[j],freqMacros.size()-1)];
|
||||
j=0;
|
||||
} else if (fm.val[j]==0xe9) {
|
||||
logV("unhandled pack!");
|
||||
} else if (fm.val[j]==0xea) {
|
||||
logV("unhandled pitch!");
|
||||
} else {
|
||||
ins->std.arpMacro.val[ins->std.arpMacro.len]=(signed char)fm.val[j];
|
||||
if (fm.val[j]>0x80) {
|
||||
ins->std.arpMacro.val[ins->std.arpMacro.len]=(fm.val[j]-0x80+24)^0x40000000;
|
||||
} else {
|
||||
ins->std.arpMacro.val[ins->std.arpMacro.len]=fm.val[j];
|
||||
}
|
||||
if (lastVal>=10) {
|
||||
ins->std.waveMacro.val[ins->std.waveMacro.len]=lastVal-10;
|
||||
}
|
||||
ins->std.arpMacro.open=true;
|
||||
if (++ins->std.arpMacro.len>=128) break;
|
||||
if (++ins->std.arpMacro.len>=255) break;
|
||||
if (++ins->std.waveMacro.len>=255) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// waveform width
|
||||
if (lastVal>=10 && (unsigned int)(lastVal-10)<ds.wave.size()) {
|
||||
ins->amiga.waveLen=ds.wave[lastVal-10]->len-1;
|
||||
}
|
||||
|
||||
// vibrato
|
||||
for (int j=0; j<=vibDelay; j++) {
|
||||
ins->std.pitchMacro.val[ins->std.pitchMacro.len]=0;
|
||||
if (++ins->std.pitchMacro.len>=255) break;
|
||||
}
|
||||
int vibPos=0;
|
||||
ins->std.pitchMacro.loop=ins->std.pitchMacro.len;
|
||||
do {
|
||||
vibPos+=vibSpeed;
|
||||
if (vibPos>vibDepth) vibPos=vibDepth;
|
||||
ins->std.pitchMacro.val[ins->std.pitchMacro.len]=vibPos*32;
|
||||
if (++ins->std.pitchMacro.len>=255) break;
|
||||
} while (vibPos<vibDepth);
|
||||
do {
|
||||
vibPos-=vibSpeed;
|
||||
if (vibPos<-vibDepth) vibPos=-vibDepth;
|
||||
ins->std.pitchMacro.val[ins->std.pitchMacro.len]=vibPos*32;
|
||||
if (++ins->std.pitchMacro.len>=255) break;
|
||||
} while (vibPos>-vibDepth);
|
||||
do {
|
||||
vibPos+=vibSpeed;
|
||||
if (vibPos>0) vibPos=0;
|
||||
ins->std.pitchMacro.val[ins->std.pitchMacro.len]=vibPos*32;
|
||||
if (++ins->std.pitchMacro.len>=255) break;
|
||||
} while (vibPos<0);
|
||||
|
||||
ds.ins.push_back(ins);
|
||||
}
|
||||
ds.insLen=(int)ds.ins.size();
|
||||
|
||||
// optimize
|
||||
ds.subsong[0]->optimizePatterns();
|
||||
ds.subsong[0]->rearrangePatterns();
|
||||
|
||||
if (active) quitDispatch();
|
||||
BUSY_BEGIN_SOFT;
|
||||
saveLock.lock();
|
||||
|
|
@ -3039,6 +3307,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len) {
|
|||
ins->std.arpMacro.len=reader.readC();
|
||||
ins->std.arpMacro.loop=reader.readI();
|
||||
ins->std.arpMacro.rel=reader.readI();
|
||||
// TODO: get rid
|
||||
ins->std.arpMacro.mode=reader.readI();
|
||||
for (int j=0; j<ins->std.arpMacro.len; j++) {
|
||||
ins->std.arpMacro.val[j]=reader.readC();
|
||||
|
|
@ -3318,15 +3587,27 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
// high short is channel
|
||||
// low short is pattern number
|
||||
std::vector<PatToWrite> patsToWrite;
|
||||
bool alreadyAdded[256];
|
||||
for (int i=0; i<chans; i++) {
|
||||
for (size_t j=0; j<song.subsong.size(); j++) {
|
||||
DivSubSong* subs=song.subsong[j];
|
||||
memset(alreadyAdded,0,256*sizeof(bool));
|
||||
for (int k=0; k<subs->ordersLen; k++) {
|
||||
if (alreadyAdded[subs->orders.ord[i][k]]) continue;
|
||||
patsToWrite.push_back(PatToWrite(j,i,subs->orders.ord[i][k]));
|
||||
alreadyAdded[subs->orders.ord[i][k]]=true;
|
||||
if (getConfInt("saveUnusedPatterns",0)==1) {
|
||||
for (int i=0; i<chans; i++) {
|
||||
for (size_t j=0; j<song.subsong.size(); j++) {
|
||||
DivSubSong* subs=song.subsong[j];
|
||||
for (int k=0; k<256; k++) {
|
||||
if (subs->pat[i].data[k]==NULL) continue;
|
||||
patsToWrite.push_back(PatToWrite(j,i,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bool alreadyAdded[256];
|
||||
for (int i=0; i<chans; i++) {
|
||||
for (size_t j=0; j<song.subsong.size(); j++) {
|
||||
DivSubSong* subs=song.subsong[j];
|
||||
memset(alreadyAdded,0,256*sizeof(bool));
|
||||
for (int k=0; k<subs->ordersLen; k++) {
|
||||
if (alreadyAdded[subs->orders.ord[i][k]]) continue;
|
||||
patsToWrite.push_back(PatToWrite(j,i,subs->orders.ord[i][k]));
|
||||
alreadyAdded[subs->orders.ord[i][k]]=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3472,7 +3753,9 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
w->writeC(song.brokenOutVol);
|
||||
w->writeC(song.e1e2StopOnSameNote);
|
||||
w->writeC(song.brokenPortaArp);
|
||||
for (int i=0; i<7; i++) {
|
||||
w->writeC(song.snNoLowPeriods);
|
||||
w->writeC(song.delayBehavior);
|
||||
for (int i=0; i<5; i++) {
|
||||
w->writeC(0);
|
||||
}
|
||||
|
||||
|
|
@ -3598,7 +3881,21 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
w->writeI(0xffffffff);
|
||||
}
|
||||
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
// store 16-bit samples as little-endian
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
unsigned char* sampleBuf=(unsigned char*)sample->getCurBuf();
|
||||
size_t bufLen=sample->getCurBufLen();
|
||||
for (size_t i=0; i<bufLen; i+=2) {
|
||||
w->writeC(sampleBuf[i+1]);
|
||||
w->writeC(sampleBuf[i]);
|
||||
}
|
||||
} else {
|
||||
w->write(sample->getCurBuf(),sample->getCurBufLen());
|
||||
}
|
||||
#else
|
||||
w->write(sample->getCurBuf(),sample->getCurBufLen());
|
||||
#endif
|
||||
|
||||
blockEndSeek=w->tell();
|
||||
w->seek(blockStartSeek,SEEK_SET);
|
||||
|
|
@ -3625,7 +3922,13 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
w->writeS(pat->data[j][1]); // octave
|
||||
w->writeS(pat->data[j][2]); // instrument
|
||||
w->writeS(pat->data[j][3]); // volume
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
for (int k=0; k<song.subsong[i.subsong]->pat[i.chan].effectCols*2; k++) {
|
||||
w->writeS(pat->data[j][4+k]);
|
||||
}
|
||||
#else
|
||||
w->write(&pat->data[j][4],2*song.subsong[i.subsong]->pat[i.chan].effectCols*2); // effects
|
||||
#endif
|
||||
}
|
||||
|
||||
w->writeString(pat->name,false);
|
||||
|
|
@ -3907,16 +4210,21 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
w->writeI(i->std.volMacro.val[j]+18);
|
||||
}
|
||||
} else {
|
||||
w->write(i->std.volMacro.val,4*i->std.volMacro.len);
|
||||
for (int j=0; j<i->std.volMacro.len; j++) {
|
||||
w->writeI(i->std.volMacro.val[j]);
|
||||
}
|
||||
}
|
||||
if (i->std.volMacro.len>0) {
|
||||
w->writeC(i->std.volMacro.loop);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: take care of new arp macro format
|
||||
w->writeC(i->std.arpMacro.len);
|
||||
if (i->std.arpMacro.mode) {
|
||||
w->write(i->std.arpMacro.val,4*i->std.arpMacro.len);
|
||||
for (int j=0; j<i->std.arpMacro.len; j++) {
|
||||
w->writeI(i->std.arpMacro.val[j]);
|
||||
}
|
||||
} else {
|
||||
for (int j=0; j<i->std.arpMacro.len; j++) {
|
||||
w->writeI(i->std.arpMacro.val[j]+12);
|
||||
|
|
@ -3933,14 +4241,18 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
w->writeI(i->std.dutyMacro.val[j]+12);
|
||||
}
|
||||
} else {
|
||||
w->write(i->std.dutyMacro.val,4*i->std.dutyMacro.len);
|
||||
for (int j=0; j<i->std.dutyMacro.len; j++) {
|
||||
w->writeI(i->std.dutyMacro.val[j]);
|
||||
}
|
||||
}
|
||||
if (i->std.dutyMacro.len>0) {
|
||||
w->writeC(i->std.dutyMacro.loop);
|
||||
}
|
||||
|
||||
w->writeC(i->std.waveMacro.len);
|
||||
w->write(i->std.waveMacro.val,4*i->std.waveMacro.len);
|
||||
for (int j=0; j<i->std.waveMacro.len; j++) {
|
||||
w->writeI(i->std.waveMacro.val[j]);
|
||||
}
|
||||
if (i->std.waveMacro.len>0) {
|
||||
w->writeC(i->std.waveMacro.loop);
|
||||
}
|
||||
|
|
@ -3991,7 +4303,9 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
w->writeI(i->data[j]>>2);
|
||||
}
|
||||
} else {
|
||||
w->write(i->data,4*i->len);
|
||||
for (int j=0; j<i->len; j++) {
|
||||
w->writeI(i->data[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4004,7 +4318,13 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
w->writeS(pat->data[k][0]); // note
|
||||
w->writeS(pat->data[k][1]); // octave
|
||||
w->writeS(pat->data[k][3]); // volume
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
for (int l=0; l<curPat[i].effectCols*2; l++) {
|
||||
w->writeS(pat->data[k][4+l]);
|
||||
}
|
||||
#else
|
||||
w->write(&pat->data[k][4],2*curPat[i].effectCols*2); // effects
|
||||
#endif
|
||||
w->writeS(pat->data[k][2]); // instrument
|
||||
}
|
||||
}
|
||||
|
|
@ -4023,7 +4343,15 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
w->writeC(50);
|
||||
// i'm too lazy to deal with .dmf's weird way of storing 8-bit samples
|
||||
w->writeC(16);
|
||||
// well I can't be lazy if it's on a big-endian system
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
for (unsigned int j=0; j<i->length16; j++) {
|
||||
w->writeC(((unsigned short)i->data16[j])&0xff);
|
||||
w->writeC(((unsigned short)i->data16[j])>>8);
|
||||
}
|
||||
#else
|
||||
w->write(i->data16,i->length16);
|
||||
#endif
|
||||
}
|
||||
|
||||
saveLock.unlock();
|
||||
|
|
|
|||
|
|
@ -733,6 +733,8 @@ void DivEngine::loadOPLI(SafeReader& reader, std::vector<DivInstrument*>& ret, S
|
|||
ins = new DivInstrument;
|
||||
ins->type = DIV_INS_OPL;
|
||||
ins->name = fmt::sprintf("%s (2)", insName);
|
||||
ins->fm.alg = (feedConnect2nd & 0x1);
|
||||
ins->fm.fb = ((feedConnect2nd >> 1) & 0xF);
|
||||
for (int i : {1,0}) {
|
||||
readOpliOp(reader, ins->fm.op[i]);
|
||||
}
|
||||
|
|
@ -1498,6 +1500,8 @@ void DivEngine::loadWOPL(SafeReader& reader, std::vector<DivInstrument*>& ret, S
|
|||
ins = new DivInstrument;
|
||||
ins->type = DIV_INS_OPL;
|
||||
ins->name = fmt::sprintf("%s (2)", insName);
|
||||
ins->fm.alg = (feedConnect2nd & 0x1);
|
||||
ins->fm.fb = ((feedConnect2nd >> 1) & 0xF);
|
||||
for (int i : {1,0}) {
|
||||
patchSum += readWoplOp(reader, ins->fm.op[i]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ void DivInstrument::putInsData(SafeWriter* w) {
|
|||
w->writeI(std.ex1Macro.loop);
|
||||
w->writeI(std.ex2Macro.loop);
|
||||
w->writeI(std.ex3Macro.loop);
|
||||
w->writeC(std.arpMacro.mode);
|
||||
w->writeC(0); // this was arp macro mode
|
||||
w->writeC(0); // reserved
|
||||
w->writeC(0);
|
||||
w->writeC(0);
|
||||
|
|
@ -543,12 +543,126 @@ void DivInstrument::putInsData(SafeWriter* w) {
|
|||
w->writeC(gb.softEnv);
|
||||
w->writeC(gb.alwaysInit);
|
||||
|
||||
// ES5506
|
||||
w->writeC(es5506.filter.mode);
|
||||
w->writeS(es5506.filter.k1);
|
||||
w->writeS(es5506.filter.k2);
|
||||
w->writeS(es5506.envelope.ecount);
|
||||
w->writeC(es5506.envelope.lVRamp);
|
||||
w->writeC(es5506.envelope.rVRamp);
|
||||
w->writeC(es5506.envelope.k1Ramp);
|
||||
w->writeC(es5506.envelope.k2Ramp);
|
||||
w->writeC(es5506.envelope.k1Slow);
|
||||
w->writeC(es5506.envelope.k2Slow);
|
||||
|
||||
// SNES
|
||||
w->writeC(snes.useEnv);
|
||||
w->writeC(snes.gainMode);
|
||||
w->writeC(snes.gain);
|
||||
w->writeC(snes.a);
|
||||
w->writeC(snes.d);
|
||||
w->writeC(snes.s);
|
||||
w->writeC(snes.r);
|
||||
|
||||
// macro speed/delay
|
||||
w->writeC(std.volMacro.speed);
|
||||
w->writeC(std.arpMacro.speed);
|
||||
w->writeC(std.dutyMacro.speed);
|
||||
w->writeC(std.waveMacro.speed);
|
||||
w->writeC(std.pitchMacro.speed);
|
||||
w->writeC(std.ex1Macro.speed);
|
||||
w->writeC(std.ex2Macro.speed);
|
||||
w->writeC(std.ex3Macro.speed);
|
||||
w->writeC(std.algMacro.speed);
|
||||
w->writeC(std.fbMacro.speed);
|
||||
w->writeC(std.fmsMacro.speed);
|
||||
w->writeC(std.amsMacro.speed);
|
||||
w->writeC(std.panLMacro.speed);
|
||||
w->writeC(std.panRMacro.speed);
|
||||
w->writeC(std.phaseResetMacro.speed);
|
||||
w->writeC(std.ex4Macro.speed);
|
||||
w->writeC(std.ex5Macro.speed);
|
||||
w->writeC(std.ex6Macro.speed);
|
||||
w->writeC(std.ex7Macro.speed);
|
||||
w->writeC(std.ex8Macro.speed);
|
||||
|
||||
w->writeC(std.volMacro.delay);
|
||||
w->writeC(std.arpMacro.delay);
|
||||
w->writeC(std.dutyMacro.delay);
|
||||
w->writeC(std.waveMacro.delay);
|
||||
w->writeC(std.pitchMacro.delay);
|
||||
w->writeC(std.ex1Macro.delay);
|
||||
w->writeC(std.ex2Macro.delay);
|
||||
w->writeC(std.ex3Macro.delay);
|
||||
w->writeC(std.algMacro.delay);
|
||||
w->writeC(std.fbMacro.delay);
|
||||
w->writeC(std.fmsMacro.delay);
|
||||
w->writeC(std.amsMacro.delay);
|
||||
w->writeC(std.panLMacro.delay);
|
||||
w->writeC(std.panRMacro.delay);
|
||||
w->writeC(std.phaseResetMacro.delay);
|
||||
w->writeC(std.ex4Macro.delay);
|
||||
w->writeC(std.ex5Macro.delay);
|
||||
w->writeC(std.ex6Macro.delay);
|
||||
w->writeC(std.ex7Macro.delay);
|
||||
w->writeC(std.ex8Macro.delay);
|
||||
|
||||
// op macro speed/delay
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentSTD::OpMacro& op=std.opMacros[i];
|
||||
|
||||
w->writeC(op.amMacro.speed);
|
||||
w->writeC(op.arMacro.speed);
|
||||
w->writeC(op.drMacro.speed);
|
||||
w->writeC(op.multMacro.speed);
|
||||
w->writeC(op.rrMacro.speed);
|
||||
w->writeC(op.slMacro.speed);
|
||||
w->writeC(op.tlMacro.speed);
|
||||
w->writeC(op.dt2Macro.speed);
|
||||
w->writeC(op.rsMacro.speed);
|
||||
w->writeC(op.dtMacro.speed);
|
||||
w->writeC(op.d2rMacro.speed);
|
||||
w->writeC(op.ssgMacro.speed);
|
||||
w->writeC(op.damMacro.speed);
|
||||
w->writeC(op.dvbMacro.speed);
|
||||
w->writeC(op.egtMacro.speed);
|
||||
w->writeC(op.kslMacro.speed);
|
||||
w->writeC(op.susMacro.speed);
|
||||
w->writeC(op.vibMacro.speed);
|
||||
w->writeC(op.wsMacro.speed);
|
||||
w->writeC(op.ksrMacro.speed);
|
||||
|
||||
w->writeC(op.amMacro.delay);
|
||||
w->writeC(op.arMacro.delay);
|
||||
w->writeC(op.drMacro.delay);
|
||||
w->writeC(op.multMacro.delay);
|
||||
w->writeC(op.rrMacro.delay);
|
||||
w->writeC(op.slMacro.delay);
|
||||
w->writeC(op.tlMacro.delay);
|
||||
w->writeC(op.dt2Macro.delay);
|
||||
w->writeC(op.rsMacro.delay);
|
||||
w->writeC(op.dtMacro.delay);
|
||||
w->writeC(op.d2rMacro.delay);
|
||||
w->writeC(op.ssgMacro.delay);
|
||||
w->writeC(op.damMacro.delay);
|
||||
w->writeC(op.dvbMacro.delay);
|
||||
w->writeC(op.egtMacro.delay);
|
||||
w->writeC(op.kslMacro.delay);
|
||||
w->writeC(op.susMacro.delay);
|
||||
w->writeC(op.vibMacro.delay);
|
||||
w->writeC(op.wsMacro.delay);
|
||||
w->writeC(op.ksrMacro.delay);
|
||||
}
|
||||
|
||||
blockEndSeek=w->tell();
|
||||
w->seek(blockStartSeek,SEEK_SET);
|
||||
w->writeI(blockEndSeek-blockStartSeek-4);
|
||||
w->seek(0,SEEK_END);
|
||||
}
|
||||
|
||||
#define READ_MACRO_VALS(x,y) \
|
||||
for (int macroValPos=0; macroValPos<y; macroValPos++) x[macroValPos]=reader.readI();
|
||||
|
||||
DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) {
|
||||
char magic[4];
|
||||
reader.read(magic,4);
|
||||
|
|
@ -674,10 +788,10 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) {
|
|||
int oldVolHeight=reader.readC();
|
||||
int oldDutyHeight=reader.readC();
|
||||
reader.readC(); // oldWaveHeight
|
||||
reader.read(std.volMacro.val,4*std.volMacro.len);
|
||||
reader.read(std.arpMacro.val,4*std.arpMacro.len);
|
||||
reader.read(std.dutyMacro.val,4*std.dutyMacro.len);
|
||||
reader.read(std.waveMacro.val,4*std.waveMacro.len);
|
||||
READ_MACRO_VALS(std.volMacro.val,std.volMacro.len);
|
||||
READ_MACRO_VALS(std.arpMacro.val,std.arpMacro.len);
|
||||
READ_MACRO_VALS(std.dutyMacro.val,std.dutyMacro.len);
|
||||
READ_MACRO_VALS(std.waveMacro.val,std.waveMacro.len);
|
||||
if (version<31) {
|
||||
if (!std.arpMacro.mode) for (int j=0; j<std.arpMacro.len; j++) {
|
||||
std.arpMacro.val[j]-=12;
|
||||
|
|
@ -692,10 +806,10 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) {
|
|||
}
|
||||
}
|
||||
if (version>=17) {
|
||||
reader.read(std.pitchMacro.val,4*std.pitchMacro.len);
|
||||
reader.read(std.ex1Macro.val,4*std.ex1Macro.len);
|
||||
reader.read(std.ex2Macro.val,4*std.ex2Macro.len);
|
||||
reader.read(std.ex3Macro.val,4*std.ex3Macro.len);
|
||||
READ_MACRO_VALS(std.pitchMacro.val,std.pitchMacro.len);
|
||||
READ_MACRO_VALS(std.ex1Macro.val,std.ex1Macro.len);
|
||||
READ_MACRO_VALS(std.ex2Macro.val,std.ex2Macro.len);
|
||||
READ_MACRO_VALS(std.ex3Macro.val,std.ex3Macro.len);
|
||||
} else {
|
||||
if (type==DIV_INS_STD) {
|
||||
if (oldVolHeight==31) {
|
||||
|
|
@ -730,10 +844,10 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) {
|
|||
std.fmsMacro.open=reader.readC();
|
||||
std.amsMacro.open=reader.readC();
|
||||
|
||||
reader.read(std.algMacro.val,4*std.algMacro.len);
|
||||
reader.read(std.fbMacro.val,4*std.fbMacro.len);
|
||||
reader.read(std.fmsMacro.val,4*std.fmsMacro.len);
|
||||
reader.read(std.amsMacro.val,4*std.amsMacro.len);
|
||||
READ_MACRO_VALS(std.algMacro.val,std.algMacro.len);
|
||||
READ_MACRO_VALS(std.fbMacro.val,std.fbMacro.len);
|
||||
READ_MACRO_VALS(std.fmsMacro.val,std.fmsMacro.len);
|
||||
READ_MACRO_VALS(std.amsMacro.val,std.amsMacro.len);
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentSTD::OpMacro& op=std.opMacros[i];
|
||||
|
|
@ -936,15 +1050,15 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) {
|
|||
// clear noise macro if PCE instrument and version<63
|
||||
if (version<63 && type==DIV_INS_PCE) {
|
||||
std.dutyMacro.len=0;
|
||||
std.dutyMacro.loop=-1;
|
||||
std.dutyMacro.rel=-1;
|
||||
std.dutyMacro.loop=255;
|
||||
std.dutyMacro.rel=255;
|
||||
}
|
||||
|
||||
// clear wave macro if OPLL instrument and version<70
|
||||
if (version<70 && type==DIV_INS_OPLL) {
|
||||
std.waveMacro.len=0;
|
||||
std.waveMacro.loop=-1;
|
||||
std.waveMacro.rel=-1;
|
||||
std.waveMacro.loop=255;
|
||||
std.waveMacro.rel=255;
|
||||
}
|
||||
|
||||
// sample map
|
||||
|
|
@ -1007,14 +1121,14 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) {
|
|||
std.ex7Macro.open=reader.readC();
|
||||
std.ex8Macro.open=reader.readC();
|
||||
|
||||
reader.read(std.panLMacro.val,4*std.panLMacro.len);
|
||||
reader.read(std.panRMacro.val,4*std.panRMacro.len);
|
||||
reader.read(std.phaseResetMacro.val,4*std.phaseResetMacro.len);
|
||||
reader.read(std.ex4Macro.val,4*std.ex4Macro.len);
|
||||
reader.read(std.ex5Macro.val,4*std.ex5Macro.len);
|
||||
reader.read(std.ex6Macro.val,4*std.ex6Macro.len);
|
||||
reader.read(std.ex7Macro.val,4*std.ex7Macro.len);
|
||||
reader.read(std.ex8Macro.val,4*std.ex8Macro.len);
|
||||
READ_MACRO_VALS(std.panLMacro.val,std.panLMacro.len);
|
||||
READ_MACRO_VALS(std.panRMacro.val,std.panRMacro.len);
|
||||
READ_MACRO_VALS(std.phaseResetMacro.val,std.phaseResetMacro.len);
|
||||
READ_MACRO_VALS(std.ex4Macro.val,std.ex4Macro.len);
|
||||
READ_MACRO_VALS(std.ex5Macro.val,std.ex5Macro.len);
|
||||
READ_MACRO_VALS(std.ex6Macro.val,std.ex6Macro.len);
|
||||
READ_MACRO_VALS(std.ex7Macro.val,std.ex7Macro.len);
|
||||
READ_MACRO_VALS(std.ex8Macro.val,std.ex8Macro.len);
|
||||
|
||||
// FDS
|
||||
fds.modSpeed=reader.readI();
|
||||
|
|
@ -1111,6 +1225,136 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) {
|
|||
gb.alwaysInit=reader.readC();
|
||||
}
|
||||
|
||||
// ES5506
|
||||
if (version>=107) {
|
||||
es5506.filter.mode=(DivInstrumentES5506::Filter::FilterMode)reader.readC();
|
||||
es5506.filter.k1=reader.readS();
|
||||
es5506.filter.k2=reader.readS();
|
||||
es5506.envelope.ecount=reader.readS();
|
||||
es5506.envelope.lVRamp=reader.readC();
|
||||
es5506.envelope.rVRamp=reader.readC();
|
||||
es5506.envelope.k1Ramp=reader.readC();
|
||||
es5506.envelope.k2Ramp=reader.readC();
|
||||
es5506.envelope.k1Slow=reader.readC();
|
||||
es5506.envelope.k2Slow=reader.readC();
|
||||
}
|
||||
|
||||
// SNES
|
||||
if (version>=109) {
|
||||
snes.useEnv=reader.readC();
|
||||
snes.gainMode=(DivInstrumentSNES::GainMode)reader.readC();
|
||||
snes.gain=reader.readC();
|
||||
snes.a=reader.readC();
|
||||
snes.d=reader.readC();
|
||||
snes.s=reader.readC();
|
||||
snes.r=reader.readC();
|
||||
}
|
||||
|
||||
// macro speed/delay
|
||||
if (version>=111) {
|
||||
std.volMacro.speed=reader.readC();
|
||||
std.arpMacro.speed=reader.readC();
|
||||
std.dutyMacro.speed=reader.readC();
|
||||
std.waveMacro.speed=reader.readC();
|
||||
std.pitchMacro.speed=reader.readC();
|
||||
std.ex1Macro.speed=reader.readC();
|
||||
std.ex2Macro.speed=reader.readC();
|
||||
std.ex3Macro.speed=reader.readC();
|
||||
std.algMacro.speed=reader.readC();
|
||||
std.fbMacro.speed=reader.readC();
|
||||
std.fmsMacro.speed=reader.readC();
|
||||
std.amsMacro.speed=reader.readC();
|
||||
std.panLMacro.speed=reader.readC();
|
||||
std.panRMacro.speed=reader.readC();
|
||||
std.phaseResetMacro.speed=reader.readC();
|
||||
std.ex4Macro.speed=reader.readC();
|
||||
std.ex5Macro.speed=reader.readC();
|
||||
std.ex6Macro.speed=reader.readC();
|
||||
std.ex7Macro.speed=reader.readC();
|
||||
std.ex8Macro.speed=reader.readC();
|
||||
|
||||
std.volMacro.delay=reader.readC();
|
||||
std.arpMacro.delay=reader.readC();
|
||||
std.dutyMacro.delay=reader.readC();
|
||||
std.waveMacro.delay=reader.readC();
|
||||
std.pitchMacro.delay=reader.readC();
|
||||
std.ex1Macro.delay=reader.readC();
|
||||
std.ex2Macro.delay=reader.readC();
|
||||
std.ex3Macro.delay=reader.readC();
|
||||
std.algMacro.delay=reader.readC();
|
||||
std.fbMacro.delay=reader.readC();
|
||||
std.fmsMacro.delay=reader.readC();
|
||||
std.amsMacro.delay=reader.readC();
|
||||
std.panLMacro.delay=reader.readC();
|
||||
std.panRMacro.delay=reader.readC();
|
||||
std.phaseResetMacro.delay=reader.readC();
|
||||
std.ex4Macro.delay=reader.readC();
|
||||
std.ex5Macro.delay=reader.readC();
|
||||
std.ex6Macro.delay=reader.readC();
|
||||
std.ex7Macro.delay=reader.readC();
|
||||
std.ex8Macro.delay=reader.readC();
|
||||
|
||||
// op macro speed/delay
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentSTD::OpMacro& op=std.opMacros[i];
|
||||
|
||||
op.amMacro.speed=reader.readC();
|
||||
op.arMacro.speed=reader.readC();
|
||||
op.drMacro.speed=reader.readC();
|
||||
op.multMacro.speed=reader.readC();
|
||||
op.rrMacro.speed=reader.readC();
|
||||
op.slMacro.speed=reader.readC();
|
||||
op.tlMacro.speed=reader.readC();
|
||||
op.dt2Macro.speed=reader.readC();
|
||||
op.rsMacro.speed=reader.readC();
|
||||
op.dtMacro.speed=reader.readC();
|
||||
op.d2rMacro.speed=reader.readC();
|
||||
op.ssgMacro.speed=reader.readC();
|
||||
op.damMacro.speed=reader.readC();
|
||||
op.dvbMacro.speed=reader.readC();
|
||||
op.egtMacro.speed=reader.readC();
|
||||
op.kslMacro.speed=reader.readC();
|
||||
op.susMacro.speed=reader.readC();
|
||||
op.vibMacro.speed=reader.readC();
|
||||
op.wsMacro.speed=reader.readC();
|
||||
op.ksrMacro.speed=reader.readC();
|
||||
|
||||
op.amMacro.delay=reader.readC();
|
||||
op.arMacro.delay=reader.readC();
|
||||
op.drMacro.delay=reader.readC();
|
||||
op.multMacro.delay=reader.readC();
|
||||
op.rrMacro.delay=reader.readC();
|
||||
op.slMacro.delay=reader.readC();
|
||||
op.tlMacro.delay=reader.readC();
|
||||
op.dt2Macro.delay=reader.readC();
|
||||
op.rsMacro.delay=reader.readC();
|
||||
op.dtMacro.delay=reader.readC();
|
||||
op.d2rMacro.delay=reader.readC();
|
||||
op.ssgMacro.delay=reader.readC();
|
||||
op.damMacro.delay=reader.readC();
|
||||
op.dvbMacro.delay=reader.readC();
|
||||
op.egtMacro.delay=reader.readC();
|
||||
op.kslMacro.delay=reader.readC();
|
||||
op.susMacro.delay=reader.readC();
|
||||
op.vibMacro.delay=reader.readC();
|
||||
op.wsMacro.delay=reader.readC();
|
||||
op.ksrMacro.delay=reader.readC();
|
||||
}
|
||||
}
|
||||
|
||||
// old arp macro format
|
||||
if (version<112) {
|
||||
if (std.arpMacro.mode) {
|
||||
std.arpMacro.mode=0;
|
||||
for (int i=0; i<std.arpMacro.len; i++) {
|
||||
std.arpMacro.val[i]^=0x40000000;
|
||||
}
|
||||
if ((std.arpMacro.loop>=std.arpMacro.len || (std.arpMacro.rel>std.arpMacro.loop && std.arpMacro.rel<std.arpMacro.len)) && std.arpMacro.len<255) {
|
||||
std.arpMacro.val[std.arpMacro.len++]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DIV_DATA_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -1150,3 +1394,148 @@ bool DivInstrument::save(const char* path) {
|
|||
w->finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DivInstrument::saveDMP(const char* path) {
|
||||
SafeWriter* w=new SafeWriter();
|
||||
w->init();
|
||||
|
||||
// write version
|
||||
w->writeC(11);
|
||||
|
||||
// guess the system
|
||||
switch (type) {
|
||||
case DIV_INS_FM:
|
||||
// we can't tell between Genesis, Neo Geo and Arcade ins type yet
|
||||
w->writeC(0x02);
|
||||
w->writeC(1);
|
||||
break;
|
||||
case DIV_INS_STD:
|
||||
// we can't tell between SMS and NES ins type yet
|
||||
w->writeC(0x03);
|
||||
w->writeC(0);
|
||||
break;
|
||||
case DIV_INS_GB:
|
||||
w->writeC(0x04);
|
||||
w->writeC(0);
|
||||
break;
|
||||
case DIV_INS_C64:
|
||||
w->writeC(0x07);
|
||||
w->writeC(0);
|
||||
break;
|
||||
case DIV_INS_PCE:
|
||||
w->writeC(0x06);
|
||||
w->writeC(0);
|
||||
break;
|
||||
case DIV_INS_OPLL:
|
||||
// ???
|
||||
w->writeC(0x13);
|
||||
w->writeC(1);
|
||||
break;
|
||||
case DIV_INS_OPZ:
|
||||
// data will be lost
|
||||
w->writeC(0x08);
|
||||
w->writeC(1);
|
||||
break;
|
||||
case DIV_INS_FDS:
|
||||
// ???
|
||||
w->writeC(0x06);
|
||||
w->writeC(0);
|
||||
break;
|
||||
default:
|
||||
// not supported by .dmp
|
||||
w->finish();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type==DIV_INS_FM || type==DIV_INS_OPLL || type==DIV_INS_OPZ) {
|
||||
w->writeC(fm.fms);
|
||||
w->writeC(fm.fb);
|
||||
w->writeC(fm.alg);
|
||||
w->writeC(fm.ams);
|
||||
|
||||
// TODO: OPLL params
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=fm.op[i];
|
||||
w->writeC(op.mult);
|
||||
w->writeC(op.tl);
|
||||
w->writeC(op.ar);
|
||||
w->writeC(op.dr);
|
||||
w->writeC(op.sl);
|
||||
w->writeC(op.rr);
|
||||
w->writeC(op.am);
|
||||
w->writeC(op.rs);
|
||||
w->writeC(op.dt|(op.dt2<<4));
|
||||
w->writeC(op.d2r);
|
||||
w->writeC(op.ssgEnv);
|
||||
}
|
||||
} else {
|
||||
if (type!=DIV_INS_GB) {
|
||||
w->writeC(std.volMacro.len);
|
||||
for (int i=0; i<std.volMacro.len; i++) {
|
||||
w->writeI(std.volMacro.val[i]);
|
||||
}
|
||||
if (std.volMacro.len>0) w->writeC(std.volMacro.loop);
|
||||
}
|
||||
|
||||
w->writeC(std.arpMacro.len);
|
||||
for (int i=0; i<std.arpMacro.len; i++) {
|
||||
w->writeI(std.arpMacro.val[i]+12);
|
||||
}
|
||||
if (std.arpMacro.len>0) w->writeC(std.arpMacro.loop);
|
||||
w->writeC(std.arpMacro.mode);
|
||||
|
||||
w->writeC(std.dutyMacro.len);
|
||||
for (int i=0; i<std.dutyMacro.len; i++) {
|
||||
w->writeI(std.dutyMacro.val[i]+12);
|
||||
}
|
||||
if (std.dutyMacro.len>0) w->writeC(std.dutyMacro.loop);
|
||||
|
||||
w->writeC(std.waveMacro.len);
|
||||
for (int i=0; i<std.waveMacro.len; i++) {
|
||||
w->writeI(std.waveMacro.val[i]+12);
|
||||
}
|
||||
if (std.waveMacro.len>0) w->writeC(std.waveMacro.loop);
|
||||
|
||||
if (type==DIV_INS_C64) {
|
||||
w->writeC(c64.triOn);
|
||||
w->writeC(c64.sawOn);
|
||||
w->writeC(c64.pulseOn);
|
||||
w->writeC(c64.noiseOn);
|
||||
w->writeC(c64.a);
|
||||
w->writeC(c64.d);
|
||||
w->writeC(c64.s);
|
||||
w->writeC(c64.r);
|
||||
w->writeC((c64.duty*100)/4095);
|
||||
w->writeC(c64.ringMod);
|
||||
w->writeC(c64.oscSync);
|
||||
w->writeC(c64.toFilter);
|
||||
w->writeC(c64.volIsCutoff);
|
||||
w->writeC(c64.initFilter);
|
||||
w->writeC(c64.res);
|
||||
w->writeC((c64.cut*100)/2047);
|
||||
w->writeC(c64.hp);
|
||||
w->writeC(c64.lp);
|
||||
w->writeC(c64.bp);
|
||||
w->writeC(c64.ch3off);
|
||||
}
|
||||
if (type==DIV_INS_GB) {
|
||||
w->writeC(gb.envVol);
|
||||
w->writeC(gb.envDir);
|
||||
w->writeC(gb.envLen);
|
||||
w->writeC(gb.soundLen);
|
||||
}
|
||||
}
|
||||
|
||||
FILE* outFile=ps_fopen(path,"wb");
|
||||
if (outFile==NULL) {
|
||||
logE("could not save instrument: %s!",strerror(errno));
|
||||
w->finish();
|
||||
return false;
|
||||
}
|
||||
if (fwrite(w->getFinalBuf(),1,w->size(),outFile)!=w->size()) {
|
||||
logW("did not write entire instrument!");
|
||||
}
|
||||
fclose(outFile);
|
||||
w->finish();
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -173,21 +173,20 @@ struct DivInstrumentMacro {
|
|||
int val[256];
|
||||
unsigned int mode;
|
||||
bool open;
|
||||
unsigned char len;
|
||||
signed char loop;
|
||||
signed char rel;
|
||||
unsigned char len, delay, speed, loop, rel;
|
||||
|
||||
// the following variables are used by the GUI and not saved in the file
|
||||
int vScroll, vZoom;
|
||||
|
||||
|
||||
explicit DivInstrumentMacro(const String& n, bool initOpen=false):
|
||||
name(n),
|
||||
mode(0),
|
||||
open(initOpen),
|
||||
len(0),
|
||||
loop(-1),
|
||||
rel(-1),
|
||||
delay(0),
|
||||
speed(1),
|
||||
loop(255),
|
||||
rel(255),
|
||||
vScroll(0),
|
||||
vZoom(-1) {
|
||||
memset(val,0,256*sizeof(int));
|
||||
|
|
@ -576,6 +575,13 @@ struct DivInstrument {
|
|||
* @return whether it was successful.
|
||||
*/
|
||||
bool save(const char* path);
|
||||
|
||||
/**
|
||||
* save this instrument to a file in .dmp format.
|
||||
* @param path file path.
|
||||
* @return whether it was successful.
|
||||
*/
|
||||
bool saveDMP(const char* path);
|
||||
DivInstrument():
|
||||
name(""),
|
||||
type(DIV_INS_FM) {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,18 @@ void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tic
|
|||
had=false;
|
||||
return;
|
||||
}
|
||||
if (delay>0) {
|
||||
delay--;
|
||||
return;
|
||||
}
|
||||
if (began && source.delay>0) {
|
||||
delay=source.delay;
|
||||
} else {
|
||||
delay=source.speed-1;
|
||||
}
|
||||
if (began) {
|
||||
began=false;
|
||||
}
|
||||
if (finished) {
|
||||
finished=false;
|
||||
}
|
||||
|
|
@ -41,16 +53,17 @@ void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tic
|
|||
actualHad=has;
|
||||
had=actualHad;
|
||||
if (has) {
|
||||
lastPos=pos;
|
||||
val=source.val[pos++];
|
||||
if (source.rel>=0 && pos>source.rel && !released) {
|
||||
if (source.loop<source.len && source.loop>=0 && source.loop<source.rel) {
|
||||
if (pos>source.rel && !released) {
|
||||
if (source.loop<source.len && source.loop<source.rel) {
|
||||
pos=source.loop;
|
||||
} else {
|
||||
pos--;
|
||||
}
|
||||
}
|
||||
if (pos>=source.len) {
|
||||
if (source.loop<source.len && source.loop>=0 && (source.loop>=source.rel || source.rel>=source.len)) {
|
||||
if (source.loop<source.len && (source.loop>=source.rel || source.rel>=source.len)) {
|
||||
pos=source.loop;
|
||||
} else if (linger) {
|
||||
pos--;
|
||||
|
|
@ -239,7 +252,7 @@ void DivMacroInt::init(DivInstrument* which) {
|
|||
for (size_t i=0; i<macroListLen; i++) {
|
||||
if (macroSource[i]!=NULL) {
|
||||
macroList[i]->prepare(*macroSource[i],e);
|
||||
hasRelease=(macroSource[i]->rel>=0 && macroSource[i]->rel<macroSource[i]->len);
|
||||
hasRelease=(macroSource[i]->rel<macroSource[i]->len);
|
||||
} else {
|
||||
hasRelease=false;
|
||||
}
|
||||
|
|
@ -251,3 +264,110 @@ void DivMacroInt::notifyInsDeletion(DivInstrument* which) {
|
|||
init(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// randomly-generated
|
||||
constexpr unsigned int hashTable[256]={
|
||||
0x0718657, 0xe904eb33, 0x14b2da2b, 0x0ef67ca9,
|
||||
0x0f0559a, 0x4142065a, 0x4d9ab4ba, 0x3cdd601a,
|
||||
0x6635aca, 0x2c41ab72, 0xf98e8d31, 0x1003ee63,
|
||||
0x3fd9fb5, 0x30734d16, 0xe8964431, 0x29bb9b79,
|
||||
0x817f580, 0xfe083b9e, 0x974b5e85, 0x3b5729c2,
|
||||
0x2afea96, 0xf1573b4b, 0x308a1024, 0xaa94b92d,
|
||||
0x693fa93, 0x547ba3da, 0xac4f206c, 0x93f72ea9,
|
||||
0xcc44001, 0x37e27670, 0xf35a63d0, 0xd1cdbb92,
|
||||
0x7c7ee24, 0xfa267ee9, 0xf9cd9956, 0x6a6768d4,
|
||||
0x9e6a108, 0xf6ca4bd0, 0xa53cba9f, 0x526a523a,
|
||||
0xf46f0c8, 0xf131bd4c, 0x82800d48, 0xabff9214,
|
||||
0x40eabd4, 0xea0ef8f7, 0xdc3968d6, 0x54c3cb63,
|
||||
0x8855023, 0xaab73861, 0xff0bea2c, 0x139b9765,
|
||||
0x4a21279, 0x6b2aa29a, 0xf147cc3f, 0xc42edc1a,
|
||||
0xfe2f86f, 0x6d352047, 0xd3cac3e4, 0x35e5c389,
|
||||
0xe923727, 0x12fe3b32, 0x204295c5, 0x254a8b7a,
|
||||
0xc1d995d, 0x26a512d2, 0xa3e34033, 0x9a968df0,
|
||||
0x53447ed, 0x36cf4077, 0x189b03a7, 0x558790e8,
|
||||
0x01f921a, 0x840f260c, 0x93dd2b86, 0x12f69cb0,
|
||||
0x117d93a, 0xcb2cbc2b, 0xd41e3aed, 0x5ff6ec75,
|
||||
0x607290d, 0xd41adb92, 0x64f94ba7, 0xaff720f7,
|
||||
0x6bf1d5d, 0xc8e36c6d, 0x7095bab5, 0xdfbf7b0d,
|
||||
0x01ddeea, 0xe8f262da, 0xf589512f, 0xc2ecac5d,
|
||||
0xbe29d98, 0xff8b5a2e, 0x18e7279e, 0x6ad24dcb,
|
||||
0x2b3b9b1, 0x6f5227d8, 0x076d7553, 0x6c5856e2,
|
||||
0x995f655, 0xe9fcf5a6, 0x83671b70, 0xaf3aed1e,
|
||||
0xac340f0, 0x5c7008b4, 0x14651282, 0x8bf855b9,
|
||||
0x4a933af, 0x829b87f1, 0x9a673070, 0xb19da64f,
|
||||
0x77d8f36, 0x584c9fdc, 0xa9e52c0d, 0x6da5e13d,
|
||||
0xae1051f, 0xe85e976f, 0xfeac2d9a, 0x19c46754,
|
||||
0x1cba6f3, 0xaf21bc31, 0x16b6a8d4, 0xe08b0fdb,
|
||||
0x97e6e54, 0x5da499ae, 0xab472e19, 0xc2491f2e,
|
||||
0xc08c563, 0xe91b131b, 0xc8e22451, 0x6995c8fe,
|
||||
0x7042718, 0x01043738, 0xc7d88b28, 0x2d9f330f,
|
||||
0x4b3aae5, 0xf1e705ba, 0xc5b8ee59, 0xa8ba4e8f,
|
||||
0x55f65a2, 0xa1899e41, 0x296243c8, 0x1e502bf2,
|
||||
0x20080de, 0x841d2239, 0x37b082af, 0xbdd7f7da,
|
||||
0x4075090, 0x1dc7dc49, 0x5cd3c69a, 0x7fb13b62,
|
||||
0xb382bf1, 0xa0cfbc2f, 0x9eca4dc1, 0xb9355453,
|
||||
0x5d0dd24, 0x834f4d8e, 0xe9b136b2, 0xe7b8738d,
|
||||
0x1c91d41, 0x8cb3ddb5, 0xdc600590, 0x607cff55,
|
||||
0x2ca7675, 0x4622a8e4, 0x9340e414, 0xcb44928a,
|
||||
0xa9e791c, 0x68849920, 0xc5b5fcd8, 0xbc352269,
|
||||
0x3ab13cf, 0xaa3cbbd0, 0x1abacc64, 0x623b5b49,
|
||||
0xcc8c4c3, 0x3c8f2f70, 0x3e584a28, 0x9316d24d,
|
||||
0xfe315a2, 0x10f0ba7a, 0xed15a523, 0x4f987369,
|
||||
0x7aa4a4a, 0x90eaf98f, 0xcf0af610, 0x1b38f4e7,
|
||||
0x19df72d, 0xd8306808, 0xd54e25ac, 0x76b79c6d,
|
||||
0x58110cf, 0x06a3e5f2, 0x873a6039, 0xf52684e3,
|
||||
0xecf39c3, 0x7cbb2759, 0xe280d361, 0x91e8471a,
|
||||
0xa67cdd3, 0x17cac3be, 0xfc9eff1f, 0x71abdf49,
|
||||
0x6168624, 0xb68f86f7, 0x67a8e72a, 0xe746911d,
|
||||
0xca48fd7, 0x8f3cc436, 0x3a3851a8, 0x30a7e26e,
|
||||
0xca49308, 0xb598ef74, 0x49ef167a, 0xa9e17632,
|
||||
0x0f7308a, 0xf156efed, 0xcf799645, 0xbae4b85a,
|
||||
0xecba3fe, 0xd97f861d, 0xc164af62, 0xb1aca42f,
|
||||
0xf249576, 0x83d1bf4e, 0x2f486a9c, 0xd3b53cc2,
|
||||
0x17d7c26, 0xd95ddae1, 0x76c1a2f5, 0xf8af6782,
|
||||
0xdbaece4, 0x010b2b53, 0x049be200, 0xd9fd0d1a,
|
||||
0x37d7e6c, 0x5b848651, 0x203c98c7, 0x669681b0,
|
||||
0x683086f, 0xdd0ee8ab, 0x5dbe008b, 0xe5d0690d,
|
||||
0x23dd758, 0x6b34acbc, 0x4b2b3e65, 0xcc7b56c1,
|
||||
0x196b0a0, 0x7b065105, 0xb731b01a, 0xd37daa16,
|
||||
0xf77816b, 0x3c9fa546, 0x81dfadb8, 0x39b1fb8b
|
||||
};
|
||||
|
||||
constexpr unsigned int NAME_HASH(const char* name) {
|
||||
unsigned int nameHash=0xffffffff;
|
||||
for (const char* i=name; *i; i++) {
|
||||
nameHash=(nameHash>>8)^hashTable[(unsigned char)*i];
|
||||
}
|
||||
return nameHash;
|
||||
}
|
||||
|
||||
#define CONSIDER(x) case NAME_HASH(#x): return &x; break;
|
||||
|
||||
DivMacroStruct* DivMacroInt::structByName(const String& name) {
|
||||
unsigned int hash=NAME_HASH(name.c_str());
|
||||
|
||||
switch (hash) {
|
||||
CONSIDER(vol)
|
||||
CONSIDER(arp)
|
||||
CONSIDER(duty)
|
||||
CONSIDER(wave)
|
||||
CONSIDER(pitch)
|
||||
CONSIDER(ex1)
|
||||
CONSIDER(ex2)
|
||||
CONSIDER(ex3)
|
||||
CONSIDER(alg)
|
||||
CONSIDER(fb)
|
||||
CONSIDER(fms)
|
||||
CONSIDER(ams)
|
||||
CONSIDER(panL)
|
||||
CONSIDER(panR)
|
||||
CONSIDER(phaseReset)
|
||||
CONSIDER(ex4)
|
||||
CONSIDER(ex5)
|
||||
CONSIDER(ex6)
|
||||
CONSIDER(ex7)
|
||||
CONSIDER(ex8)
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,21 +25,24 @@
|
|||
class DivEngine;
|
||||
|
||||
struct DivMacroStruct {
|
||||
int pos;
|
||||
int pos, lastPos, delay;
|
||||
int val;
|
||||
bool has, had, actualHad, finished, will, linger;
|
||||
bool has, had, actualHad, finished, will, linger, began;
|
||||
unsigned int mode;
|
||||
void doMacro(DivInstrumentMacro& source, bool released, bool tick);
|
||||
void init() {
|
||||
pos=mode=0;
|
||||
pos=lastPos=mode=delay=0;
|
||||
has=had=actualHad=will=false;
|
||||
linger=false;
|
||||
began=true;
|
||||
// TODO: test whether this breaks anything?
|
||||
val=0;
|
||||
}
|
||||
void prepare(DivInstrumentMacro& source, DivEngine* e);
|
||||
DivMacroStruct():
|
||||
pos(0),
|
||||
lastPos(0),
|
||||
delay(0),
|
||||
val(0),
|
||||
has(false),
|
||||
had(false),
|
||||
|
|
@ -47,6 +50,7 @@ struct DivMacroStruct {
|
|||
finished(false),
|
||||
will(false),
|
||||
linger(false),
|
||||
began(false),
|
||||
mode(0) {}
|
||||
};
|
||||
|
||||
|
|
@ -127,6 +131,13 @@ class DivMacroInt {
|
|||
*/
|
||||
void notifyInsDeletion(DivInstrument* which);
|
||||
|
||||
/**
|
||||
* get DivMacroStruct by macro name.
|
||||
* @param which the macro name.
|
||||
* @return a DivMacroStruct, or NULL if none found.
|
||||
*/
|
||||
DivMacroStruct* structByName(const String& name);
|
||||
|
||||
DivMacroInt():
|
||||
e(NULL),
|
||||
ins(NULL),
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "engine.h"
|
||||
#include "../ta-log.h"
|
||||
|
||||
static DivPattern emptyPat;
|
||||
|
||||
|
|
@ -40,6 +41,44 @@ DivPattern* DivChannelData::getPattern(int index, bool create) {
|
|||
return data[index];
|
||||
}
|
||||
|
||||
std::vector<std::pair<int,int>> DivChannelData::optimize() {
|
||||
std::vector<std::pair<int,int>> ret;
|
||||
for (int i=0; i<256; i++) {
|
||||
if (data[i]!=NULL) {
|
||||
// compare
|
||||
for (int j=0; j<256; j++) {
|
||||
if (j==i) continue;
|
||||
if (data[j]==NULL) continue;
|
||||
if (memcmp(data[i]->data,data[j]->data,256*32*sizeof(short))==0) {
|
||||
delete data[j];
|
||||
data[j]=NULL;
|
||||
logV("%d == %d",i,j);
|
||||
ret.push_back(std::pair<int,int>(j,i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::pair<int,int>> DivChannelData::rearrange() {
|
||||
std::vector<std::pair<int,int>> ret;
|
||||
for (int i=0; i<256; i++) {
|
||||
if (data[i]==NULL) {
|
||||
for (int j=i; j<256; j++) {
|
||||
if (data[j]!=NULL) {
|
||||
data[i]=data[j];
|
||||
data[j]=NULL;
|
||||
logV("%d -> %d",j,i);
|
||||
ret.push_back(std::pair<int,int>(j,i));
|
||||
if (++i>=256) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DivChannelData::wipePatterns() {
|
||||
for (int i=0; i<256; i++) {
|
||||
if (data[i]!=NULL) {
|
||||
|
|
@ -54,81 +93,6 @@ void DivPattern::copyOn(DivPattern* dest) {
|
|||
memcpy(dest->data,data,sizeof(data));
|
||||
}
|
||||
|
||||
SafeReader* DivPattern::compile(int len, int fxRows) {
|
||||
SafeWriter w;
|
||||
w.init();
|
||||
short lastNote, lastOctave, lastInstr, lastVolume, lastEffect[8], lastEffectVal[8];
|
||||
unsigned char rows=0;
|
||||
|
||||
lastNote=0;
|
||||
lastOctave=0;
|
||||
lastInstr=-1;
|
||||
lastVolume=-1;
|
||||
memset(lastEffect,-1,8*sizeof(short));
|
||||
memset(lastEffectVal,-1,8*sizeof(short));
|
||||
|
||||
for (int i=0; i<len; i++) {
|
||||
unsigned char mask=0;
|
||||
if (data[i][0]!=-1) {
|
||||
lastNote=data[i][0];
|
||||
lastOctave=data[i][1];
|
||||
mask|=128;
|
||||
}
|
||||
if (data[i][2]!=-1 && data[i][2]!=lastInstr) {
|
||||
lastInstr=data[i][2];
|
||||
mask|=32;
|
||||
}
|
||||
if (data[i][3]!=-1 && data[i][3]!=lastVolume) {
|
||||
lastVolume=data[i][3];
|
||||
mask|=64;
|
||||
}
|
||||
for (int j=0; j<fxRows; j++) {
|
||||
if (data[i][4+(j<<1)]!=-1) {
|
||||
lastEffect[j]=data[i][4+(j<<1)];
|
||||
lastEffectVal[j]=data[i][5+(j<<1)];
|
||||
mask=(mask&0xf8)|j;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mask) {
|
||||
rows++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rows!=0) {
|
||||
w.writeC(rows);
|
||||
}
|
||||
rows=1;
|
||||
|
||||
w.writeC(mask);
|
||||
if (mask&128) {
|
||||
if (lastNote==100) {
|
||||
w.writeC(-128);
|
||||
} else {
|
||||
w.writeC(lastNote+(lastOctave*12));
|
||||
}
|
||||
}
|
||||
if (mask&64) {
|
||||
w.writeC(lastVolume);
|
||||
}
|
||||
if (mask&32) {
|
||||
w.writeC(lastInstr);
|
||||
}
|
||||
for (int j=0; j<(mask&7); j++) {
|
||||
w.writeC(lastEffect[j]);
|
||||
if (lastEffectVal[j]==-1) {
|
||||
w.writeC(0);
|
||||
} else {
|
||||
w.writeC(lastEffectVal[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
w.writeC(rows);
|
||||
w.writeC(0);
|
||||
|
||||
return w.toReader();
|
||||
}
|
||||
|
||||
DivChannelData::DivChannelData():
|
||||
effectCols(1) {
|
||||
memset(data,0,256*sizeof(void*));
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "safeReader.h"
|
||||
#include <vector>
|
||||
|
||||
struct DivPattern {
|
||||
String name;
|
||||
|
|
@ -28,14 +29,6 @@ struct DivPattern {
|
|||
* @param dest the destination pattern.
|
||||
*/
|
||||
void copyOn(DivPattern* dest);
|
||||
|
||||
/**
|
||||
* don't use yet!
|
||||
* @param len the pattern length
|
||||
* @param fxRows number of effect ...columns
|
||||
* @return a SafeReader.
|
||||
*/
|
||||
SafeReader* compile(int len=256, int fxRows=1);
|
||||
DivPattern();
|
||||
};
|
||||
|
||||
|
|
@ -59,6 +52,20 @@ struct DivChannelData {
|
|||
*/
|
||||
DivPattern* getPattern(int index, bool create);
|
||||
|
||||
/**
|
||||
* optimize pattern data.
|
||||
* not thread-safe! use a mutex!
|
||||
* @return a list of From -> To pairs
|
||||
*/
|
||||
std::vector<std::pair<int,int>> optimize();
|
||||
|
||||
/**
|
||||
* re-arrange NULLs.
|
||||
* not thread-safe! use a mutex!
|
||||
* @return a list of From -> To pairs
|
||||
*/
|
||||
std::vector<std::pair<int,int>> rearrange();
|
||||
|
||||
/**
|
||||
* destroy all patterns on this DivChannelData.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -94,10 +94,6 @@ bool DivDispatch::getWantPreNote() {
|
|||
return false;
|
||||
}
|
||||
|
||||
const char* DivDispatch::getEffectName(unsigned char effect) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivDispatch::setFlags(unsigned int flags) {
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -64,21 +64,6 @@ const char** DivPlatformAmiga::getRegisterSheet() {
|
|||
return regCheatSheetAmiga;
|
||||
}
|
||||
|
||||
const char* DivPlatformAmiga::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Toggle filter (0 disables; 1 enables)";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Toggle AM with next channel";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Toggle period modulation with next channel";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define writeAudDat(x) \
|
||||
chan[i].audDat=x; \
|
||||
if (i<3 && chan[i].useV) { \
|
||||
|
|
@ -178,19 +163,9 @@ void DivPlatformAmiga::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(chan[i].std.arp.val));
|
||||
} else {
|
||||
chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(chan[i].note+chan[i].std.arp.val));
|
||||
}
|
||||
}
|
||||
// TODO: why the off mult? this may be a bug!
|
||||
chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(parent->calcArp(chan[i].note,chan[i].std.arp.val)));
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(chan[i].note));
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].useWave && chan[i].std.wave.had) {
|
||||
if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) {
|
||||
|
|
|
|||
|
|
@ -105,7 +105,6 @@ class DivPlatformAmiga: public DivDispatch {
|
|||
void notifyWaveChange(int wave);
|
||||
void notifyInsDeletion(void* ins);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -50,111 +50,6 @@ const char** DivPlatformArcade::getRegisterSheet() {
|
|||
return regCheatSheetOPM;
|
||||
}
|
||||
|
||||
const char* DivPlatformArcade::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Set noise frequency (xx: value; 0 disables noise)";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Set feedback (0 to 7)";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Set level of operator 1 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x13:
|
||||
return "13xx: Set level of operator 2 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x14:
|
||||
return "14xx: Set level of operator 3 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x15:
|
||||
return "15xx: Set level of operator 4 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x16:
|
||||
return "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)";
|
||||
break;
|
||||
case 0x17:
|
||||
return "17xx: Set LFO speed";
|
||||
break;
|
||||
case 0x18:
|
||||
return "18xx: Set LFO waveform (0 saw, 1 square, 2 triangle, 3 noise)";
|
||||
break;
|
||||
case 0x19:
|
||||
return "19xx: Set attack of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x1a:
|
||||
return "1Axx: Set attack of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x1b:
|
||||
return "1Bxx: Set attack of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x1c:
|
||||
return "1Cxx: Set attack of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x1d:
|
||||
return "1Dxx: Set attack of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x1e:
|
||||
return "1Exx: Set AM depth (0 to 7F)";
|
||||
break;
|
||||
case 0x1f:
|
||||
return "1Fxx: Set PM depth (0 to 7F)";
|
||||
break;
|
||||
case 0x30:
|
||||
return "30xx: Toggle hard envelope reset on new notes";
|
||||
break;
|
||||
case 0x50:
|
||||
return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)";
|
||||
break;
|
||||
case 0x51:
|
||||
return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)";
|
||||
break;
|
||||
case 0x52:
|
||||
return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)";
|
||||
break;
|
||||
case 0x53:
|
||||
return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)";
|
||||
break;
|
||||
case 0x54:
|
||||
return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)";
|
||||
break;
|
||||
case 0x55:
|
||||
return "55xy: Set detune 2 (x: operator from 1 to 4 (0 for all ops); y: detune from 0 to 3)";
|
||||
break;
|
||||
case 0x56:
|
||||
return "56xx: Set decay of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x57:
|
||||
return "57xx: Set decay of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x58:
|
||||
return "58xx: Set decay of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x59:
|
||||
return "59xx: Set decay of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5a:
|
||||
return "5Axx: Set decay of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x5b:
|
||||
return "5Bxx: Set decay 2 of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x5c:
|
||||
return "5Cxx: Set decay 2 of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x5d:
|
||||
return "5Dxx: Set decay 2 of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x5e:
|
||||
return "5Exx: Set decay 2 of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5f:
|
||||
return "5Fxx: Set decay 2 of operator 4 (0 to 1F)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformArcade::acquire_nuked(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
static int o[2];
|
||||
|
||||
|
|
@ -266,18 +161,9 @@ void DivPlatformArcade::tick(bool sysTick) {
|
|||
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_LINEAR(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_LINEAR(chan[i].note+(signed char)chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_LINEAR(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_LINEAR(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.duty.had) {
|
||||
|
|
|
|||
|
|
@ -115,7 +115,6 @@ class DivPlatformArcade: public DivPlatformOPM {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformArcade();
|
||||
|
|
|
|||
|
|
@ -73,42 +73,6 @@ const char** DivPlatformAY8910::getRegisterSheet() {
|
|||
return intellivision?regCheatSheetAY8914:regCheatSheetAY;
|
||||
}
|
||||
|
||||
const char* DivPlatformAY8910::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x20:
|
||||
return "20xx: Set channel mode (bit 0: square; bit 1: noise; bit 2: envelope)";
|
||||
break;
|
||||
case 0x21:
|
||||
return "21xx: Set noise frequency (0 to 1F)";
|
||||
break;
|
||||
case 0x22:
|
||||
return "22xy: Set envelope mode (x: shape, y: enable for this channel)";
|
||||
break;
|
||||
case 0x23:
|
||||
return "23xx: Set envelope period low byte";
|
||||
break;
|
||||
case 0x24:
|
||||
return "24xx: Set envelope period high byte";
|
||||
break;
|
||||
case 0x25:
|
||||
return "25xx: Envelope slide up";
|
||||
break;
|
||||
case 0x26:
|
||||
return "26xx: Envelope slide down";
|
||||
break;
|
||||
case 0x29:
|
||||
return "29xy: Set auto-envelope (x: numerator; y: denominator)";
|
||||
break;
|
||||
case 0x2e:
|
||||
return "2Exx: Write to I/O port A";
|
||||
break;
|
||||
case 0x2f:
|
||||
return "2Fxx: Write to I/O port B";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
if (ayBufLen<len) {
|
||||
ayBufLen=len;
|
||||
|
|
@ -132,6 +96,7 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l
|
|||
end=true;
|
||||
break;
|
||||
}
|
||||
// Partially
|
||||
unsigned char dacData=(((unsigned char)s->data8[chan[i].dac.pos]^0x80)>>4);
|
||||
chan[i].dac.out=MAX(0,MIN(15,(dacData*chan[i].outVol)/15));
|
||||
if (prev_out!=chan[i].dac.out) {
|
||||
|
|
@ -237,18 +202,9 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
rWrite(0x06,31-chan[i].std.duty.val);
|
||||
|
|
|
|||
|
|
@ -170,7 +170,6 @@ class DivPlatformAY8910: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
DivPlatformAY8910(bool useExtMode=false, unsigned int eclk=COLOR_NTSC, unsigned char ediv=8):
|
||||
|
|
|
|||
|
|
@ -77,54 +77,6 @@ const char** DivPlatformAY8930::getRegisterSheet() {
|
|||
return regCheatSheetAY8930;
|
||||
}
|
||||
|
||||
const char* DivPlatformAY8930::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x12:
|
||||
return "12xx: Set duty cycle (0 to 8)";
|
||||
break;
|
||||
case 0x20:
|
||||
return "20xx: Set channel mode (bit 0: square; bit 1: noise; bit 2: envelope)";
|
||||
break;
|
||||
case 0x21:
|
||||
return "21xx: Set noise frequency (0 to 1F)";
|
||||
break;
|
||||
case 0x22:
|
||||
return "22xy: Set envelope mode (x: shape, y: enable for this channel)";
|
||||
break;
|
||||
case 0x23:
|
||||
return "23xx: Set envelope period low byte";
|
||||
break;
|
||||
case 0x24:
|
||||
return "24xx: Set envelope period high byte";
|
||||
break;
|
||||
case 0x25:
|
||||
return "25xx: Envelope slide up";
|
||||
break;
|
||||
case 0x26:
|
||||
return "26xx: Envelope slide down";
|
||||
break;
|
||||
case 0x27:
|
||||
return "27xx: Set noise AND mask";
|
||||
break;
|
||||
case 0x28:
|
||||
return "28xx: Set noise OR mask";
|
||||
break;
|
||||
case 0x29:
|
||||
return "29xy: Set auto-envelope (x: numerator; y: denominator)";
|
||||
break;
|
||||
case 0x2d:
|
||||
return "2Dxx: NOT TO BE EMPLOYED BY THE COMPOSER";
|
||||
break;
|
||||
case 0x2e:
|
||||
return "2Exx: Write to I/O port A";
|
||||
break;
|
||||
case 0x2f:
|
||||
return "2Fxx: Write to I/O port B";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
if (ayBufLen<len) {
|
||||
ayBufLen=len;
|
||||
|
|
@ -148,6 +100,7 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l
|
|||
end=true;
|
||||
break;
|
||||
}
|
||||
// Partially
|
||||
unsigned char dacData=(((unsigned char)s->data8[chan[i].dac.pos]^0x80)>>3);
|
||||
chan[i].dac.out=MAX(0,MIN(31,(dacData*chan[i].outVol)/31));
|
||||
if (prev_out!=chan[i].dac.out) {
|
||||
|
|
@ -257,18 +210,9 @@ void DivPlatformAY8930::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
rWrite(0x06,chan[i].std.duty.val);
|
||||
|
|
|
|||
|
|
@ -171,7 +171,6 @@ class DivPlatformAY8930: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -39,15 +39,6 @@ const char** DivPlatformBubSysWSG::getRegisterSheet() {
|
|||
return regCheatSheetBubSysWSG;
|
||||
}
|
||||
|
||||
const char* DivPlatformBubSysWSG::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Change waveform";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformBubSysWSG::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
int chanOut=0;
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
|
|
@ -101,18 +92,9 @@ void DivPlatformBubSysWSG::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.wave.had) {
|
||||
if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) {
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@ class DivPlatformBubSysWSG: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformBubSysWSG();
|
||||
|
|
|
|||
|
|
@ -62,52 +62,6 @@ const char** DivPlatformC64::getRegisterSheet() {
|
|||
return regCheatSheetSID;
|
||||
}
|
||||
|
||||
const char* DivPlatformC64::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Set waveform (bit 0: triangle; bit 1: saw; bit 2: pulse; bit 3: noise)";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Set coarse cutoff (not recommended; use 4xxx instead)";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Set coarse pulse width (not recommended; use 3xxx instead)";
|
||||
break;
|
||||
case 0x13:
|
||||
return "13xx: Set resonance (0 to F)";
|
||||
break;
|
||||
case 0x14:
|
||||
return "14xx: Set filter mode (bit 0: low pass; bit 1: band pass; bit 2: high pass)";
|
||||
break;
|
||||
case 0x15:
|
||||
return "15xx: Set envelope reset time";
|
||||
break;
|
||||
case 0x1a:
|
||||
return "1Axx: Disable envelope reset for this channel (1 disables; 0 enables)";
|
||||
break;
|
||||
case 0x1b:
|
||||
return "1Bxy: Reset cutoff (x: on new note; y: now)";
|
||||
break;
|
||||
case 0x1c:
|
||||
return "1Cxy: Reset pulse width (x: on new note; y: now)";
|
||||
break;
|
||||
case 0x1e:
|
||||
return "1Exy: Change additional parameters";
|
||||
break;
|
||||
case 0x30: case 0x31: case 0x32: case 0x33:
|
||||
case 0x34: case 0x35: case 0x36: case 0x37:
|
||||
case 0x38: case 0x39: case 0x3a: case 0x3b:
|
||||
case 0x3c: case 0x3d: case 0x3e: case 0x3f:
|
||||
return "3xxx: Set pulse width (0 to FFF)";
|
||||
break;
|
||||
case 0x40: case 0x41: case 0x42: case 0x43:
|
||||
case 0x44: case 0x45: case 0x46: case 0x47:
|
||||
return "4xxx: Set cutoff (0 to 7FF)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformC64::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
int dcOff=sid.get_dc(0);
|
||||
for (size_t i=start; i<start+len; i++) {
|
||||
|
|
@ -150,18 +104,9 @@ void DivPlatformC64::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_C64);
|
||||
|
|
|
|||
|
|
@ -103,7 +103,6 @@ class DivPlatformC64: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void setChipModel(bool is6581);
|
||||
void quit();
|
||||
|
|
|
|||
|
|
@ -55,30 +55,6 @@ const char** DivPlatformFDS::getRegisterSheet() {
|
|||
return regCheatSheetFDS;
|
||||
}
|
||||
|
||||
const char* DivPlatformFDS::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Change waveform";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Set modulation depth";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xy: Set modulation speed high byte (x: enable; y: value)";
|
||||
break;
|
||||
case 0x13:
|
||||
return "13xx: Set modulation speed low byte";
|
||||
break;
|
||||
case 0x14:
|
||||
return "14xx: Set modulator position";
|
||||
break;
|
||||
case 0x15:
|
||||
return "15xx: Set modulator table to waveform";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformFDS::acquire_puNES(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
for (size_t i=start; i<start+len; i++) {
|
||||
extcl_apu_tick_FDS(fds);
|
||||
|
|
@ -145,18 +121,9 @@ void DivPlatformFDS::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (chan[i].std.duty.had) {
|
||||
|
|
|
|||
|
|
@ -104,7 +104,6 @@ class DivPlatformFDS: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformFDS();
|
||||
|
|
|
|||
|
|
@ -61,27 +61,6 @@ const char** DivPlatformGB::getRegisterSheet() {
|
|||
return regCheatSheetGB;
|
||||
}
|
||||
|
||||
const char* DivPlatformGB::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Change waveform";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Set noise length (0: long; 1: short)";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Set duty cycle (0 to 3)";
|
||||
break;
|
||||
case 0x13:
|
||||
return "13xy: Setup sweep (x: time; y: shift)";
|
||||
break;
|
||||
case 0x14:
|
||||
return "14xx: Set sweep direction (0: up; 1: down)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformGB::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
for (size_t i=start; i<start+len; i++) {
|
||||
if (!writes.empty()) {
|
||||
|
|
@ -181,34 +160,18 @@ void DivPlatformGB::tick(bool sysTick) {
|
|||
chan[i].soundLen=64;
|
||||
|
||||
if (!chan[i].keyOn) chan[i].killIt=true;
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (i==3) { // noise
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=chan[i].std.arp.val+24;
|
||||
} else {
|
||||
chan[i].baseFreq=chan[i].note+chan[i].std.arp.val;
|
||||
}
|
||||
chan[i].baseFreq=parent->calcArp(chan[i].note,chan[i].std.arp.val,24);
|
||||
if (chan[i].baseFreq>255) chan[i].baseFreq=255;
|
||||
if (chan[i].baseFreq<0) chan[i].baseFreq=0;
|
||||
} else {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val+24);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
}
|
||||
chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val,24));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
chan[i].duty=chan[i].std.duty.val;
|
||||
|
|
@ -353,26 +316,27 @@ void DivPlatformGB::tick(bool sysTick) {
|
|||
if (chan[i].keyOn) chan[i].keyOn=false;
|
||||
if (chan[i].keyOff) chan[i].keyOff=false;
|
||||
chan[i].freqChanged=false;
|
||||
}
|
||||
if (chan[i].killIt) {
|
||||
if (i!=2) {
|
||||
//rWrite(16+i*5+2,8);
|
||||
int killDelta=chan[i].lastKill-chan[i].outVol+1;
|
||||
if (killDelta<0) killDelta+=16;
|
||||
chan[i].lastKill=chan[i].outVol;
|
||||
|
||||
if (chan[i].killIt) {
|
||||
if (i!=2) {
|
||||
//rWrite(16+i*5+2,8);
|
||||
int killDelta=chan[i].lastKill-chan[i].outVol+1;
|
||||
if (killDelta<0) killDelta+=16;
|
||||
chan[i].lastKill=chan[i].outVol;
|
||||
|
||||
if (killDelta!=1) {
|
||||
rWrite(16+i*5+2,((chan[i].envVol<<4))|8);
|
||||
for (int j=0; j<killDelta; j++) {
|
||||
rWrite(16+i*5+2,0x09);
|
||||
rWrite(16+i*5+2,0x11);
|
||||
rWrite(16+i*5+2,0x08);
|
||||
}
|
||||
if (killDelta!=1) {
|
||||
rWrite(16+i*5+2,((chan[i].envVol<<4))|8);
|
||||
for (int j=0; j<killDelta; j++) {
|
||||
rWrite(16+i*5+2,0x09);
|
||||
rWrite(16+i*5+2,0x11);
|
||||
rWrite(16+i*5+2,0x08);
|
||||
}
|
||||
}
|
||||
chan[i].killIt=false;
|
||||
}
|
||||
chan[i].killIt=false;
|
||||
}
|
||||
|
||||
chan[i].soManyHacksToMakeItDefleCompatible=false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -409,10 +373,16 @@ int DivPlatformGB::dispatch(DivCommand c) {
|
|||
ws.init(ins,32,15,chan[c.chan].insChanged);
|
||||
}
|
||||
if ((chan[c.chan].insChanged || ins->gb.alwaysInit) && !chan[c.chan].softEnv) {
|
||||
chan[c.chan].envVol=ins->gb.envVol;
|
||||
if (!chan[c.chan].soManyHacksToMakeItDefleCompatible && c.chan!=2) {
|
||||
chan[c.chan].envVol=ins->gb.envVol;
|
||||
}
|
||||
chan[c.chan].envLen=ins->gb.envLen;
|
||||
chan[c.chan].envDir=ins->gb.envDir;
|
||||
chan[c.chan].soundLen=ins->gb.soundLen;
|
||||
if (!chan[c.chan].soManyHacksToMakeItDefleCompatible && c.chan!=2) {
|
||||
chan[c.chan].vol=chan[c.chan].envVol;
|
||||
chan[c.chan].outVol=chan[c.chan].envVol;
|
||||
}
|
||||
}
|
||||
if (c.chan==2 && chan[c.chan].softEnv) {
|
||||
chan[c.chan].soundLen=64;
|
||||
|
|
@ -460,6 +430,7 @@ int DivPlatformGB::dispatch(DivCommand c) {
|
|||
}
|
||||
if (!chan[c.chan].softEnv) {
|
||||
chan[c.chan].envVol=chan[c.chan].vol;
|
||||
chan[c.chan].soManyHacksToMakeItDefleCompatible=true;
|
||||
} else if (c.chan!=2) {
|
||||
chan[c.chan].envVol=chan[c.chan].vol;
|
||||
if (!chan[c.chan].keyOn) chan[c.chan].killIt=true;
|
||||
|
|
@ -636,7 +607,7 @@ void DivPlatformGB::notifyWaveChange(int wave) {
|
|||
if (chan[2].wave==wave) {
|
||||
ws.changeWave1(wave);
|
||||
updateWave();
|
||||
if (!chan[2].keyOff) chan[2].keyOn=true;
|
||||
if (!chan[2].keyOff && chan[2].active) chan[2].keyOn=true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ class DivPlatformGB: public DivDispatch {
|
|||
int freq, baseFreq, pitch, pitch2, note, ins;
|
||||
unsigned char duty, sweep;
|
||||
bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, released, softEnv, killIt;
|
||||
bool soManyHacksToMakeItDefleCompatible;
|
||||
signed char vol, outVol, wave, lastKill;
|
||||
unsigned char envVol, envDir, envLen, soundLen;
|
||||
unsigned short hwSeqPos;
|
||||
|
|
@ -59,6 +60,7 @@ class DivPlatformGB: public DivDispatch {
|
|||
released(false),
|
||||
softEnv(false),
|
||||
killIt(false),
|
||||
soManyHacksToMakeItDefleCompatible(false),
|
||||
vol(15),
|
||||
outVol(15),
|
||||
wave(-1),
|
||||
|
|
@ -113,7 +115,6 @@ class DivPlatformGB: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
void setFlags(unsigned int flags);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
|
|
|
|||
|
|
@ -27,108 +27,6 @@
|
|||
|
||||
#define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6])))
|
||||
|
||||
const char* DivPlatformGenesis::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xy: Setup LFO (x: enable; y: speed)";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Set feedback (0 to 7)";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Set level of operator 1 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x13:
|
||||
return "13xx: Set level of operator 2 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x14:
|
||||
return "14xx: Set level of operator 3 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x15:
|
||||
return "15xx: Set level of operator 4 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x16:
|
||||
return "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)";
|
||||
break;
|
||||
case 0x17:
|
||||
return "17xx: Enable channel 6 DAC";
|
||||
break;
|
||||
case 0x18:
|
||||
return "18xx: Toggle extended channel 3 mode";
|
||||
break;
|
||||
case 0x19:
|
||||
return "19xx: Set attack of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x1a:
|
||||
return "1Axx: Set attack of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x1b:
|
||||
return "1Bxx: Set attack of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x1c:
|
||||
return "1Cxx: Set attack of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x1d:
|
||||
return "1Dxx: Set attack of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x30:
|
||||
return "30xx: Toggle hard envelope reset on new notes";
|
||||
break;
|
||||
case 0x50:
|
||||
return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)";
|
||||
break;
|
||||
case 0x51:
|
||||
return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)";
|
||||
break;
|
||||
case 0x52:
|
||||
return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)";
|
||||
break;
|
||||
case 0x53:
|
||||
return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)";
|
||||
break;
|
||||
case 0x54:
|
||||
return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)";
|
||||
break;
|
||||
case 0x55:
|
||||
return "55xy: Set SSG envelope (x: operator from 1 to 4 (0 for all ops); y: 0-7 on, 8 off)";
|
||||
break;
|
||||
case 0x56:
|
||||
return "56xx: Set decay of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x57:
|
||||
return "57xx: Set decay of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x58:
|
||||
return "58xx: Set decay of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x59:
|
||||
return "59xx: Set decay of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5a:
|
||||
return "5Axx: Set decay of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x5b:
|
||||
return "5Bxx: Set decay 2 of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x5c:
|
||||
return "5Cxx: Set decay 2 of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x5d:
|
||||
return "5Dxx: Set decay 2 of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x5e:
|
||||
return "5Exx: Set decay 2 of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5f:
|
||||
return "5Fxx: Set decay 2 of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0xdf:
|
||||
return "DFxx: Set sample playback direction (0: normal; 1: reverse)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformGenesis::processDAC() {
|
||||
if (softPCM) {
|
||||
softPCMTimer+=chipClock/576;
|
||||
|
|
@ -365,26 +263,40 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].std.arp.val,11);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note+(signed char)chan[i].std.arp.val,11);
|
||||
if (i>=5 && chan[i].furnaceDac) {
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
chan[i].baseFreq=parent->calcBaseFreq(1,1,parent->calcArp(chan[i].note,chan[i].std.arp.val),false);
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note,11);
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11);
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].pan=chan[i].std.panL.val&3;
|
||||
if (i<6) {
|
||||
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 (i>=5 && chan[i].furnaceDac) {
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[5].pan&=1;
|
||||
chan[5].pan|=chan[i].std.panL.val?2:0;
|
||||
}
|
||||
if (chan[i].std.panR.had) {
|
||||
chan[5].pan&=2;
|
||||
chan[5].pan|=chan[i].std.panR.val?1:0;
|
||||
}
|
||||
if (chan[i].std.panL.had || chan[i].std.panR.had) {
|
||||
rWrite(chanOffs[5]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[5].pan<<6))|(chan[5].state.fms&7)|((chan[5].state.ams&3)<<4));
|
||||
}
|
||||
} else {
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].pan=chan[i].std.panL.val&3;
|
||||
if (i<6) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -144,7 +144,6 @@ class DivPlatformGenesis: public DivPlatformOPN {
|
|||
int getPortaFloor(int ch);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
DivPlatformGenesis():
|
||||
|
|
|
|||
|
|
@ -561,6 +561,11 @@ void DivPlatformGenesisExt::forceIns() {
|
|||
opChan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (extMode && softPCM && chan[7].active) { // CSM
|
||||
chan[7].insChanged=true;
|
||||
chan[7].freqChanged=true;
|
||||
chan[7].keyOn=true;
|
||||
}
|
||||
}
|
||||
|
||||
void* DivPlatformGenesisExt::getChanState(int ch) {
|
||||
|
|
|
|||
|
|
@ -130,19 +130,6 @@ const char** DivPlatformLynx::getRegisterSheet() {
|
|||
return regCheatSheetLynx;
|
||||
}
|
||||
|
||||
const char* DivPlatformLynx::getEffectName(unsigned char effect) {
|
||||
switch (effect)
|
||||
{
|
||||
case 0x30: case 0x31: case 0x32: case 0x33:
|
||||
case 0x34: case 0x35: case 0x36: case 0x37:
|
||||
case 0x38: case 0x39: case 0x3a: case 0x3b:
|
||||
case 0x3c: case 0x3d: case 0x3e: case 0x3f:
|
||||
return "3xxx: Load LFSR (0 to FFF)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
for (int i=0; i<4; i++) {
|
||||
|
|
@ -186,22 +173,9 @@ void DivPlatformLynx::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
|
||||
if (chan[i].pcm) chan[i].sampleBaseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
|
||||
chan[i].actualNote=chan[i].std.arp.val;
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
|
||||
if (chan[i].pcm) chan[i].sampleBaseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val);
|
||||
chan[i].actualNote=chan[i].note+chan[i].std.arp.val;
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
|
||||
if (chan[i].pcm) chan[i].sampleBaseFreq=NOTE_FREQUENCY(chan[i].note);
|
||||
chan[i].actualNote=chan[i].note;
|
||||
chan[i].actualNote=parent->calcArp(chan[i].note,chan[i].std.arp.val);
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].actualNote);
|
||||
if (chan[i].pcm) chan[i].sampleBaseFreq=NOTE_FREQUENCY(chan[i].actualNote);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,6 @@ class DivPlatformLynx: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName( unsigned char effect );
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformLynx();
|
||||
|
|
|
|||
|
|
@ -43,15 +43,6 @@ const char** DivPlatformMMC5::getRegisterSheet() {
|
|||
return regCheatSheetMMC5;
|
||||
}
|
||||
|
||||
const char* DivPlatformMMC5::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x12:
|
||||
return "12xx: Set duty cycle/noise mode (pulse: 0 to 3; noise: 0 or 1)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
for (size_t i=start; i<start+len; i++) {
|
||||
if (dacSample!=-1) {
|
||||
|
|
@ -110,20 +101,12 @@ void DivPlatformMMC5::tick(bool sysTick) {
|
|||
if (chan[i].outVol<0) chan[i].outVol=0;
|
||||
rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6));
|
||||
}
|
||||
// TODO: arp macros on NES PCM?
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
chan[i].duty=chan[i].std.duty.val;
|
||||
|
|
|
|||
|
|
@ -89,7 +89,6 @@ class DivPlatformMMC5: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformMMC5();
|
||||
|
|
|
|||
|
|
@ -30,18 +30,6 @@ const char** DivPlatformMSM6258::getRegisterSheet() {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -109,7 +109,6 @@ class DivPlatformMSM6258: public DivDispatch {
|
|||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
void setFlags(unsigned int flags);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
const void* getSampleMem(int index);
|
||||
size_t getSampleMemCapacity(int index);
|
||||
size_t getSampleMemUsage(int index);
|
||||
|
|
|
|||
|
|
@ -30,15 +30,6 @@ 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;
|
||||
}
|
||||
|
||||
u8 DivPlatformMSM6295::read_byte(u32 address) {
|
||||
if (adpcmMem==NULL || address>=getSampleMemCapacity(0)) {
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -97,7 +97,6 @@ class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf {
|
|||
virtual void poke(std::vector<DivRegWrite>& wlist) override;
|
||||
virtual void setFlags(unsigned int flags) override;
|
||||
virtual const char** getRegisterSheet() override;
|
||||
virtual const char* getEffectName(unsigned char effect) override;
|
||||
virtual const void* getSampleMem(int index) override;
|
||||
virtual size_t getSampleMemCapacity(int index) override;
|
||||
virtual size_t getSampleMemUsage(int index) override;
|
||||
|
|
|
|||
|
|
@ -108,51 +108,6 @@ const char** DivPlatformN163::getRegisterSheet() {
|
|||
return regCheatSheetN163;
|
||||
}
|
||||
|
||||
const char* DivPlatformN163::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Select waveform";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Set waveform position in RAM (single nibble unit)";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Set waveform length in RAM (04 to FC, 4 nibble unit)";
|
||||
break;
|
||||
case 0x13:
|
||||
return "130x: Change waveform update mode (0: off, bit 0: update now, bit 1: update when every waveform changes)";
|
||||
break;
|
||||
case 0x14:
|
||||
return "14xx: Select waveform for load to RAM";
|
||||
break;
|
||||
case 0x15:
|
||||
return "15xx: Set waveform position for load to RAM (single nibble unit)";
|
||||
break;
|
||||
case 0x16:
|
||||
return "16xx: Set waveform length for load to RAM (04 to FC, 4 nibble unit)";
|
||||
break;
|
||||
case 0x17:
|
||||
return "170x: Change waveform load mode (0: off, bit 0: load now, bit 1: load when every waveform changes)";
|
||||
break;
|
||||
case 0x18:
|
||||
return "180x: Change channel limits (0 to 7, x + 1)";
|
||||
break;
|
||||
case 0x20:
|
||||
return "20xx: (Global) Select waveform for load to RAM";
|
||||
break;
|
||||
case 0x21:
|
||||
return "21xx: (Global) Set waveform position for load to RAM (single nibble unit)";
|
||||
break;
|
||||
case 0x22:
|
||||
return "22xx: (Global) Set waveform length for load to RAM (04 to FC, 4 nibble unit)";
|
||||
break;
|
||||
case 0x23:
|
||||
return "230x: (Global) Change waveform load mode (0: off, bit 0: load now, bit 1: load when every waveform changes)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformN163::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
for (size_t i=start; i<start+len; i++) {
|
||||
n163.tick();
|
||||
|
|
@ -234,18 +189,9 @@ void DivPlatformN163::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
if (chan[i].wavePos!=chan[i].std.duty.val) {
|
||||
|
|
|
|||
|
|
@ -110,7 +110,6 @@ class DivPlatformN163: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformN163();
|
||||
|
|
|
|||
|
|
@ -151,18 +151,6 @@ const char** DivPlatformNamcoWSG::getRegisterSheet() {
|
|||
return regCheatSheetNamcoWSG;
|
||||
}
|
||||
|
||||
const char* DivPlatformNamcoWSG::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Change waveform";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Toggle noise mode";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformNamcoWSG::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
while (!writes.empty()) {
|
||||
QueuedWrite w=writes.front();
|
||||
|
|
@ -218,18 +206,9 @@ void DivPlatformNamcoWSG::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.wave.had) {
|
||||
if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) {
|
||||
|
|
|
|||
|
|
@ -96,7 +96,6 @@ class DivPlatformNamcoWSG: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformNamcoWSG();
|
||||
|
|
|
|||
|
|
@ -62,27 +62,6 @@ const char** DivPlatformNES::getRegisterSheet() {
|
|||
return regCheatSheetNES;
|
||||
}
|
||||
|
||||
const char* DivPlatformNES::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x11:
|
||||
return "11xx: Write to delta modulation counter (0 to 7F)";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Set duty cycle/noise mode (pulse: 0 to 3; noise: 0 or 1)";
|
||||
break;
|
||||
case 0x13:
|
||||
return "13xy: Sweep up (x: time; y: shift)";
|
||||
break;
|
||||
case 0x14:
|
||||
return "14xy: Sweep down (x: time; y: shift)";
|
||||
break;
|
||||
case 0x18:
|
||||
return "18xx: Select PCM/DPCM mode (0: PCM; 1: DPCM)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) {
|
||||
if (useNP) {
|
||||
nes1_NP->Write(addr,data);
|
||||
|
|
@ -240,28 +219,15 @@ void DivPlatformNES::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (i==3) { // noise
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=chan[i].std.arp.val;
|
||||
} else {
|
||||
chan[i].baseFreq=chan[i].note+chan[i].std.arp.val;
|
||||
}
|
||||
chan[i].baseFreq=parent->calcArp(chan[i].note,chan[i].std.arp.val);
|
||||
if (chan[i].baseFreq>255) chan[i].baseFreq=255;
|
||||
if (chan[i].baseFreq<0) chan[i].baseFreq=0;
|
||||
} else {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
chan[i].duty=chan[i].std.duty.val;
|
||||
|
|
|
|||
|
|
@ -106,7 +106,6 @@ class DivPlatformNES: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
const void* getSampleMem(int index);
|
||||
size_t getSampleMemCapacity(int index);
|
||||
size_t getSampleMemUsage(int index);
|
||||
|
|
|
|||
|
|
@ -152,98 +152,6 @@ const int orderedOpsL[4]={
|
|||
#define ADDR_FREQH 0xb0
|
||||
#define ADDR_LR_FB_ALG 0xc0
|
||||
|
||||
const char* DivPlatformOPL::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Set global AM depth (0: 1dB, 1: 4.8dB)";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Set feedback (0 to 7)";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Set level of operator 1 (0 highest, 3F lowest)";
|
||||
break;
|
||||
case 0x13:
|
||||
return "13xx: Set level of operator 2 (0 highest, 3F lowest)";
|
||||
break;
|
||||
case 0x14:
|
||||
return "14xx: Set level of operator 3 (0 highest, 3F lowest; 4-op only)";
|
||||
break;
|
||||
case 0x15:
|
||||
return "15xx: Set level of operator 4 (0 highest, 3F lowest; 4-op only)";
|
||||
break;
|
||||
case 0x16:
|
||||
return "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)";
|
||||
break;
|
||||
case 0x17:
|
||||
return "17xx: Set global vibrato depth (0: normal, 1: double)";
|
||||
break;
|
||||
case 0x18:
|
||||
if (properDrumsSys) {
|
||||
return "18xx: Toggle drums mode (1: enabled; 0: disabled)";
|
||||
}
|
||||
break;
|
||||
case 0x19:
|
||||
return "19xx: Set attack of all operators (0 to F)";
|
||||
break;
|
||||
case 0x1a:
|
||||
return "1Axx: Set attack of operator 1 (0 to F)";
|
||||
break;
|
||||
case 0x1b:
|
||||
return "1Bxx: Set attack of operator 2 (0 to F)";
|
||||
break;
|
||||
case 0x1c:
|
||||
return "1Cxx: Set attack of operator 3 (0 to F; 4-op only)";
|
||||
break;
|
||||
case 0x1d:
|
||||
return "1Dxx: Set attack of operator 4 (0 to F; 4-op only)";
|
||||
break;
|
||||
case 0x2a:
|
||||
return "2Axy: Set waveform (x: operator from 1 to 4 (0 for all ops); y: waveform from 0 to 3 in OPL2 and 0 to 7 in OPL3)";
|
||||
break;
|
||||
case 0x30:
|
||||
return "30xx: Toggle hard envelope reset on new notes";
|
||||
break;
|
||||
case 0x50:
|
||||
return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)";
|
||||
break;
|
||||
case 0x51:
|
||||
return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)";
|
||||
break;
|
||||
case 0x52:
|
||||
return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)";
|
||||
break;
|
||||
case 0x53:
|
||||
return "53xy: Set vibrato (x: operator from 1 to 4 (0 for all ops); y: enabled)";
|
||||
break;
|
||||
case 0x54:
|
||||
return "54xy: Set key scale level (x: operator from 1 to 4 (0 for all ops); y: level from 0 to 3)";
|
||||
break;
|
||||
case 0x55:
|
||||
return "55xy: Set envelope sustain (x: operator from 1 to 4 (0 for all ops); y: enabled)";
|
||||
break;
|
||||
case 0x56:
|
||||
return "56xx: Set decay of all operators (0 to F)";
|
||||
break;
|
||||
case 0x57:
|
||||
return "57xx: Set decay of operator 1 (0 to F)";
|
||||
break;
|
||||
case 0x58:
|
||||
return "58xx: Set decay of operator 2 (0 to F)";
|
||||
break;
|
||||
case 0x59:
|
||||
return "59xx: Set decay of operator 3 (0 to F; 4-op only)";
|
||||
break;
|
||||
case 0x5a:
|
||||
return "5Axx: Set decay of operator 4 (0 to F; 4-op only)";
|
||||
break;
|
||||
case 0x5b:
|
||||
return "5Bxy: Set whether key will scale envelope (x: operator from 1 to 4 (0 for all ops); y: enabled)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformOPL::acquire_nuked(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
static short o[2];
|
||||
static int os[2];
|
||||
|
|
@ -389,18 +297,9 @@ void DivPlatformOPL::tick(bool sysTick) {
|
|||
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (oplType==3 && chan[i].std.panL.had) {
|
||||
|
|
@ -583,18 +482,9 @@ void DivPlatformOPL::tick(bool sysTick) {
|
|||
|
||||
if (chan[adpcmChan].std.arp.had) {
|
||||
if (!chan[adpcmChan].inPorta) {
|
||||
if (chan[adpcmChan].std.arp.mode) {
|
||||
chan[adpcmChan].baseFreq=NOTE_ADPCMB(chan[adpcmChan].std.arp.val);
|
||||
} else {
|
||||
chan[adpcmChan].baseFreq=NOTE_ADPCMB(chan[adpcmChan].note+(signed char)chan[adpcmChan].std.arp.val);
|
||||
}
|
||||
chan[adpcmChan].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[adpcmChan].note,chan[adpcmChan].std.arp.val));
|
||||
}
|
||||
chan[adpcmChan].freqChanged=true;
|
||||
} else {
|
||||
if (chan[adpcmChan].std.arp.mode && chan[adpcmChan].std.arp.finished) {
|
||||
chan[adpcmChan].baseFreq=NOTE_ADPCMB(chan[adpcmChan].note);
|
||||
chan[adpcmChan].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[adpcmChan].std.phaseReset.had) {
|
||||
if ((chan[adpcmChan].std.phaseReset.val==1) && chan[adpcmChan].active) {
|
||||
|
|
@ -891,6 +781,13 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
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) {
|
||||
/*
|
||||
if (chan[c.chan+1].active) {
|
||||
chan[c.chan+1].keyOff=true;
|
||||
chan[c.chan+1].keyOn=false;
|
||||
chan[c.chan+1].active=false;
|
||||
}*/
|
||||
chan[c.chan+1].insChanged=true;
|
||||
chan[c.chan+1].macroInit(NULL);
|
||||
}
|
||||
update4OpMask=true;
|
||||
|
|
@ -1691,7 +1588,7 @@ void DivPlatformOPL::setOPLType(int type, bool drums) {
|
|||
adpcmChan=drums?11:9;
|
||||
}
|
||||
break;
|
||||
case 3: case 759:
|
||||
case 3: case 4: case 759:
|
||||
slotsNonDrums=slotsOPL3;
|
||||
slotsDrums=slotsOPL3Drums;
|
||||
slots=drums?slotsDrums:slotsNonDrums;
|
||||
|
|
@ -1705,6 +1602,7 @@ void DivPlatformOPL::setOPLType(int type, bool drums) {
|
|||
pretendYMU=true;
|
||||
adpcmChan=16;
|
||||
} else if (type==4) {
|
||||
chipFreqBase=32768*684;
|
||||
downsample=true;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -147,7 +147,6 @@ class DivPlatformOPL: public DivDispatch {
|
|||
int getPortaFloor(int ch);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char* getEffectName(unsigned char effect);
|
||||
const void* getSampleMem(int index);
|
||||
size_t getSampleMemCapacity(int index);
|
||||
size_t getSampleMemUsage(int index);
|
||||
|
|
|
|||
|
|
@ -27,68 +27,6 @@
|
|||
|
||||
#define CHIP_FREQBASE 1180068
|
||||
|
||||
const char* DivPlatformOPLL::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x11:
|
||||
return "11xx: Set feedback (0 to 7)";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Set level of operator 1 (0 highest, 3F lowest)";
|
||||
break;
|
||||
case 0x13:
|
||||
return "13xx: Set level of operator 2 (0 highest, F lowest)";
|
||||
break;
|
||||
case 0x16:
|
||||
return "16xy: Set operator multiplier (x: operator from 1 to 2; y: multiplier)";
|
||||
break;
|
||||
case 0x18:
|
||||
if (properDrumsSys) {
|
||||
return "18xx: Toggle drums mode (1: enabled; 0: disabled)";
|
||||
}
|
||||
break;
|
||||
case 0x19:
|
||||
return "19xx: Set attack of all operators (0 to F)";
|
||||
break;
|
||||
case 0x1a:
|
||||
return "1Axx: Set attack of operator 1 (0 to F)";
|
||||
break;
|
||||
case 0x1b:
|
||||
return "1Bxx: Set attack of operator 2 (0 to F)";
|
||||
break;
|
||||
case 0x50:
|
||||
return "50xy: Set AM (x: operator from 1 to 2 (0 for all ops); y: AM)";
|
||||
break;
|
||||
case 0x51:
|
||||
return "51xy: Set sustain level (x: operator from 1 to 2 (0 for all ops); y: sustain)";
|
||||
break;
|
||||
case 0x52:
|
||||
return "52xy: Set release (x: operator from 1 to 2 (0 for all ops); y: release)";
|
||||
break;
|
||||
case 0x53:
|
||||
return "53xy: Set vibrato (x: operator from 1 to 2 (0 for all ops); y: enabled)";
|
||||
break;
|
||||
case 0x54:
|
||||
return "54xy: Set key scale level (x: operator from 1 to 2 (0 for all ops); y: level from 0 to 3)";
|
||||
break;
|
||||
case 0x55:
|
||||
return "55xy: Set envelope sustain (x: operator from 1 to 2 (0 for all ops); y: enabled)";
|
||||
break;
|
||||
case 0x56:
|
||||
return "56xx: Set decay of all operators (0 to F)";
|
||||
break;
|
||||
case 0x57:
|
||||
return "57xx: Set decay of operator 1 (0 to F)";
|
||||
break;
|
||||
case 0x58:
|
||||
return "58xx: Set decay of operator 2 (0 to F)";
|
||||
break;
|
||||
case 0x5b:
|
||||
return "5Bxy: Set whether key will scale envelope (x: operator from 1 to 2 (0 for all ops); y: enabled)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const unsigned char cycleMapOPLL[18]={
|
||||
8, 7, 6, 7, 8, 7, 8, 6, 0, 1, 2, 7, 8, 9, 3, 4, 5, 9
|
||||
};
|
||||
|
|
@ -169,18 +107,9 @@ void DivPlatformOPLL::tick(bool sysTick) {
|
|||
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.wave.had && chan[i].state.opllPreset!=16) {
|
||||
|
|
|
|||
|
|
@ -122,7 +122,6 @@ class DivPlatformOPLL: public DivDispatch {
|
|||
int getPortaFloor(int ch);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformOPLL();
|
||||
|
|
|
|||
|
|
@ -53,27 +53,6 @@ const char** DivPlatformPCE::getRegisterSheet() {
|
|||
return regCheatSheetPCE;
|
||||
}
|
||||
|
||||
const char* DivPlatformPCE::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Change waveform";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Toggle noise mode";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Setup LFO (0: disabled; 1: 1x depth; 2: 16x depth; 3: 256x depth)";
|
||||
break;
|
||||
case 0x13:
|
||||
return "13xx: Set LFO speed";
|
||||
break;
|
||||
case 0x17:
|
||||
return "17xx: Toggle PCM mode";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
// PCM part
|
||||
|
|
@ -190,28 +169,12 @@ void DivPlatformPCE::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
|
||||
// noise
|
||||
int noiseSeek=chan[i].std.arp.val;
|
||||
if (noiseSeek<0) noiseSeek=0;
|
||||
chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
|
||||
int noiseSeek=chan[i].note+chan[i].std.arp.val;
|
||||
if (noiseSeek<0) noiseSeek=0;
|
||||
chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0);
|
||||
}
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
|
||||
int noiseSeek=chan[i].note;
|
||||
int noiseSeek=parent->calcArp(chan[i].note,chan[i].std.arp.val);
|
||||
chan[i].baseFreq=NOTE_PERIODIC(noiseSeek);
|
||||
if (noiseSeek<0) noiseSeek=0;
|
||||
chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.wave.had && !chan[i].pcm) {
|
||||
if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) {
|
||||
|
|
|
|||
|
|
@ -112,7 +112,6 @@ class DivPlatformPCE: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformPCE();
|
||||
|
|
|
|||
|
|
@ -128,18 +128,9 @@ void DivPlatformPCMDAC::tick(bool sysTick) {
|
|||
}
|
||||
if (chan.std.arp.had) {
|
||||
if (!chan.inPorta) {
|
||||
if (chan.std.arp.mode) {
|
||||
chan.baseFreq=NOTE_FREQUENCY(chan.std.arp.val);
|
||||
} else {
|
||||
chan.baseFreq=NOTE_FREQUENCY(chan.note+chan.std.arp.val);
|
||||
}
|
||||
chan.baseFreq=NOTE_FREQUENCY(parent->calcArp(chan.note,chan.std.arp.val));
|
||||
}
|
||||
chan.freqChanged=true;
|
||||
} else {
|
||||
if (chan.std.arp.mode && chan.std.arp.finished) {
|
||||
chan.baseFreq=NOTE_FREQUENCY(chan.note);
|
||||
chan.freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan.useWave && chan.std.wave.had) {
|
||||
if (chan.wave!=chan.std.wave.val || chan.ws.activeChanged()) {
|
||||
|
|
|
|||
|
|
@ -190,10 +190,6 @@ const char** DivPlatformPCSpeaker::getRegisterSheet() {
|
|||
return regCheatSheetPCSpeaker;
|
||||
}
|
||||
|
||||
const char* DivPlatformPCSpeaker::getEffectName(unsigned char effect) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const float cut=0.05;
|
||||
const float reso=0.06;
|
||||
|
||||
|
|
@ -351,18 +347,9 @@ void DivPlatformPCSpeaker::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
if (chan[i].std.pitch.mode) {
|
||||
|
|
|
|||
|
|
@ -113,7 +113,6 @@ class DivPlatformPCSpeaker: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformPCSpeaker();
|
||||
|
|
|
|||
|
|
@ -37,15 +37,6 @@ const char** DivPlatformPET::getRegisterSheet() {
|
|||
return regCheatSheet6522;
|
||||
}
|
||||
|
||||
const char* DivPlatformPET::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Change waveform";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// high-level emulation of 6522 shift register and driver software for now
|
||||
void DivPlatformPET::rWrite(unsigned int addr, unsigned char val) {
|
||||
bool hwSROutput=((regPool[11]>>2)&7)==4;
|
||||
|
|
@ -113,18 +104,9 @@ void DivPlatformPET::tick(bool sysTick) {
|
|||
}
|
||||
if (chan.std.arp.had) {
|
||||
if (!chan.inPorta) {
|
||||
if (chan.std.arp.mode) {
|
||||
chan.baseFreq=NOTE_PERIODIC(chan.std.arp.val);
|
||||
} else {
|
||||
chan.baseFreq=NOTE_PERIODIC(chan.note+chan.std.arp.val);
|
||||
}
|
||||
chan.baseFreq=NOTE_PERIODIC(parent->calcArp(chan.note,chan.std.arp.val));
|
||||
}
|
||||
chan.freqChanged=true;
|
||||
} else {
|
||||
if (chan.std.arp.mode && chan.std.arp.finished) {
|
||||
chan.baseFreq=NOTE_PERIODIC(chan.note);
|
||||
chan.freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan.std.wave.had) {
|
||||
if (chan.wave!=chan.std.wave.val) {
|
||||
|
|
@ -133,8 +115,14 @@ void DivPlatformPET::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
if (chan.std.pitch.had) {
|
||||
chan.freqChanged=true;
|
||||
if (chan.std.pitch.mode) {
|
||||
chan.pitch2+=chan.std.pitch.val;
|
||||
CLAMP_VAR(chan.pitch2,-32768,32767);
|
||||
} else {
|
||||
chan.pitch2=chan.std.pitch.val;
|
||||
}
|
||||
chan.freqChanged=true;
|
||||
}
|
||||
if (chan.freqChanged || chan.keyOn || chan.keyOff) {
|
||||
chan.freq=parent->calcFreq(chan.baseFreq,chan.pitch,true,0,chan.pitch2,chipClock,CHIP_DIVIDER)-2;
|
||||
if (chan.freq>65535) chan.freq=65535;
|
||||
|
|
|
|||
|
|
@ -80,7 +80,6 @@ class DivPlatformPET: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformPET();
|
||||
|
|
|
|||
|
|
@ -249,24 +249,6 @@ const char** DivPlatformQSound::getRegisterSheet() {
|
|||
return regCheatSheetQSound;
|
||||
}
|
||||
|
||||
const char* DivPlatformQSound::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Set echo feedback level (00 to FF)";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Set channel echo level (00 to FF)";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Toggle QSound algorithm (0: disabled; 1: enabled)";
|
||||
break;
|
||||
default:
|
||||
if ((effect & 0xf0) == 0x30) {
|
||||
return "3xxx: Set echo delay buffer length (000 to AA5)";
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void DivPlatformQSound::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
qsound_update(&chip);
|
||||
|
|
@ -322,18 +304,9 @@ void DivPlatformQSound::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=QS_NOTE_FREQUENCY(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=QS_NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=QS_NOTE_FREQUENCY(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=QS_NOTE_FREQUENCY(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
chan[i].echo=CLAMP(chan[i].std.duty.val,0,32767);
|
||||
|
|
|
|||
|
|
@ -96,7 +96,6 @@ class DivPlatformQSound: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
const void* getSampleMem(int index = 0);
|
||||
size_t getSampleMemCapacity(int index = 0);
|
||||
size_t getSampleMemUsage(int index = 0);
|
||||
|
|
|
|||
|
|
@ -43,10 +43,6 @@ const char** DivPlatformRF5C68::getRegisterSheet() {
|
|||
return regCheatSheetRF5C68;
|
||||
}
|
||||
|
||||
const char* DivPlatformRF5C68::getEffectName(unsigned char effect) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformRF5C68::chWrite(unsigned char ch, unsigned int addr, unsigned char val) {
|
||||
if (!skipRegisterWrites) {
|
||||
if (curChan!=ch) {
|
||||
|
|
@ -88,18 +84,9 @@ void DivPlatformRF5C68::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
if (chan[i].std.pitch.mode) {
|
||||
|
|
|
|||
|
|
@ -94,7 +94,6 @@ class DivPlatformRF5C68: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
const void* getSampleMem(int index = 0);
|
||||
size_t getSampleMemCapacity(int index = 0);
|
||||
size_t getSampleMemUsage(int index = 0);
|
||||
|
|
|
|||
|
|
@ -56,21 +56,6 @@ const char** DivPlatformSAA1099::getRegisterSheet() {
|
|||
return regCheatSheetSAA;
|
||||
}
|
||||
|
||||
const char* DivPlatformSAA1099::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xy: Set channel mode (x: noise; y: tone)";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Set noise frequency";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Setup envelope (refer to docs for more information)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformSAA1099::acquire_saaSound(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
if (saaBufLen<len*2) {
|
||||
saaBufLen=len*2;
|
||||
|
|
@ -114,18 +99,9 @@ void DivPlatformSAA1099::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
saaNoise[i/3]=chan[i].std.duty.val&3;
|
||||
|
|
|
|||
|
|
@ -96,7 +96,6 @@ class DivPlatformSAA1099: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -80,15 +80,6 @@ const char** DivPlatformSCC::getRegisterSheet() {
|
|||
return isPlus ? regCheatSheetSCCPlus : regCheatSheetSCC;
|
||||
}
|
||||
|
||||
const char* DivPlatformSCC::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Change waveform";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformSCC::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
for (int i=0; i<16; i++) {
|
||||
|
|
@ -124,18 +115,9 @@ void DivPlatformSCC::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.wave.had) {
|
||||
if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) {
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@ class DivPlatformSCC: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
void setFlags(unsigned int flags);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void setChipModel(bool isPlus);
|
||||
|
|
|
|||
|
|
@ -26,15 +26,6 @@
|
|||
//#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;}
|
||||
//#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
|
||||
|
||||
const char* DivPlatformSegaPCM::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x20:
|
||||
return "20xx: Set PCM frequency";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
static int os[2];
|
||||
|
||||
|
|
@ -97,18 +88,9 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
|
|||
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=(chan[i].std.arp.val<<6);
|
||||
} else {
|
||||
chan[i].baseFreq=((chan[i].note+(signed char)chan[i].std.arp.val)<<6);
|
||||
}
|
||||
chan[i].baseFreq=(parent->calcArp(chan[i].note,chan[i].std.arp.val)<<6);
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=(chan[i].note<<6);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.panL.had) {
|
||||
|
|
|
|||
|
|
@ -114,7 +114,6 @@ class DivPlatformSegaPCM: public DivDispatch {
|
|||
bool isStereo();
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformSegaPCM();
|
||||
|
|
|
|||
|
|
@ -38,15 +38,6 @@ const char** DivPlatformSMS::getRegisterSheet() {
|
|||
return stereo?regCheatSheetGG:regCheatSheetSN;
|
||||
}
|
||||
|
||||
const char* DivPlatformSMS::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x20:
|
||||
return "20xy: Set noise mode (x: preset freq/ch3 freq; y: thin pulse/noise)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
int oL=0;
|
||||
int oR=0;
|
||||
|
|
@ -141,22 +132,12 @@ void DivPlatformSMS::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
|
||||
chan[i].actualNote=chan[i].std.arp.val;
|
||||
} else {
|
||||
// TODO: check whether this weird octave boundary thing applies to other systems as well
|
||||
int areYouSerious=chan[i].note+chan[i].std.arp.val;
|
||||
while (areYouSerious>0x60) areYouSerious-=12;
|
||||
chan[i].baseFreq=NOTE_PERIODIC(areYouSerious);
|
||||
chan[i].actualNote=areYouSerious;
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
|
||||
chan[i].actualNote=chan[i].note;
|
||||
// TODO: check whether this weird octave boundary thing applies to other systems as well
|
||||
// TODO: add compatibility flag. this is horrible.
|
||||
int areYouSerious=parent->calcArp(chan[i].note,chan[i].std.arp.val);
|
||||
while (areYouSerious>0x60) areYouSerious-=12;
|
||||
chan[i].baseFreq=NOTE_PERIODIC(areYouSerious);
|
||||
chan[i].actualNote=areYouSerious;
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
|
|
@ -197,7 +178,11 @@ void DivPlatformSMS::tick(bool sysTick) {
|
|||
if (chan[i].freqChanged) {
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,toneDivider);
|
||||
if (chan[i].freq>1023) chan[i].freq=1023;
|
||||
if (chan[i].freq<8) chan[i].freq=1;
|
||||
if (parent->song.snNoLowPeriods) {
|
||||
if (chan[i].freq<8) chan[i].freq=1;
|
||||
} else {
|
||||
if (chan[i].freq<0) chan[i].freq=0;
|
||||
}
|
||||
//if (chan[i].actualNote>0x5d) chan[i].freq=0x01;
|
||||
rWrite(0,0x80|i<<5|(chan[i].freq&15));
|
||||
rWrite(0,chan[i].freq>>4);
|
||||
|
|
@ -212,7 +197,9 @@ void DivPlatformSMS::tick(bool sysTick) {
|
|||
if (chan[3].freqChanged || updateSNMode) {
|
||||
chan[3].freq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch,true,0,chan[3].pitch2,chipClock,noiseDivider);
|
||||
if (chan[3].freq>1023) chan[3].freq=1023;
|
||||
if (chan[3].actualNote>0x5d) chan[3].freq=0x01;
|
||||
if (parent->song.snNoLowPeriods) {
|
||||
if (chan[3].actualNote>0x5d) chan[3].freq=0x01;
|
||||
}
|
||||
if (snNoiseMode&2) { // take period from channel 3
|
||||
if (updateSNMode || resetPhase) {
|
||||
if (snNoiseMode&1) {
|
||||
|
|
@ -232,12 +219,8 @@ void DivPlatformSMS::tick(bool sysTick) {
|
|||
} else { // 3 fixed values
|
||||
unsigned char value;
|
||||
if (chan[3].std.arp.had) {
|
||||
if (chan[3].std.arp.mode) {
|
||||
value=chan[3].std.arp.val%12;
|
||||
} else {
|
||||
value=(chan[3].note+chan[3].std.arp.val)%12;
|
||||
}
|
||||
} else {
|
||||
value=parent->calcArp(chan[3].note,chan[3].std.arp.val)%12;
|
||||
} else { // pardon?
|
||||
value=chan[3].note%12;
|
||||
}
|
||||
if (value<3) {
|
||||
|
|
|
|||
|
|
@ -101,7 +101,6 @@ class DivPlatformSMS: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
void setNuked(bool value);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
|
|
|
|||
|
|
@ -300,12 +300,46 @@ void SoundUnit::NextSample(short* l, short* r) {
|
|||
}
|
||||
}
|
||||
|
||||
*l=minval(32767,maxval(-32767,tnsL));
|
||||
*r=minval(32767,maxval(-32767,tnsR));
|
||||
if (dsOut) {
|
||||
tnsL=minval(32767,maxval(-32767,tnsL<<1));
|
||||
tnsR=minval(32767,maxval(-32767,tnsR<<1));
|
||||
|
||||
short accumL=0;
|
||||
short accumR=0;
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
if ((tnsL>>8)==0 && dsCounterL>0) dsCounterL=0;
|
||||
dsCounterL+=tnsL>>8;
|
||||
if (dsCounterL>=0) {
|
||||
accumL+=4095;
|
||||
dsCounterL-=127;
|
||||
} else {
|
||||
accumL+=-4095;
|
||||
dsCounterL+=127;
|
||||
}
|
||||
|
||||
if ((tnsR>>8)==0 && dsCounterR>0) dsCounterR=0;
|
||||
dsCounterR+=tnsR>>8;
|
||||
if (dsCounterR>=0) {
|
||||
accumR+=4095;
|
||||
dsCounterR-=127;
|
||||
} else {
|
||||
accumR+=-4095;
|
||||
dsCounterR+=127;
|
||||
}
|
||||
}
|
||||
|
||||
*l=accumL;
|
||||
*r=accumR;
|
||||
} else {
|
||||
*l=minval(32767,maxval(-32767,tnsL));
|
||||
*r=minval(32767,maxval(-32767,tnsR));
|
||||
}
|
||||
}
|
||||
|
||||
void SoundUnit::Init(int sampleMemSize) {
|
||||
void SoundUnit::Init(int sampleMemSize, bool dsOutMode) {
|
||||
pcmSize=sampleMemSize;
|
||||
dsOut=dsOutMode;
|
||||
Reset();
|
||||
memset(pcm,0,pcmSize);
|
||||
for (int i=0; i<256; i++) {
|
||||
|
|
@ -346,6 +380,8 @@ void SoundUnit::Reset() {
|
|||
oldflags[i]=0;
|
||||
pcmdec[i]=0;
|
||||
}
|
||||
dsCounterL=0;
|
||||
dsCounterR=0;
|
||||
tnsL=0;
|
||||
tnsR=0;
|
||||
ilBufPos=0;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ class SoundUnit {
|
|||
unsigned short oldfreq[8];
|
||||
unsigned short oldflags[8];
|
||||
unsigned int pcmSize;
|
||||
bool dsOut;
|
||||
short dsCounterL, dsCounterR;
|
||||
public:
|
||||
unsigned short resetfreq[8];
|
||||
unsigned short voldcycles[8];
|
||||
|
|
@ -99,7 +101,7 @@ class SoundUnit {
|
|||
if (ret>32767) ret=32767;
|
||||
return ret;
|
||||
}
|
||||
void Init(int sampleMemSize=8192);
|
||||
void Init(int sampleMemSize=8192, bool dsOutMode=false);
|
||||
void Reset();
|
||||
SoundUnit();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -26,76 +26,18 @@
|
|||
#define rWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
|
||||
#define chWrite(c,a,v) rWrite(((c)<<5)|(a),v);
|
||||
|
||||
#define CHIP_DIVIDER 2
|
||||
#define CHIP_FREQBASE 524288
|
||||
|
||||
const char** DivPlatformSoundUnit::getRegisterSheet() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* DivPlatformSoundUnit::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Set waveform (0 to 7)";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Set pulse width (0 to 7F)";
|
||||
break;
|
||||
case 0x13:
|
||||
return "13xx: Set resonance (0 to F)";
|
||||
break;
|
||||
case 0x14:
|
||||
return "14xx: Set filter mode (bit 0: ring mod; bit 1: low pass; bit 2: high pass; bit 3: band pass)";
|
||||
break;
|
||||
case 0x15:
|
||||
return "15xx: Set frequency sweep period low byte";
|
||||
break;
|
||||
case 0x16:
|
||||
return "16xx: Set frequency sweep period high byte";
|
||||
break;
|
||||
case 0x17:
|
||||
return "17xx: Set volume sweep period low byte";
|
||||
break;
|
||||
case 0x18:
|
||||
return "18xx: Set volume sweep period high byte";
|
||||
break;
|
||||
case 0x19:
|
||||
return "19xx: Set cutoff sweep period low byte";
|
||||
break;
|
||||
case 0x1a:
|
||||
return "1Axx: Set cutoff sweep period high byte";
|
||||
break;
|
||||
case 0x1b:
|
||||
return "1Bxx: Set frequency sweep boundary";
|
||||
break;
|
||||
case 0x1c:
|
||||
return "1Cxx: Set volume sweep boundary";
|
||||
break;
|
||||
case 0x1d:
|
||||
return "1Dxx: Set cutoff sweep boundary";
|
||||
break;
|
||||
case 0x1e:
|
||||
return "1Exx: Set phase reset period low byte";
|
||||
break;
|
||||
case 0x1f:
|
||||
return "1Fxx: Set phase reset period high byte";
|
||||
break;
|
||||
case 0x20:
|
||||
return "20xx: Toggle frequency sweep (bit 0-6: speed; bit 7: direction is up)";
|
||||
break;
|
||||
case 0x21:
|
||||
return "21xx: Toggle volume sweep (bit 0-4: speed; bit 5: direciton is up; bit 6: loop; bit 7: alternate)";
|
||||
break;
|
||||
case 0x22:
|
||||
return "22xx: Toggle cutoff sweep (bit 0-6: speed; bit 7: direction is up)";
|
||||
break;
|
||||
case 0x40: case 0x41: case 0x42: case 0x43:
|
||||
case 0x44: case 0x45: case 0x46: case 0x47:
|
||||
case 0x48: case 0x49: case 0x4a: case 0x4b:
|
||||
case 0x4c: case 0x4d: case 0x4e: case 0x4f:
|
||||
return "4xxx: Set cutoff (0 to FFF)";
|
||||
break;
|
||||
double DivPlatformSoundUnit::NOTE_SU(int ch, int note) {
|
||||
if (chan[ch].switchRoles) {
|
||||
return NOTE_PERIODIC(note);
|
||||
}
|
||||
return NULL;
|
||||
return NOTE_FREQUENCY(note);
|
||||
}
|
||||
|
||||
void DivPlatformSoundUnit::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
|
|
@ -136,18 +78,9 @@ void DivPlatformSoundUnit::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_SU(i,parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
chan[i].duty=chan[i].std.duty.val;
|
||||
|
|
@ -190,13 +123,18 @@ void DivPlatformSoundUnit::tick(bool sysTick) {
|
|||
if (chan[i].std.ex4.had) {
|
||||
chan[i].syncTimer=chan[i].std.ex4.val&65535;
|
||||
chan[i].timerSync=(chan[i].syncTimer>0);
|
||||
chWrite(i,0x1e,chan[i].syncTimer&0xff);
|
||||
chWrite(i,0x1f,chan[i].syncTimer>>8);
|
||||
if (chan[i].switchRoles) {
|
||||
chWrite(i,0x00,chan[i].syncTimer&0xff);
|
||||
chWrite(i,0x01,chan[i].syncTimer>>8);
|
||||
} else {
|
||||
chWrite(i,0x1e,chan[i].syncTimer&0xff);
|
||||
chWrite(i,0x1f,chan[i].syncTimer>>8);
|
||||
}
|
||||
writeControlUpper(i);
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU);
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE);
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].switchRoles,2,chan[i].pitch2,chipClock,chan[i].switchRoles?CHIP_DIVIDER:CHIP_FREQBASE);
|
||||
if (chan[i].pcm) {
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU);
|
||||
// TODO: sample map?
|
||||
|
|
@ -213,8 +151,13 @@ void DivPlatformSoundUnit::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].freq<0) chan[i].freq=0;
|
||||
if (chan[i].freq>65535) chan[i].freq=65535;
|
||||
chWrite(i,0x00,chan[i].freq&0xff);
|
||||
chWrite(i,0x01,chan[i].freq>>8);
|
||||
if (chan[i].switchRoles) {
|
||||
chWrite(i,0x1e,chan[i].freq&0xff);
|
||||
chWrite(i,0x1f,chan[i].freq>>8);
|
||||
} else {
|
||||
chWrite(i,0x00,chan[i].freq&0xff);
|
||||
chWrite(i,0x01,chan[i].freq>>8);
|
||||
}
|
||||
if (chan[i].keyOn) {
|
||||
if (chan[i].pcm) {
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU);
|
||||
|
|
@ -256,6 +199,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SU);
|
||||
chan[c.chan].switchRoles=ins->su.switchRoles;
|
||||
if (chan[c.chan].pcm && !(ins->type==DIV_INS_AMIGA || ins->amiga.useSample)) {
|
||||
chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->amiga.useSample);
|
||||
writeControl(c.chan);
|
||||
|
|
@ -263,7 +207,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->amiga.useSample);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
chan[c.chan].baseFreq=NOTE_SU(c.chan,c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
}
|
||||
|
|
@ -413,7 +357,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
|
|||
writeControlUpper(c.chan);
|
||||
break;
|
||||
case DIV_CMD_C64_FINE_CUTOFF:
|
||||
chan[c.chan].baseCutoff=c.value;
|
||||
chan[c.chan].baseCutoff=c.value*4;
|
||||
if (!chan[c.chan].std.ex1.has) {
|
||||
chan[c.chan].cutoff=chan[c.chan].baseCutoff;
|
||||
chWrite(c.chan,0x06,chan[c.chan].cutoff&0xff);
|
||||
|
|
@ -421,7 +365,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_FREQUENCY(c.value2);
|
||||
int destFreq=NOTE_SU(c.chan,c.value2);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch==2)?1:(1+(chan[c.chan].baseFreq>>9)));
|
||||
|
|
@ -453,7 +397,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
|
|||
chan[c.chan].keyOn=true;
|
||||
break;
|
||||
case DIV_CMD_LEGATO:
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].baseFreq=NOTE_SU(c.chan,c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
|
|
@ -461,7 +405,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
|
|||
if (chan[c.chan].active && c.value2) {
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SU));
|
||||
}
|
||||
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
|
||||
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_SU(c.chan,chan[c.chan].note);
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
|
|
@ -485,6 +429,11 @@ void DivPlatformSoundUnit::forceIns() {
|
|||
for (int i=0; i<8; i++) {
|
||||
chan[i].insChanged=true;
|
||||
chan[i].freqChanged=true;
|
||||
|
||||
// restore channel attributes
|
||||
chWrite(i,0x03,chan[i].pan);
|
||||
writeControl(i);
|
||||
writeControlUpper(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -572,7 +521,7 @@ void DivPlatformSoundUnit::setFlags(unsigned int flags) {
|
|||
|
||||
sampleMemSize=flags&16;
|
||||
|
||||
su->Init(sampleMemSize?65536:8192);
|
||||
su->Init(sampleMemSize?65536:8192,flags&32);
|
||||
renderSamples();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class DivPlatformSoundUnit: public DivDispatch {
|
|||
int ins, cutoff, baseCutoff, res, control, hasOffset;
|
||||
signed char pan;
|
||||
unsigned char duty;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, noise, pcm, phaseReset, filterPhaseReset;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, noise, pcm, phaseReset, filterPhaseReset, switchRoles;
|
||||
bool pcmLoop, timerSync, freqSweep, volSweep, cutSweep;
|
||||
unsigned short freqSweepP, volSweepP, cutSweepP;
|
||||
unsigned char freqSweepB, volSweepB, cutSweepB;
|
||||
|
|
@ -67,6 +67,7 @@ class DivPlatformSoundUnit: public DivDispatch {
|
|||
pcm(false),
|
||||
phaseReset(false),
|
||||
filterPhaseReset(false),
|
||||
switchRoles(false),
|
||||
pcmLoop(false),
|
||||
timerSync(false),
|
||||
freqSweep(false),
|
||||
|
|
@ -108,6 +109,7 @@ class DivPlatformSoundUnit: public DivDispatch {
|
|||
SoundUnit* su;
|
||||
size_t sampleMemLen;
|
||||
unsigned char regPool[128];
|
||||
double NOTE_SU(int ch, int note);
|
||||
void writeControl(int ch);
|
||||
void writeControlUpper(int ch);
|
||||
|
||||
|
|
@ -131,7 +133,6 @@ class DivPlatformSoundUnit: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
const void* getSampleMem(int index);
|
||||
size_t getSampleMemCapacity(int index);
|
||||
size_t getSampleMemUsage(int index);
|
||||
|
|
|
|||
|
|
@ -50,27 +50,6 @@ const char** DivPlatformSwan::getRegisterSheet() {
|
|||
return regCheatSheetWS;
|
||||
}
|
||||
|
||||
const char* DivPlatformSwan::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Change waveform";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Setup noise mode (0: disabled; 1-8: enabled/tap)";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Setup sweep period (0: disabled; 1-20: enabled/period)";
|
||||
break;
|
||||
case 0x13:
|
||||
return "13xx: Set sweep amount";
|
||||
break;
|
||||
case 0x17:
|
||||
return "17xx: Toggle PCM mode";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformSwan::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
// PCM part
|
||||
|
|
@ -155,18 +134,9 @@ void DivPlatformSwan::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.wave.had && !(i==1 && pcm)) {
|
||||
if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,6 @@ class DivPlatformSwan: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformSwan();
|
||||
|
|
|
|||
|
|
@ -34,15 +34,6 @@ const char* regCheatSheetTIA[]={
|
|||
NULL
|
||||
};
|
||||
|
||||
const char* DivPlatformTIA::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Select shape (0 to F)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char** DivPlatformTIA::getRegisterSheet() {
|
||||
return regCheatSheetTIA;
|
||||
}
|
||||
|
|
@ -96,20 +87,18 @@ void DivPlatformTIA::tick(bool sysTick) {
|
|||
rWrite(0x19+i,chan[i].outVol&15);
|
||||
}
|
||||
}
|
||||
// TODO: the way arps work on TIA is really weird
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=0x80000000|chan[i].std.arp.val;
|
||||
if (chan[i].std.arp.val<0 && (!(chan[i].std.arp.val&0x40000000))) {
|
||||
chan[i].baseFreq=0x80000000|(chan[i].std.arp.val|0x40000000);
|
||||
} else if (chan[i].std.arp.val>=0 && chan[i].std.arp.val&0x40000000) {
|
||||
chan[i].baseFreq=0x80000000|(chan[i].std.arp.val&(~0x40000000));
|
||||
} else {
|
||||
chan[i].baseFreq=(chan[i].note+chan[i].std.arp.val)<<8;
|
||||
}
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=chan[i].note<<8;
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.wave.had) {
|
||||
chan[i].shape=chan[i].std.wave.val&15;
|
||||
|
|
@ -126,13 +115,6 @@ void DivPlatformTIA::tick(bool sysTick) {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
if (chan[i].insChanged) {
|
||||
if (!chan[i].std.wave.will) {
|
||||
chan[i].shape=4;
|
||||
rWrite(0x15+i,chan[i].shape);
|
||||
}
|
||||
chan[i].insChanged=false;
|
||||
}
|
||||
chan[i].freq=dealWithFreq(chan[i].shape,chan[i].baseFreq,chan[i].pitch)+chan[i].pitch2;
|
||||
if ((chan[i].shape==4 || chan[i].shape==5) && !(chan[i].baseFreq&0x80000000 && ((chan[i].baseFreq&0x7fffffff)<32))) {
|
||||
if (chan[i].baseFreq<39*256) {
|
||||
|
|
@ -173,6 +155,13 @@ int DivPlatformTIA::dispatch(DivCommand c) {
|
|||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
if (chan[c.chan].insChanged) {
|
||||
if (!chan[c.chan].std.wave.will) {
|
||||
chan[c.chan].shape=4;
|
||||
rWrite(0x15+c.chan,chan[c.chan].shape);
|
||||
}
|
||||
chan[c.chan].insChanged=false;
|
||||
}
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x19+c.chan,0);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@ class DivPlatformTIA: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -55,139 +55,6 @@ const char** DivPlatformTX81Z::getRegisterSheet() {
|
|||
return regCheatSheetOPZ;
|
||||
}
|
||||
|
||||
const char* DivPlatformTX81Z::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Set noise frequency (xx: value; 0 disables noise)";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Set feedback (0 to 7)";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Set level of operator 1 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x13:
|
||||
return "13xx: Set level of operator 2 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x14:
|
||||
return "14xx: Set level of operator 3 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x15:
|
||||
return "15xx: Set level of operator 4 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x16:
|
||||
return "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)";
|
||||
break;
|
||||
case 0x17:
|
||||
return "17xx: Set LFO speed";
|
||||
break;
|
||||
case 0x18:
|
||||
return "18xx: Set LFO waveform (0 saw, 1 square, 2 triangle, 3 noise)";
|
||||
break;
|
||||
case 0x19:
|
||||
return "19xx: Set attack of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x1a:
|
||||
return "1Axx: Set attack of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x1b:
|
||||
return "1Bxx: Set attack of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x1c:
|
||||
return "1Cxx: Set attack of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x1d:
|
||||
return "1Dxx: Set attack of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x1e:
|
||||
return "1Exx: Set AM depth (0 to 7F)";
|
||||
break;
|
||||
case 0x1f:
|
||||
return "1Fxx: Set PM depth (0 to 7F)";
|
||||
break;
|
||||
case 0x28:
|
||||
return "28xy: Set reverb (x: operator from 1 to 4 (0 for all ops); y: reverb from 0 to 7)";
|
||||
break;
|
||||
case 0x2a:
|
||||
return "2Axy: Set waveform (x: operator from 1 to 4 (0 for all ops); y: waveform from 0 to 7)";
|
||||
break;
|
||||
case 0x2b:
|
||||
return "2Bxy: Set envelope generator shift (x: operator from 1 to 4 (0 for all ops); y: shift from 0 to 3)";
|
||||
break;
|
||||
case 0x2c:
|
||||
return "2Cxy: Set fine multiplier (x: operator from 1 to 4 (0 for all ops); y: fine)";
|
||||
break;
|
||||
case 0x2f:
|
||||
return "2Fxx: Toggle hard envelope reset on new notes";
|
||||
break;
|
||||
case 0x30: case 0x31: case 0x32: case 0x33:
|
||||
case 0x34: case 0x35: case 0x36: case 0x37:
|
||||
return "3xyy: Set fixed frequency of operator 1 (x: octave from 0 to 7; y: frequency)";
|
||||
break;
|
||||
case 0x38: case 0x39: case 0x3a: case 0x3b:
|
||||
case 0x3c: case 0x3d: case 0x3e: case 0x3f:
|
||||
return "3xyy: Set fixed frequency of operator 2 (x: octave from 8 to F; y: frequency)";
|
||||
break;
|
||||
case 0x40: case 0x41: case 0x42: case 0x43:
|
||||
case 0x44: case 0x45: case 0x46: case 0x47:
|
||||
return "4xyy: Set fixed frequency of operator 3 (x: octave from 0 to 7; y: frequency)";
|
||||
break;
|
||||
case 0x48: case 0x49: case 0x4a: case 0x4b:
|
||||
case 0x4c: case 0x4d: case 0x4e: case 0x4f:
|
||||
return "4xyy: Set fixed frequency of operator 4 (x: octave from 8 to F; y: frequency)";
|
||||
break;
|
||||
case 0x50:
|
||||
return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)";
|
||||
break;
|
||||
case 0x51:
|
||||
return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)";
|
||||
break;
|
||||
case 0x52:
|
||||
return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)";
|
||||
break;
|
||||
case 0x53:
|
||||
return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)";
|
||||
break;
|
||||
case 0x54:
|
||||
return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)";
|
||||
break;
|
||||
case 0x55:
|
||||
return "55xy: Set detune 2 (x: operator from 1 to 4 (0 for all ops); y: detune from 0 to 3)";
|
||||
break;
|
||||
case 0x56:
|
||||
return "56xx: Set decay of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x57:
|
||||
return "57xx: Set decay of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x58:
|
||||
return "58xx: Set decay of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x59:
|
||||
return "59xx: Set decay of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5a:
|
||||
return "5Axx: Set decay of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x5b:
|
||||
return "5Bxx: Set decay 2 of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x5c:
|
||||
return "5Cxx: Set decay 2 of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x5d:
|
||||
return "5Dxx: Set decay 2 of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x5e:
|
||||
return "5Exx: Set decay 2 of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5f:
|
||||
return "5Fxx: Set decay 2 of operator 4 (0 to 1F)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformTX81Z::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
static int os[2];
|
||||
|
||||
|
|
@ -256,18 +123,9 @@ void DivPlatformTX81Z::tick(bool sysTick) {
|
|||
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_LINEAR(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_LINEAR(chan[i].note+(signed char)chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_LINEAR(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_LINEAR(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.duty.had) {
|
||||
|
|
|
|||
|
|
@ -108,7 +108,6 @@ class DivPlatformTX81Z: public DivPlatformOPM {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformTX81Z();
|
||||
|
|
|
|||
|
|
@ -51,18 +51,6 @@ const char** DivPlatformVERA::getRegisterSheet() {
|
|||
return regCheatSheetVERA;
|
||||
}
|
||||
|
||||
const char* DivPlatformVERA::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x20:
|
||||
return "20xx: Change waveform";
|
||||
break;
|
||||
case 0x22:
|
||||
return "22xx: Set duty cycle (0 to 3F)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
// both PSG part and PCM part output a full 16-bit range, putting bufL/R
|
||||
// argument right into both could cause an overflow
|
||||
|
|
@ -171,18 +159,9 @@ void DivPlatformVERA::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=calcNoteFreq(0,chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=calcNoteFreq(0,chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=calcNoteFreq(0,parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=calcNoteFreq(0,chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
rWriteLo(i,3,chan[i].std.duty.val);
|
||||
|
|
@ -221,18 +200,9 @@ void DivPlatformVERA::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[16].std.arp.had) {
|
||||
if (!chan[16].inPorta) {
|
||||
if (chan[16].std.arp.mode) {
|
||||
chan[16].baseFreq=calcNoteFreq(16,chan[16].std.arp.val);
|
||||
} else {
|
||||
chan[16].baseFreq=calcNoteFreq(16,chan[16].note+chan[16].std.arp.val);
|
||||
}
|
||||
chan[16].baseFreq=calcNoteFreq(16,parent->calcArp(chan[16].note,chan[16].std.arp.val));
|
||||
}
|
||||
chan[16].freqChanged=true;
|
||||
} else {
|
||||
if (chan[16].std.arp.mode && chan[16].std.arp.finished) {
|
||||
chan[16].baseFreq=calcNoteFreq(16,chan[16].note);
|
||||
chan[16].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[16].freqChanged) {
|
||||
double off=65536.0;
|
||||
|
|
|
|||
|
|
@ -79,7 +79,6 @@ class DivPlatformVERA: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformVERA();
|
||||
|
|
|
|||
|
|
@ -39,15 +39,6 @@ const char** DivPlatformVIC20::getRegisterSheet() {
|
|||
return regCheatSheetVIC;
|
||||
}
|
||||
|
||||
const char* DivPlatformVIC20::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Change waveform";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformVIC20::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
const unsigned char loadFreq[3] = {0x7e, 0x7d, 0x7b};
|
||||
const unsigned char wavePatterns[16] = {
|
||||
|
|
@ -103,18 +94,9 @@ void DivPlatformVIC20::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.wave.had) {
|
||||
if (chan[i].wave!=chan[i].std.wave.val) {
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ class DivPlatformVIC20: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformVIC20();
|
||||
|
|
|
|||
|
|
@ -46,18 +46,6 @@ const char** DivPlatformVRC6::getRegisterSheet() {
|
|||
return regCheatSheetVRC6;
|
||||
}
|
||||
|
||||
const char* DivPlatformVRC6::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x12:
|
||||
return "12xx: Set duty cycle (pulse: 0 to 7)";
|
||||
break;
|
||||
case 0x17:
|
||||
return "17xx: Toggle PCM mode (pulse channel)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
for (size_t i=start; i<start+len; i++) {
|
||||
// PCM part
|
||||
|
|
@ -165,18 +153,9 @@ void DivPlatformVRC6::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
chan[i].duty=chan[i].std.duty.val;
|
||||
|
|
|
|||
|
|
@ -99,7 +99,6 @@ class DivPlatformVRC6: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
DivPlatformVRC6() : vrc6(intf) {};
|
||||
|
|
|
|||
|
|
@ -205,39 +205,6 @@ const char** DivPlatformX1_010::getRegisterSheet() {
|
|||
return regCheatSheetX1_010;
|
||||
}
|
||||
|
||||
const char* DivPlatformX1_010::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Change waveform";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Change envelope shape";
|
||||
break;
|
||||
case 0x17:
|
||||
return "17xx: Toggle PCM mode";
|
||||
break;
|
||||
case 0x20:
|
||||
return "20xx: Set PCM frequency (1 to FF)";
|
||||
break;
|
||||
case 0x22:
|
||||
return "22xx: Set envelope mode (bit 0: enable, bit 1: one-shot, bit 2: split shape to L/R, bit 3/5: H.invert right/left, bit 4/6: V.invert right/left)";
|
||||
break;
|
||||
case 0x23:
|
||||
return "23xx: Set envelope period";
|
||||
break;
|
||||
case 0x25:
|
||||
return "25xx: Envelope slide up";
|
||||
break;
|
||||
case 0x26:
|
||||
return "26xx: Envelope slide down";
|
||||
break;
|
||||
case 0x29:
|
||||
return "29xy: Set auto-envelope (x: numerator; y: denominator)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformX1_010::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
x1_010.tick();
|
||||
|
|
@ -366,18 +333,9 @@ void DivPlatformX1_010::tick(bool sysTick) {
|
|||
if ((!chan[i].pcm) || chan[i].furnacePCM) {
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NoteX1_010(i,chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NoteX1_010(i,chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NoteX1_010(i,parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NoteX1_010(i,chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[i].std.wave.had && !chan[i].pcm) {
|
||||
|
|
|
|||
|
|
@ -146,7 +146,6 @@ class DivPlatformX1_010: public DivDispatch, public x1_010_mem_intf {
|
|||
size_t getSampleMemUsage(int index = 0);
|
||||
void renderSamples();
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
void setBanked(bool banked);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
|
|
|
|||
|
|
@ -156,123 +156,6 @@ const char** DivPlatformYM2203::getRegisterSheet() {
|
|||
return regCheatSheetYM2203;
|
||||
}
|
||||
|
||||
const char* DivPlatformYM2203::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x11:
|
||||
return "11xx: Set feedback (0 to 7)";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Set level of operator 1 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x13:
|
||||
return "13xx: Set level of operator 2 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x14:
|
||||
return "14xx: Set level of operator 3 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x15:
|
||||
return "15xx: Set level of operator 4 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x16:
|
||||
return "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)";
|
||||
break;
|
||||
case 0x18:
|
||||
return "18xx: Toggle extended channel 3 mode";
|
||||
break;
|
||||
case 0x19:
|
||||
return "19xx: Set attack of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x1a:
|
||||
return "1Axx: Set attack of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x1b:
|
||||
return "1Bxx: Set attack of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x1c:
|
||||
return "1Cxx: Set attack of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x1d:
|
||||
return "1Dxx: Set attack of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x20:
|
||||
return "20xx: Set SSG channel mode (bit 0: square; bit 1: noise; bit 2: envelope)";
|
||||
break;
|
||||
case 0x21:
|
||||
return "21xx: Set SSG noise frequency (0 to 1F)";
|
||||
break;
|
||||
case 0x22:
|
||||
return "22xy: Set SSG envelope mode (x: shape, y: enable for this channel)";
|
||||
break;
|
||||
case 0x23:
|
||||
return "23xx: Set SSG envelope period low byte";
|
||||
break;
|
||||
case 0x24:
|
||||
return "24xx: Set SSG envelope period high byte";
|
||||
break;
|
||||
case 0x25:
|
||||
return "25xx: SSG envelope slide up";
|
||||
break;
|
||||
case 0x26:
|
||||
return "26xx: SSG envelope slide down";
|
||||
break;
|
||||
case 0x29:
|
||||
return "29xy: Set SSG auto-envelope (x: numerator; y: denominator)";
|
||||
break;
|
||||
case 0x30:
|
||||
return "30xx: Toggle hard envelope reset on new notes";
|
||||
break;
|
||||
case 0x50:
|
||||
return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)";
|
||||
break;
|
||||
case 0x51:
|
||||
return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)";
|
||||
break;
|
||||
case 0x52:
|
||||
return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)";
|
||||
break;
|
||||
case 0x53:
|
||||
return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)";
|
||||
break;
|
||||
case 0x54:
|
||||
return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)";
|
||||
break;
|
||||
case 0x55:
|
||||
return "55xy: Set SSG envelope (x: operator from 1 to 4 (0 for all ops); y: 0-7 on, 8 off)";
|
||||
break;
|
||||
case 0x56:
|
||||
return "56xx: Set decay of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x57:
|
||||
return "57xx: Set decay of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x58:
|
||||
return "58xx: Set decay of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x59:
|
||||
return "59xx: Set decay of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5a:
|
||||
return "5Axx: Set decay of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x5b:
|
||||
return "5Bxx: Set decay 2 of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x5c:
|
||||
return "5Cxx: Set decay 2 of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x5d:
|
||||
return "5Dxx: Set decay 2 of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x5e:
|
||||
return "5Exx: Set decay 2 of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5f:
|
||||
return "5Fxx: Set decay 2 of operator 4 (0 to 1F)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformYM2203::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
static int os;
|
||||
|
||||
|
|
@ -348,18 +231,9 @@ void DivPlatformYM2203::tick(bool sysTick) {
|
|||
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].std.arp.val,11);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note+(signed char)chan[i].std.arp.val,11);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11);
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note,11);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.pitch.had) {
|
||||
|
|
|
|||
|
|
@ -114,7 +114,6 @@ class DivPlatformYM2203: public DivPlatformOPN {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
void setFlags(unsigned int flags);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
|
|
|
|||
|
|
@ -279,126 +279,6 @@ const char** DivPlatformYM2608::getRegisterSheet() {
|
|||
return regCheatSheetYM2608;
|
||||
}
|
||||
|
||||
const char* DivPlatformYM2608::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xy: Setup LFO (x: enable; y: speed)";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Set feedback (0 to 7)";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Set level of operator 1 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x13:
|
||||
return "13xx: Set level of operator 2 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x14:
|
||||
return "14xx: Set level of operator 3 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x15:
|
||||
return "15xx: Set level of operator 4 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x16:
|
||||
return "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)";
|
||||
break;
|
||||
case 0x18:
|
||||
return "18xx: Toggle extended channel 3 mode";
|
||||
break;
|
||||
case 0x19:
|
||||
return "19xx: Set attack of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x1a:
|
||||
return "1Axx: Set attack of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x1b:
|
||||
return "1Bxx: Set attack of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x1c:
|
||||
return "1Cxx: Set attack of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x1d:
|
||||
return "1Dxx: Set attack of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x20:
|
||||
return "20xx: Set SSG channel mode (bit 0: square; bit 1: noise; bit 2: envelope)";
|
||||
break;
|
||||
case 0x21:
|
||||
return "21xx: Set SSG noise frequency (0 to 1F)";
|
||||
break;
|
||||
case 0x22:
|
||||
return "22xy: Set SSG envelope mode (x: shape, y: enable for this channel)";
|
||||
break;
|
||||
case 0x23:
|
||||
return "23xx: Set SSG envelope period low byte";
|
||||
break;
|
||||
case 0x24:
|
||||
return "24xx: Set SSG envelope period high byte";
|
||||
break;
|
||||
case 0x25:
|
||||
return "25xx: SSG envelope slide up";
|
||||
break;
|
||||
case 0x26:
|
||||
return "26xx: SSG envelope slide down";
|
||||
break;
|
||||
case 0x29:
|
||||
return "29xy: Set SSG auto-envelope (x: numerator; y: denominator)";
|
||||
break;
|
||||
case 0x30:
|
||||
return "30xx: Toggle hard envelope reset on new notes";
|
||||
break;
|
||||
case 0x50:
|
||||
return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)";
|
||||
break;
|
||||
case 0x51:
|
||||
return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)";
|
||||
break;
|
||||
case 0x52:
|
||||
return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)";
|
||||
break;
|
||||
case 0x53:
|
||||
return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)";
|
||||
break;
|
||||
case 0x54:
|
||||
return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)";
|
||||
break;
|
||||
case 0x55:
|
||||
return "55xy: Set SSG envelope (x: operator from 1 to 4 (0 for all ops); y: 0-7 on, 8 off)";
|
||||
break;
|
||||
case 0x56:
|
||||
return "56xx: Set decay of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x57:
|
||||
return "57xx: Set decay of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x58:
|
||||
return "58xx: Set decay of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x59:
|
||||
return "59xx: Set decay of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5a:
|
||||
return "5Axx: Set decay of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x5b:
|
||||
return "5Bxx: Set decay 2 of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x5c:
|
||||
return "5Cxx: Set decay 2 of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x5d:
|
||||
return "5Dxx: Set decay 2 of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x5e:
|
||||
return "5Exx: Set decay 2 of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5f:
|
||||
return "5Fxx: Set decay 2 of operator 4 (0 to 1F)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
double DivPlatformYM2608::NOTE_OPNB(int ch, int note) {
|
||||
if (ch>8) { // ADPCM-B
|
||||
return NOTE_ADPCMB(note);
|
||||
|
|
@ -506,18 +386,9 @@ void DivPlatformYM2608::tick(bool sysTick) {
|
|||
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].std.arp.val,11);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note+(signed char)chan[i].std.arp.val,11);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11);
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note,11);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.panL.had) {
|
||||
|
|
@ -692,18 +563,9 @@ void DivPlatformYM2608::tick(bool sysTick) {
|
|||
|
||||
if (chan[15].std.arp.had) {
|
||||
if (!chan[15].inPorta) {
|
||||
if (chan[15].std.arp.mode) {
|
||||
chan[15].baseFreq=NOTE_ADPCMB(chan[15].std.arp.val);
|
||||
} else {
|
||||
chan[15].baseFreq=NOTE_ADPCMB(chan[15].note+(signed char)chan[15].std.arp.val);
|
||||
}
|
||||
chan[15].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[15].note,chan[15].std.arp.val));
|
||||
}
|
||||
chan[15].freqChanged=true;
|
||||
} else {
|
||||
if (chan[15].std.arp.mode && chan[15].std.arp.finished) {
|
||||
chan[15].baseFreq=NOTE_ADPCMB(chan[15].note);
|
||||
chan[15].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[15].std.panL.had) {
|
||||
if (chan[15].pan!=(chan[15].std.panL.val&3)) {
|
||||
|
|
|
|||
|
|
@ -130,7 +130,6 @@ class DivPlatformYM2608: public DivPlatformOPN {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
const void* getSampleMem(int index);
|
||||
size_t getSampleMemCapacity(int index);
|
||||
size_t getSampleMemUsage(int index);
|
||||
|
|
|
|||
|
|
@ -232,126 +232,6 @@ const char** DivPlatformYM2610::getRegisterSheet() {
|
|||
return regCheatSheetYM2610;
|
||||
}
|
||||
|
||||
const char* DivPlatformYM2610::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xy: Setup LFO (x: enable; y: speed)";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Set feedback (0 to 7)";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Set level of operator 1 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x13:
|
||||
return "13xx: Set level of operator 2 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x14:
|
||||
return "14xx: Set level of operator 3 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x15:
|
||||
return "15xx: Set level of operator 4 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x16:
|
||||
return "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)";
|
||||
break;
|
||||
case 0x18:
|
||||
return "18xx: Toggle extended channel 3 mode";
|
||||
break;
|
||||
case 0x19:
|
||||
return "19xx: Set attack of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x1a:
|
||||
return "1Axx: Set attack of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x1b:
|
||||
return "1Bxx: Set attack of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x1c:
|
||||
return "1Cxx: Set attack of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x1d:
|
||||
return "1Dxx: Set attack of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x20:
|
||||
return "20xx: Set SSG channel mode (bit 0: square; bit 1: noise; bit 2: envelope)";
|
||||
break;
|
||||
case 0x21:
|
||||
return "21xx: Set SSG noise frequency (0 to 1F)";
|
||||
break;
|
||||
case 0x22:
|
||||
return "22xy: Set SSG envelope mode (x: shape, y: enable for this channel)";
|
||||
break;
|
||||
case 0x23:
|
||||
return "23xx: Set SSG envelope period low byte";
|
||||
break;
|
||||
case 0x24:
|
||||
return "24xx: Set SSG envelope period high byte";
|
||||
break;
|
||||
case 0x25:
|
||||
return "25xx: SSG envelope slide up";
|
||||
break;
|
||||
case 0x26:
|
||||
return "26xx: SSG envelope slide down";
|
||||
break;
|
||||
case 0x29:
|
||||
return "29xy: Set SSG auto-envelope (x: numerator; y: denominator)";
|
||||
break;
|
||||
case 0x30:
|
||||
return "30xx: Toggle hard envelope reset on new notes";
|
||||
break;
|
||||
case 0x50:
|
||||
return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)";
|
||||
break;
|
||||
case 0x51:
|
||||
return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)";
|
||||
break;
|
||||
case 0x52:
|
||||
return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)";
|
||||
break;
|
||||
case 0x53:
|
||||
return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)";
|
||||
break;
|
||||
case 0x54:
|
||||
return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)";
|
||||
break;
|
||||
case 0x55:
|
||||
return "55xy: Set SSG envelope (x: operator from 1 to 4 (0 for all ops); y: 0-7 on, 8 off)";
|
||||
break;
|
||||
case 0x56:
|
||||
return "56xx: Set decay of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x57:
|
||||
return "57xx: Set decay of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x58:
|
||||
return "58xx: Set decay of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x59:
|
||||
return "59xx: Set decay of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5a:
|
||||
return "5Axx: Set decay of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x5b:
|
||||
return "5Bxx: Set decay 2 of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x5c:
|
||||
return "5Cxx: Set decay 2 of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x5d:
|
||||
return "5Dxx: Set decay 2 of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x5e:
|
||||
return "5Exx: Set decay 2 of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5f:
|
||||
return "5Fxx: Set decay 2 of operator 4 (0 to 1F)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
static int os[2];
|
||||
|
||||
|
|
@ -443,18 +323,9 @@ void DivPlatformYM2610::tick(bool sysTick) {
|
|||
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].std.arp.val,11);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note+(signed char)chan[i].std.arp.val,11);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11);
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note,11);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.panL.had) {
|
||||
|
|
@ -632,18 +503,9 @@ void DivPlatformYM2610::tick(bool sysTick) {
|
|||
|
||||
if (chan[adpcmBChanOffs].std.arp.had) {
|
||||
if (!chan[adpcmBChanOffs].inPorta) {
|
||||
if (chan[adpcmBChanOffs].std.arp.mode) {
|
||||
chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].std.arp.val);
|
||||
} else {
|
||||
chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].note+(signed char)chan[adpcmBChanOffs].std.arp.val);
|
||||
}
|
||||
chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[adpcmBChanOffs].note,chan[adpcmBChanOffs].std.arp.val));
|
||||
}
|
||||
chan[adpcmBChanOffs].freqChanged=true;
|
||||
} else {
|
||||
if (chan[adpcmBChanOffs].std.arp.mode && chan[adpcmBChanOffs].std.arp.finished) {
|
||||
chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].note);
|
||||
chan[adpcmBChanOffs].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[adpcmBChanOffs].std.panL.had) {
|
||||
if (chan[adpcmBChanOffs].pan!=(chan[adpcmBChanOffs].std.panL.val&3)) {
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ class DivPlatformYM2610: public DivPlatformYM2610Base<14> {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
DivPlatformYM2610():
|
||||
|
|
|
|||
|
|
@ -296,126 +296,6 @@ const char** DivPlatformYM2610B::getRegisterSheet() {
|
|||
return regCheatSheetYM2610B;
|
||||
}
|
||||
|
||||
const char* DivPlatformYM2610B::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xy: Setup LFO (x: enable; y: speed)";
|
||||
break;
|
||||
case 0x11:
|
||||
return "11xx: Set feedback (0 to 7)";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Set level of operator 1 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x13:
|
||||
return "13xx: Set level of operator 2 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x14:
|
||||
return "14xx: Set level of operator 3 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x15:
|
||||
return "15xx: Set level of operator 4 (0 highest, 7F lowest)";
|
||||
break;
|
||||
case 0x16:
|
||||
return "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)";
|
||||
break;
|
||||
case 0x18:
|
||||
return "18xx: Toggle extended channel 3 mode";
|
||||
break;
|
||||
case 0x19:
|
||||
return "19xx: Set attack of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x1a:
|
||||
return "1Axx: Set attack of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x1b:
|
||||
return "1Bxx: Set attack of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x1c:
|
||||
return "1Cxx: Set attack of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x1d:
|
||||
return "1Dxx: Set attack of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x20:
|
||||
return "20xx: Set SSG channel mode (bit 0: square; bit 1: noise; bit 2: envelope)";
|
||||
break;
|
||||
case 0x21:
|
||||
return "21xx: Set SSG noise frequency (0 to 1F)";
|
||||
break;
|
||||
case 0x22:
|
||||
return "22xy: Set SSG envelope mode (x: shape, y: enable for this channel)";
|
||||
break;
|
||||
case 0x23:
|
||||
return "23xx: Set SSG envelope period low byte";
|
||||
break;
|
||||
case 0x24:
|
||||
return "24xx: Set SSG envelope period high byte";
|
||||
break;
|
||||
case 0x25:
|
||||
return "25xx: SSG envelope slide up";
|
||||
break;
|
||||
case 0x26:
|
||||
return "26xx: SSG envelope slide down";
|
||||
break;
|
||||
case 0x29:
|
||||
return "29xy: Set SSG auto-envelope (x: numerator; y: denominator)";
|
||||
break;
|
||||
case 0x30:
|
||||
return "30xx: Toggle hard envelope reset on new notes";
|
||||
break;
|
||||
case 0x50:
|
||||
return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)";
|
||||
break;
|
||||
case 0x51:
|
||||
return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)";
|
||||
break;
|
||||
case 0x52:
|
||||
return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)";
|
||||
break;
|
||||
case 0x53:
|
||||
return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)";
|
||||
break;
|
||||
case 0x54:
|
||||
return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)";
|
||||
break;
|
||||
case 0x55:
|
||||
return "55xy: Set SSG envelope (x: operator from 1 to 4 (0 for all ops); y: 0-7 on, 8 off)";
|
||||
break;
|
||||
case 0x56:
|
||||
return "56xx: Set decay of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x57:
|
||||
return "57xx: Set decay of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x58:
|
||||
return "58xx: Set decay of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x59:
|
||||
return "59xx: Set decay of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5a:
|
||||
return "5Axx: Set decay of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x5b:
|
||||
return "5Bxx: Set decay 2 of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x5c:
|
||||
return "5Cxx: Set decay 2 of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x5d:
|
||||
return "5Dxx: Set decay 2 of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x5e:
|
||||
return "5Exx: Set decay 2 of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5f:
|
||||
return "5Fxx: Set decay 2 of operator 4 (0 to 1F)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
static int os[2];
|
||||
|
||||
|
|
@ -506,18 +386,9 @@ void DivPlatformYM2610B::tick(bool sysTick) {
|
|||
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].std.arp.val,11);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note+(signed char)chan[i].std.arp.val,11);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11);
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note,11);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.panL.had) {
|
||||
|
|
@ -694,18 +565,9 @@ void DivPlatformYM2610B::tick(bool sysTick) {
|
|||
|
||||
if (chan[adpcmBChanOffs].std.arp.had) {
|
||||
if (!chan[adpcmBChanOffs].inPorta) {
|
||||
if (chan[adpcmBChanOffs].std.arp.mode) {
|
||||
chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].std.arp.val);
|
||||
} else {
|
||||
chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].note+(signed char)chan[adpcmBChanOffs].std.arp.val);
|
||||
}
|
||||
chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[adpcmBChanOffs].note,chan[adpcmBChanOffs].std.arp.val));
|
||||
}
|
||||
chan[adpcmBChanOffs].freqChanged=true;
|
||||
} else {
|
||||
if (chan[adpcmBChanOffs].std.arp.mode && chan[adpcmBChanOffs].std.arp.finished) {
|
||||
chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].note);
|
||||
chan[adpcmBChanOffs].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[adpcmBChanOffs].std.panL.had) {
|
||||
if (chan[adpcmBChanOffs].pan!=(chan[adpcmBChanOffs].std.panL.val&3)) {
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base<16> {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
DivPlatformYM2610B():
|
||||
|
|
|
|||
|
|
@ -60,10 +60,6 @@ const char** DivPlatformYMZ280B::getRegisterSheet() {
|
|||
return regCheatSheetYMZ280B;
|
||||
}
|
||||
|
||||
const char* DivPlatformYMZ280B::getEffectName(unsigned char effect) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformYMZ280B::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
short buf[16][256];
|
||||
short *bufPtrs[16]={
|
||||
|
|
@ -99,18 +95,9 @@ void DivPlatformYMZ280B::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
if (chan[i].std.pitch.mode) {
|
||||
|
|
@ -344,6 +331,8 @@ void DivPlatformYMZ280B::forceIns() {
|
|||
chan[i].insChanged=true;
|
||||
chan[i].freqChanged=true;
|
||||
chan[i].sample=-1;
|
||||
|
||||
rWrite(0x03+i*4,chan[i].panning);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,6 @@ class DivPlatformYMZ280B: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
const void* getSampleMem(int index = 0);
|
||||
size_t getSampleMemCapacity(int index = 0);
|
||||
size_t getSampleMemUsage(int index = 0);
|
||||
|
|
|
|||
|
|
@ -27,18 +27,6 @@ const char** DivPlatformZXBeeper::getRegisterSheet() {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
const char* DivPlatformZXBeeper::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x12:
|
||||
return "12xx: Set pulse width";
|
||||
break;
|
||||
case 0x17:
|
||||
return "17xx: Trigger overlay drum";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformZXBeeper::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
bool o=false;
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
|
|
@ -93,18 +81,9 @@ void DivPlatformZXBeeper::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
if (chan[i].std.pitch.mode) {
|
||||
|
|
|
|||
|
|
@ -92,7 +92,6 @@ class DivPlatformZXBeeper: public DivDispatch {
|
|||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformZXBeeper();
|
||||
|
|
|
|||
|
|
@ -295,13 +295,39 @@ int DivEngine::dispatchCmd(DivCommand c) {
|
|||
}
|
||||
|
||||
bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effectVal) {
|
||||
if (sysDefs[sysOfChan[ch]]==NULL) return false;
|
||||
return sysDefs[sysOfChan[ch]]->effectFunc(ch,effect,effectVal);
|
||||
DivSysDef* sysDef=sysDefs[sysOfChan[ch]];
|
||||
if (sysDef==NULL) return false;
|
||||
auto iter=sysDef->effectHandlers.find(effect);
|
||||
if (iter==sysDef->effectHandlers.end()) return false;
|
||||
EffectHandler handler=iter->second;
|
||||
int val=0;
|
||||
int val2=0;
|
||||
try {
|
||||
val=handler.val?handler.val(effect,effectVal):effectVal;
|
||||
val2=handler.val2?handler.val2(effect,effectVal):0;
|
||||
} catch (DivDoNotHandleEffect& e) {
|
||||
return false;
|
||||
}
|
||||
// wouldn't this cause problems if it were to return 0?
|
||||
return dispatchCmd(DivCommand(handler.dispatchCmd,ch,val,val2));
|
||||
}
|
||||
|
||||
bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal) {
|
||||
if (sysDefs[sysOfChan[ch]]==NULL) return false;
|
||||
return sysDefs[sysOfChan[ch]]->postEffectFunc(ch,effect,effectVal);
|
||||
DivSysDef* sysDef=sysDefs[sysOfChan[ch]];
|
||||
if (sysDef==NULL) return false;
|
||||
auto iter=sysDef->postEffectHandlers.find(effect);
|
||||
if (iter==sysDef->postEffectHandlers.end()) return false;
|
||||
EffectHandler handler=iter->second;
|
||||
int val=0;
|
||||
int val2=0;
|
||||
try {
|
||||
val=handler.val?handler.val(effect,effectVal):effectVal;
|
||||
val2=handler.val2?handler.val2(effect,effectVal):0;
|
||||
} catch (DivDoNotHandleEffect& e) {
|
||||
return true;
|
||||
}
|
||||
// wouldn't this cause problems if it were to return 0?
|
||||
return dispatchCmd(DivCommand(handler.dispatchCmd,ch,val,val2));
|
||||
}
|
||||
|
||||
void DivEngine::processRow(int i, bool afterDelay) {
|
||||
|
|
@ -338,7 +364,9 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
break;
|
||||
case 0xed: // delay
|
||||
if (effectVal!=0) {
|
||||
if (effectVal<=nextSpeed) {
|
||||
bool comparison=(song.delayBehavior==1)?(effectVal<=nextSpeed):(effectVal<nextSpeed);
|
||||
if (song.delayBehavior==2) comparison=true;
|
||||
if (comparison) {
|
||||
chan[i].rowDelay=effectVal+1;
|
||||
chan[i].delayOrder=whatOrder;
|
||||
chan[i].delayRow=whatRow;
|
||||
|
|
@ -349,6 +377,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
}
|
||||
returnAfterPre=true;
|
||||
} else {
|
||||
logV("higher than nextSpeed! %d>%d",effectVal,nextSpeed);
|
||||
chan[i].delayLocked=false;
|
||||
}
|
||||
}
|
||||
|
|
@ -356,6 +385,8 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
}
|
||||
}
|
||||
if (returnAfterPre) return;
|
||||
} else {
|
||||
logV("honoring delay at position %d",whatRow);
|
||||
}
|
||||
|
||||
if (chan[i].delayLocked) return;
|
||||
|
|
@ -607,14 +638,11 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
break;
|
||||
case 0xc0: case 0xc1: case 0xc2: case 0xc3: // set Hz
|
||||
divider=(double)(((effect&0x3)<<8)|effectVal);
|
||||
if (divider<10) divider=10;
|
||||
if (divider<1) divider=1;
|
||||
cycles=got.rate*pow(2,MASTER_CLOCK_PREC)/divider;
|
||||
clockDrift=0;
|
||||
subticks=0;
|
||||
break;
|
||||
case 0xdf: // set sample direction
|
||||
dispatchCmd(DivCommand(DIV_CMD_SAMPLE_DIR,i,effectVal));
|
||||
break;
|
||||
case 0xe0: // arp speed
|
||||
if (effectVal>0) {
|
||||
curSubSong->arpLen=effectVal;
|
||||
|
|
@ -684,7 +712,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
dispatchCmd(DivCommand(DIV_CMD_SAMPLE_BANK,i,effectVal));
|
||||
break;
|
||||
case 0xec: // delayed note cut
|
||||
if (effectVal>0 && effectVal<nextSpeed) {
|
||||
if (effectVal>0 && (song.delayBehavior==2 || effectVal<nextSpeed)) {
|
||||
chan[i].cut=effectVal+1;
|
||||
}
|
||||
break;
|
||||
|
|
@ -698,7 +726,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
break;
|
||||
case 0xf0: // set Hz by tempo
|
||||
divider=(double)effectVal*2.0/5.0;
|
||||
if (divider<10) divider=10;
|
||||
if (divider<1) divider=1;
|
||||
cycles=got.rate*pow(2,MASTER_CLOCK_PREC)/divider;
|
||||
clockDrift=0;
|
||||
subticks=0;
|
||||
|
|
@ -881,7 +909,9 @@ void DivEngine::nextRow() {
|
|||
prevRow=curRow;
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
chan[i].rowDelay=0;
|
||||
if (song.delayBehavior!=2) {
|
||||
chan[i].rowDelay=0;
|
||||
}
|
||||
processRow(i,false);
|
||||
}
|
||||
|
||||
|
|
@ -963,7 +993,7 @@ void DivEngine::nextRow() {
|
|||
|
||||
bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
||||
bool ret=false;
|
||||
if (divider<10) divider=10;
|
||||
if (divider<1) divider=1;
|
||||
|
||||
if (lowLatency && !skipping && !inhibitLowLat) {
|
||||
tickMult=1000/divider;
|
||||
|
|
@ -984,10 +1014,27 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
//output->midiOut->send(TAMidiMessage(TA_MIDI_CLOCK,0,0));
|
||||
}
|
||||
|
||||
if (!pendingNotes.empty()) {
|
||||
bool isOn[DIV_MAX_CHANS];
|
||||
memset(isOn,0,DIV_MAX_CHANS*sizeof(bool));
|
||||
|
||||
for (int i=pendingNotes.size()-1; i>=0; i--) {
|
||||
if (pendingNotes[i].channel<0 || pendingNotes[i].channel>=chans) continue;
|
||||
if (pendingNotes[i].on) {
|
||||
isOn[pendingNotes[i].channel]=true;
|
||||
} else {
|
||||
if (isOn[pendingNotes[i].channel]) {
|
||||
logV("erasing off -> on sequence in %d",pendingNotes[i].channel);
|
||||
pendingNotes.erase(pendingNotes.begin()+i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (!pendingNotes.empty()) {
|
||||
DivNoteEvent& note=pendingNotes.front();
|
||||
if (note.channel<0 || note.channel>=chans) {
|
||||
pendingNotes.pop();
|
||||
pendingNotes.pop_front();
|
||||
continue;
|
||||
}
|
||||
if (note.on) {
|
||||
|
|
@ -1007,7 +1054,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF,note.channel));
|
||||
}
|
||||
}
|
||||
pendingNotes.pop();
|
||||
pendingNotes.pop_front();
|
||||
}
|
||||
|
||||
if (!freelance) {
|
||||
|
|
@ -1219,7 +1266,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
case TA_MIDI_NOTE_OFF: {
|
||||
if (chan<0 || chan>=chans) break;
|
||||
if (midiIsDirect) {
|
||||
pendingNotes.push(DivNoteEvent(chan,-1,-1,-1,false));
|
||||
pendingNotes.push_back(DivNoteEvent(chan,-1,-1,-1,false));
|
||||
} else {
|
||||
autoNoteOff(msg.type&15,msg.data[0]-12,msg.data[1]);
|
||||
}
|
||||
|
|
@ -1234,13 +1281,13 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
if (chan<0 || chan>=chans) break;
|
||||
if (msg.data[1]==0) {
|
||||
if (midiIsDirect) {
|
||||
pendingNotes.push(DivNoteEvent(chan,-1,-1,-1,false));
|
||||
pendingNotes.push_back(DivNoteEvent(chan,-1,-1,-1,false));
|
||||
} else {
|
||||
autoNoteOff(msg.type&15,msg.data[0]-12,msg.data[1]);
|
||||
}
|
||||
} else {
|
||||
if (midiIsDirect) {
|
||||
pendingNotes.push(DivNoteEvent(chan,ins,msg.data[0]-12,msg.data[1],true));
|
||||
pendingNotes.push_back(DivNoteEvent(chan,ins,msg.data[0]-12,msg.data[1],true));
|
||||
} else {
|
||||
autoNoteOn(msg.type&15,ins,msg.data[0]-12,msg.data[1]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,6 +77,85 @@ signed char SafeReader::readC() {
|
|||
return (signed char)buf[curSeek++];
|
||||
}
|
||||
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
short SafeReader::readS_BE() {
|
||||
#ifdef READ_DEBUG
|
||||
logD("SR: reading short %x:",curSeek);
|
||||
#endif
|
||||
if (curSeek+2>len) throw EndOfFileException(this,len);
|
||||
short ret;
|
||||
memcpy(&ret,&buf[curSeek],2);
|
||||
#ifdef READ_DEBUG
|
||||
logD("SR: %.4x",ret);
|
||||
#endif
|
||||
curSeek+=2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
short SafeReader::readS() {
|
||||
if (curSeek+2>len) throw EndOfFileException(this,len);
|
||||
short ret;
|
||||
memcpy(&ret,&buf[curSeek],2);
|
||||
curSeek+=2;
|
||||
return ((ret>>8)&0xff)|(ret<<8);
|
||||
}
|
||||
|
||||
int SafeReader::readI_BE() {
|
||||
#ifdef READ_DEBUG
|
||||
logD("SR: reading int %x:",curSeek);
|
||||
#endif
|
||||
if (curSeek+4>len) throw EndOfFileException(this,len);
|
||||
int ret;
|
||||
memcpy(&ret,&buf[curSeek],4);
|
||||
curSeek+=4;
|
||||
#ifdef READ_DEBUG
|
||||
logD("SR: %.8x",ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SafeReader::readI() {
|
||||
if (curSeek+4>len) throw EndOfFileException(this,len);
|
||||
unsigned int ret;
|
||||
memcpy(&ret,&buf[curSeek],4);
|
||||
curSeek+=4;
|
||||
return (int)((ret>>24)|((ret&0xff0000)>>8)|((ret&0xff00)<<8)|((ret&0xff)<<24));
|
||||
}
|
||||
|
||||
int64_t SafeReader::readL() {
|
||||
if (curSeek+8>len) throw EndOfFileException(this,len);
|
||||
unsigned char ret[8];
|
||||
memcpy(ret,&buf[curSeek],8);
|
||||
curSeek+=8;
|
||||
return (int64_t)(ret[0]|(ret[1]<<8)|(ret[2]<<16)|(ret[3]<<24)|((uint64_t)ret[4]<<32)|((uint64_t)ret[5]<<40)|((uint64_t)ret[6]<<48)|((uint64_t)ret[7]<<56));
|
||||
}
|
||||
|
||||
float SafeReader::readF() {
|
||||
if (curSeek+4>len) throw EndOfFileException(this,len);
|
||||
unsigned int ret;
|
||||
memcpy(&ret,&buf[curSeek],4);
|
||||
curSeek+=4;
|
||||
ret=((ret>>24)|((ret&0xff0000)>>8)|((ret&0xff00)<<8)|((ret&0xff)<<24));
|
||||
return *((float*)(&ret));
|
||||
}
|
||||
|
||||
double SafeReader::readD() {
|
||||
if (curSeek+8>len) throw EndOfFileException(this,len);
|
||||
unsigned char ret[8];
|
||||
unsigned char retB[8];
|
||||
memcpy(ret,&buf[curSeek],8);
|
||||
curSeek+=8;
|
||||
retB[0]=ret[7];
|
||||
retB[1]=ret[6];
|
||||
retB[2]=ret[5];
|
||||
retB[3]=ret[4];
|
||||
retB[4]=ret[3];
|
||||
retB[5]=ret[2];
|
||||
retB[6]=ret[1];
|
||||
retB[7]=ret[0];
|
||||
return *((double*)retB);
|
||||
}
|
||||
#else
|
||||
short SafeReader::readS() {
|
||||
#ifdef READ_DEBUG
|
||||
logD("SR: reading short %x:",curSeek);
|
||||
|
|
@ -144,6 +223,7 @@ double SafeReader::readD() {
|
|||
curSeek+=8;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
String SafeReader::readString(size_t stlen) {
|
||||
String ret;
|
||||
|
|
|
|||
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