Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt
This commit is contained in:
commit
7867b59580
85 changed files with 6024 additions and 3108 deletions
|
|
@ -532,23 +532,46 @@ class DivDispatch {
|
|||
|
||||
/**
|
||||
* Get sample memory buffer.
|
||||
* @param index the memory index.
|
||||
* @return a pointer to sample memory, or NULL.
|
||||
*/
|
||||
virtual const void* getSampleMem(int index = 0);
|
||||
|
||||
/**
|
||||
* Get sample memory capacity.
|
||||
* @param index the memory index.
|
||||
* @return memory capacity in bytes, or 0 if memory doesn't exist.
|
||||
*/
|
||||
virtual size_t getSampleMemCapacity(int index = 0);
|
||||
|
||||
/**
|
||||
* get sample memory name.
|
||||
* @param index the memory index.
|
||||
* @return a name, or NULL if it doesn't have any name in particular.
|
||||
*/
|
||||
virtual const char* getSampleMemName(int index=0);
|
||||
|
||||
/**
|
||||
* Get sample memory usage.
|
||||
* @param index the memory index.
|
||||
* @return memory usage in bytes.
|
||||
*/
|
||||
virtual size_t getSampleMemUsage(int index = 0);
|
||||
|
||||
/**
|
||||
* Render samples into sample memory.
|
||||
* check whether sample has been loaded in memory.
|
||||
* @param memory index.
|
||||
* @param sample the sample in question.
|
||||
* @return whether it did.
|
||||
*/
|
||||
virtual void renderSamples();
|
||||
virtual bool isSampleLoaded(int index, int sample);
|
||||
|
||||
|
||||
/**
|
||||
* Render samples into sample memory.
|
||||
* @param sysID the chip's index in the chip list.
|
||||
*/
|
||||
virtual void renderSamples(int sysID);
|
||||
|
||||
/**
|
||||
* initialize this DivDispatch.
|
||||
|
|
|
|||
|
|
@ -1315,7 +1315,7 @@ void DivEngine::renderSamples() {
|
|||
// step 2: render samples to dispatch
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
if (disCont[i].dispatch!=NULL) {
|
||||
disCont[i].dispatch->renderSamples();
|
||||
disCont[i].dispatch->renderSamples(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2478,10 +2478,10 @@ void DivEngine::previewSampleNoLock(int sample, int note, int pStart, int pEnd)
|
|||
return;
|
||||
}
|
||||
blip_clear(samp_bb);
|
||||
double rate=song.sample[sample]->rate;
|
||||
double rate=song.sample[sample]->centerRate;
|
||||
if (note>=0) {
|
||||
rate=(pow(2.0,(double)(note)/12.0)*((double)song.sample[sample]->centerRate)*0.0625);
|
||||
if (rate<=0) rate=song.sample[sample]->rate;
|
||||
if (rate<=0) rate=song.sample[sample]->centerRate;
|
||||
}
|
||||
if (rate<100) rate=100;
|
||||
blip_set_rates(samp_bb,rate,got.rate);
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@
|
|||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||
|
||||
#define DIV_VERSION "dev125"
|
||||
#define DIV_ENGINE_VERSION 125
|
||||
#define DIV_VERSION "dev128"
|
||||
#define DIV_ENGINE_VERSION 128
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
#define DIV_VERSION_FC 0xff02
|
||||
|
|
@ -766,7 +766,7 @@ class DivEngine {
|
|||
|
||||
// get instrument from file
|
||||
// if the returned vector is empty then there was an error.
|
||||
std::vector<DivInstrument*> instrumentFromFile(const char* path);
|
||||
std::vector<DivInstrument*> instrumentFromFile(const char* path, bool loadAssets=true);
|
||||
|
||||
// load temporary instrument
|
||||
void loadTempIns(DivInstrument* which);
|
||||
|
|
|
|||
|
|
@ -208,7 +208,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
}*/
|
||||
|
||||
// Game Boy arp+soundLen screwery
|
||||
ds.systemFlags[0].set("enoughAlready",true);
|
||||
if (ds.system[0]==DIV_SYSTEM_GB) {
|
||||
ds.systemFlags[0].set("enoughAlready",true);
|
||||
}
|
||||
|
||||
logI("reading module data...");
|
||||
if (ds.version>0x0c) {
|
||||
|
|
@ -966,6 +968,11 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
ds.system[1]=DIV_SYSTEM_FDS;
|
||||
}
|
||||
|
||||
// SMS noise freq
|
||||
if (ds.system[0]==DIV_SYSTEM_SMS) {
|
||||
ds.systemFlags[0].set("noEasyNoise",true);
|
||||
}
|
||||
|
||||
ds.systemName=getSongSystemLegacyName(ds,!getConfInt("noMultiSystem",0));
|
||||
|
||||
if (active) quitDispatch();
|
||||
|
|
@ -2348,142 +2355,24 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
|
||||
// read samples
|
||||
for (int i=0; i<ds.sampleLen; i++) {
|
||||
int vol=0;
|
||||
int pitch=0;
|
||||
DivSample* sample=new DivSample;
|
||||
|
||||
if (!reader.seek(samplePtr[i],SEEK_SET)) {
|
||||
logE("couldn't seek to sample %d!",i);
|
||||
lastError=fmt::sprintf("couldn't seek to sample %d!",i);
|
||||
ds.unload();
|
||||
delete sample;
|
||||
delete[] file;
|
||||
return false;
|
||||
}
|
||||
|
||||
reader.read(magic,4);
|
||||
if (strcmp(magic,"SMPL")!=0 && strcmp(magic,"SMP2")!=0) {
|
||||
logE("%d: invalid sample header!",i);
|
||||
lastError="invalid sample header!";
|
||||
if (sample->readSampleData(reader,ds.version)!=DIV_DATA_SUCCESS) {
|
||||
lastError="invalid sample header/data!";
|
||||
ds.unload();
|
||||
delete sample;
|
||||
delete[] file;
|
||||
return false;
|
||||
}
|
||||
bool isNewSample=(strcmp(magic,"SMP2")==0);
|
||||
reader.readI();
|
||||
DivSample* sample=new DivSample;
|
||||
logD("reading sample %d at %x...",i,samplePtr[i]);
|
||||
if (!isNewSample) logV("(old sample)");
|
||||
|
||||
sample->name=reader.readString();
|
||||
sample->samples=reader.readI();
|
||||
if (!isNewSample) {
|
||||
sample->loopEnd=sample->samples;
|
||||
}
|
||||
sample->rate=reader.readI();
|
||||
|
||||
if (isNewSample) {
|
||||
sample->centerRate=reader.readI();
|
||||
sample->depth=(DivSampleDepth)reader.readC();
|
||||
if (ds.version>=123) {
|
||||
sample->loopMode=(DivSampleLoopMode)reader.readC();
|
||||
} else {
|
||||
sample->loopMode=DIV_SAMPLE_LOOP_FORWARD;
|
||||
reader.readC();
|
||||
}
|
||||
|
||||
// reserved
|
||||
reader.readC();
|
||||
reader.readC();
|
||||
|
||||
sample->loopStart=reader.readI();
|
||||
sample->loopEnd=reader.readI();
|
||||
sample->loop=(sample->loopStart>=0)&&(sample->loopEnd>=0);
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
reader.readI();
|
||||
}
|
||||
} else {
|
||||
if (ds.version<58) {
|
||||
vol=reader.readS();
|
||||
pitch=reader.readS();
|
||||
} else {
|
||||
reader.readI();
|
||||
}
|
||||
sample->depth=(DivSampleDepth)reader.readC();
|
||||
|
||||
// reserved
|
||||
reader.readC();
|
||||
|
||||
// while version 32 stored this value, it was unused.
|
||||
if (ds.version>=38) {
|
||||
sample->centerRate=(unsigned short)reader.readS();
|
||||
} else {
|
||||
reader.readS();
|
||||
}
|
||||
|
||||
if (ds.version>=19) {
|
||||
sample->loopStart=reader.readI();
|
||||
sample->loop=(sample->loopStart>=0)&&(sample->loopEnd>=0);
|
||||
} else {
|
||||
reader.readI();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
for (int pos=0; pos<length; pos++) {
|
||||
data[pos]=((unsigned short)data[pos]>>8)|((unsigned short)data[pos]<<8);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pitch!=5) {
|
||||
logD("%d: scaling from %d...",i,pitch);
|
||||
}
|
||||
|
||||
// render data
|
||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) {
|
||||
logW("%d: sample depth is wrong! (%d)",i,sample->depth);
|
||||
sample->depth=DIV_SAMPLE_DEPTH_16BIT;
|
||||
}
|
||||
sample->samples=(double)sample->samples/samplePitches[pitch];
|
||||
sample->init(sample->samples);
|
||||
|
||||
unsigned int k=0;
|
||||
float mult=(float)(vol)/50.0f;
|
||||
for (double j=0; j<length; j+=samplePitches[pitch]) {
|
||||
if (k>=sample->samples) {
|
||||
break;
|
||||
}
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
float next=(float)(data[(unsigned int)j]-0x80)*mult;
|
||||
sample->data8[k++]=fmin(fmax(next,-128),127);
|
||||
} else {
|
||||
float next=(float)data[(unsigned int)j]*mult;
|
||||
sample->data16[k++]=fmin(fmax(next,-32768),32767);
|
||||
}
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
ds.sample.push_back(sample);
|
||||
}
|
||||
|
|
@ -2631,6 +2520,16 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
}
|
||||
}
|
||||
|
||||
// SN noise compat
|
||||
if (ds.version<128) {
|
||||
for (int i=0; i<ds.systemLen; i++) {
|
||||
if (ds.system[i]==DIV_SYSTEM_SMS ||
|
||||
ds.system[i]==DIV_SYSTEM_T6W28) {
|
||||
ds.systemFlags[i].set("noEasyNoise",true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (active) quitDispatch();
|
||||
BUSY_BEGIN_SOFT;
|
||||
saveLock.lock();
|
||||
|
|
@ -4621,7 +4520,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
for (int i=0; i<song.insLen; i++) {
|
||||
DivInstrument* ins=song.ins[i];
|
||||
insPtr.push_back(w->tell());
|
||||
ins->putInsData(w);
|
||||
logV("writing instrument %d...",i);
|
||||
ins->putInsData2(w,false);
|
||||
}
|
||||
|
||||
/// WAVETABLE
|
||||
|
|
@ -4635,45 +4535,7 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
for (int i=0; i<song.sampleLen; i++) {
|
||||
DivSample* sample=song.sample[i];
|
||||
samplePtr.push_back(w->tell());
|
||||
w->write("SMP2",4);
|
||||
blockStartSeek=w->tell();
|
||||
w->writeI(0);
|
||||
|
||||
w->writeString(sample->name,false);
|
||||
w->writeI(sample->samples);
|
||||
w->writeI(sample->rate);
|
||||
w->writeI(sample->centerRate);
|
||||
w->writeC(sample->depth);
|
||||
w->writeC(sample->loopMode);
|
||||
w->writeC(0); // reserved
|
||||
w->writeC(0);
|
||||
w->writeI(sample->loop?sample->loopStart:-1);
|
||||
w->writeI(sample->loop?sample->loopEnd:-1);
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
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);
|
||||
w->writeI(blockEndSeek-blockStartSeek-4);
|
||||
w->seek(0,SEEK_END);
|
||||
sample->putSampleData(w);
|
||||
}
|
||||
|
||||
/// PATTERN
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
|||
logD("instrument type is C64");
|
||||
break;
|
||||
case 8: // Arcade
|
||||
ins->type=DIV_INS_FM;
|
||||
ins->type=DIV_INS_OPM;
|
||||
logD("instrument type is Arcade");
|
||||
break;
|
||||
case 9: // Neo Geo
|
||||
|
|
@ -187,6 +187,8 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
|||
ins->type=DIV_INS_OPLL;
|
||||
} else if (sys==1) {
|
||||
ins->type=DIV_INS_OPL;
|
||||
} else if (sys==8) {
|
||||
ins->type=DIV_INS_OPM;
|
||||
} else {
|
||||
ins->type=DIV_INS_FM;
|
||||
}
|
||||
|
|
@ -1341,7 +1343,7 @@ void DivEngine::loadOPM(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
|||
// At this point we know any other line would be associated with patch params
|
||||
if (newPatch == NULL) {
|
||||
newPatch = new DivInstrument;
|
||||
newPatch->type = DIV_INS_FM;
|
||||
newPatch->type = DIV_INS_OPM;
|
||||
newPatch->fm.ops = 4;
|
||||
}
|
||||
|
||||
|
|
@ -1814,7 +1816,7 @@ void DivEngine::loadWOPN(SafeReader& reader, std::vector<DivInstrument*>& ret, S
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path) {
|
||||
std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path, bool loadAssets) {
|
||||
std::vector<DivInstrument*> ret;
|
||||
warnings="";
|
||||
|
||||
|
|
@ -1880,10 +1882,19 @@ std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path) {
|
|||
|
||||
unsigned char magic[16];
|
||||
bool isFurnaceInstr=false;
|
||||
bool isOldFurnaceIns=false;
|
||||
try {
|
||||
reader.read(magic,16);
|
||||
if (memcmp("-Furnace instr.-",magic,16)==0) {
|
||||
reader.read(magic,4);
|
||||
if (memcmp("FINS",magic,4)==0) {
|
||||
isFurnaceInstr=true;
|
||||
logV("found a new Furnace ins");
|
||||
} else {
|
||||
reader.read(&magic[4],12);
|
||||
if (memcmp("-Furnace instr.-",magic,16)==0) {
|
||||
logV("found an old Furnace ins");
|
||||
isFurnaceInstr=true;
|
||||
isOldFurnaceIns=true;
|
||||
}
|
||||
}
|
||||
} catch (EndOfFileException& e) {
|
||||
reader.seek(0,SEEK_SET);
|
||||
|
|
@ -1892,17 +1903,25 @@ std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path) {
|
|||
if (isFurnaceInstr) {
|
||||
DivInstrument* ins=new DivInstrument;
|
||||
try {
|
||||
short version=reader.readS();
|
||||
reader.readS(); // reserved
|
||||
short version=0;
|
||||
if (isOldFurnaceIns) {
|
||||
version=reader.readS();
|
||||
reader.readS(); // reserved
|
||||
} else {
|
||||
version=reader.readS();
|
||||
reader.seek(0,SEEK_SET);
|
||||
}
|
||||
|
||||
if (version>DIV_ENGINE_VERSION) {
|
||||
warnings="this instrument is made with a more recent version of Furnace!";
|
||||
}
|
||||
|
||||
unsigned int dataPtr=reader.readI();
|
||||
reader.seek(dataPtr,SEEK_SET);
|
||||
if (isOldFurnaceIns) {
|
||||
unsigned int dataPtr=reader.readI();
|
||||
reader.seek(dataPtr,SEEK_SET);
|
||||
}
|
||||
|
||||
if (ins->readInsData(reader,version)!=DIV_DATA_SUCCESS) {
|
||||
if (ins->readInsData(reader,version,loadAssets?(&song):NULL)!=DIV_DATA_SUCCESS) {
|
||||
lastError="invalid instrument header/data!";
|
||||
delete ins;
|
||||
delete[] buf;
|
||||
|
|
@ -1961,7 +1980,12 @@ std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path) {
|
|||
format=DIV_INSFORMAT_WOPL;
|
||||
} else if (extS==".wopn") {
|
||||
format=DIV_INSFORMAT_WOPN;
|
||||
}
|
||||
} else {
|
||||
// unknown format
|
||||
lastError="unknown instrument format";
|
||||
delete[] buf;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -24,6 +24,9 @@
|
|||
#include "safeWriter.h"
|
||||
#include "dataErrors.h"
|
||||
#include "../ta-utils.h"
|
||||
#include <vector>
|
||||
|
||||
struct DivSong;
|
||||
|
||||
// NOTICE!
|
||||
// before adding new instrument types to this struct, please ask me first.
|
||||
|
|
@ -97,11 +100,21 @@ struct DivInstrumentFM {
|
|||
unsigned char alg, fb, fms, ams, fms2, ams2, ops, opllPreset;
|
||||
bool fixedDrums;
|
||||
unsigned short kickFreq, snareHatFreq, tomTopFreq;
|
||||
|
||||
bool operator==(const DivInstrumentFM& other);
|
||||
bool operator!=(const DivInstrumentFM& other) {
|
||||
return !(*this==other);
|
||||
}
|
||||
struct Operator {
|
||||
bool enable;
|
||||
unsigned char am, ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv;
|
||||
unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759/OPL/OPZ
|
||||
unsigned char kvs;
|
||||
|
||||
bool operator==(const Operator& other);
|
||||
bool operator!=(const Operator& other) {
|
||||
return !(*this==other);
|
||||
}
|
||||
Operator():
|
||||
enable(true),
|
||||
am(0),
|
||||
|
|
@ -296,6 +309,12 @@ struct DivInstrumentGB {
|
|||
unsigned char cmd;
|
||||
unsigned short data;
|
||||
} hwSeq[256];
|
||||
|
||||
bool operator==(const DivInstrumentGB& other);
|
||||
bool operator!=(const DivInstrumentGB& other) {
|
||||
return !(*this==other);
|
||||
}
|
||||
|
||||
DivInstrumentGB():
|
||||
envVol(15),
|
||||
envDir(0),
|
||||
|
|
@ -318,6 +337,11 @@ struct DivInstrumentC64 {
|
|||
unsigned short cut;
|
||||
bool hp, lp, bp, ch3off;
|
||||
|
||||
bool operator==(const DivInstrumentC64& other);
|
||||
bool operator!=(const DivInstrumentC64& other) {
|
||||
return !(*this==other);
|
||||
}
|
||||
|
||||
DivInstrumentC64():
|
||||
triOn(false),
|
||||
sawOn(true),
|
||||
|
|
@ -369,6 +393,11 @@ struct DivInstrumentAmiga {
|
|||
unsigned char waveLen;
|
||||
SampleMap noteMap[120];
|
||||
|
||||
bool operator==(const DivInstrumentAmiga& other);
|
||||
bool operator!=(const DivInstrumentAmiga& other) {
|
||||
return !(*this==other);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the sample at specified note.
|
||||
* @return the sample.
|
||||
|
|
@ -424,6 +453,11 @@ struct DivInstrumentAmiga {
|
|||
struct DivInstrumentX1_010 {
|
||||
int bankSlot;
|
||||
|
||||
bool operator==(const DivInstrumentX1_010& other);
|
||||
bool operator!=(const DivInstrumentX1_010& other) {
|
||||
return !(*this==other);
|
||||
}
|
||||
|
||||
DivInstrumentX1_010():
|
||||
bankSlot(0) {}
|
||||
};
|
||||
|
|
@ -432,6 +466,11 @@ struct DivInstrumentN163 {
|
|||
int wave, wavePos, waveLen;
|
||||
unsigned char waveMode;
|
||||
|
||||
bool operator==(const DivInstrumentN163& other);
|
||||
bool operator!=(const DivInstrumentN163& other) {
|
||||
return !(*this==other);
|
||||
}
|
||||
|
||||
DivInstrumentN163():
|
||||
wave(-1),
|
||||
wavePos(0),
|
||||
|
|
@ -444,6 +483,12 @@ struct DivInstrumentFDS {
|
|||
int modSpeed, modDepth;
|
||||
// this is here for compatibility.
|
||||
bool initModTableWithFirstWave;
|
||||
|
||||
bool operator==(const DivInstrumentFDS& other);
|
||||
bool operator!=(const DivInstrumentFDS& other) {
|
||||
return !(*this==other);
|
||||
}
|
||||
|
||||
DivInstrumentFDS():
|
||||
modSpeed(0),
|
||||
modDepth(0),
|
||||
|
|
@ -456,6 +501,11 @@ struct DivInstrumentMultiPCM {
|
|||
unsigned char ar, d1r, dl, d2r, rr, rc;
|
||||
unsigned char lfo, vib, am;
|
||||
|
||||
bool operator==(const DivInstrumentMultiPCM& other);
|
||||
bool operator!=(const DivInstrumentMultiPCM& other) {
|
||||
return !(*this==other);
|
||||
}
|
||||
|
||||
DivInstrumentMultiPCM():
|
||||
ar(15), d1r(15), dl(0), d2r(0), rr(15), rc(15),
|
||||
lfo(0), vib(0), am(0) {
|
||||
|
|
@ -494,6 +544,12 @@ struct DivInstrumentWaveSynth {
|
|||
unsigned char effect;
|
||||
bool oneShot, enabled, global;
|
||||
unsigned char speed, param1, param2, param3, param4;
|
||||
|
||||
bool operator==(const DivInstrumentWaveSynth& other);
|
||||
bool operator!=(const DivInstrumentWaveSynth& other) {
|
||||
return !(*this==other);
|
||||
}
|
||||
|
||||
DivInstrumentWaveSynth():
|
||||
wave1(0),
|
||||
wave2(0),
|
||||
|
|
@ -511,6 +567,12 @@ struct DivInstrumentWaveSynth {
|
|||
|
||||
struct DivInstrumentSoundUnit {
|
||||
bool switchRoles;
|
||||
|
||||
bool operator==(const DivInstrumentSoundUnit& other);
|
||||
bool operator!=(const DivInstrumentSoundUnit& other) {
|
||||
return !(*this==other);
|
||||
}
|
||||
|
||||
DivInstrumentSoundUnit():
|
||||
switchRoles(false) {}
|
||||
};
|
||||
|
|
@ -546,6 +608,12 @@ struct DivInstrumentES5506 {
|
|||
};
|
||||
Filter filter;
|
||||
Envelope envelope;
|
||||
|
||||
bool operator==(const DivInstrumentES5506& other);
|
||||
bool operator!=(const DivInstrumentES5506& other) {
|
||||
return !(*this==other);
|
||||
}
|
||||
|
||||
DivInstrumentES5506():
|
||||
filter(Filter()),
|
||||
envelope(Envelope()) {}
|
||||
|
|
@ -563,6 +631,12 @@ struct DivInstrumentSNES {
|
|||
GainMode gainMode;
|
||||
unsigned char gain;
|
||||
unsigned char a, d, s, r;
|
||||
|
||||
bool operator==(const DivInstrumentSNES& other);
|
||||
bool operator!=(const DivInstrumentSNES& other) {
|
||||
return !(*this==other);
|
||||
}
|
||||
|
||||
DivInstrumentSNES():
|
||||
useEnv(true),
|
||||
sus(false),
|
||||
|
|
@ -576,7 +650,6 @@ struct DivInstrumentSNES {
|
|||
|
||||
struct DivInstrument {
|
||||
String name;
|
||||
bool mode;
|
||||
DivInstrumentType type;
|
||||
DivInstrumentFM fm;
|
||||
DivInstrumentSTD std;
|
||||
|
|
@ -591,6 +664,51 @@ struct DivInstrument {
|
|||
DivInstrumentSoundUnit su;
|
||||
DivInstrumentES5506 es5506;
|
||||
DivInstrumentSNES snes;
|
||||
|
||||
/**
|
||||
* these are internal functions.
|
||||
*/
|
||||
void writeMacro(SafeWriter* w, const DivInstrumentMacro& m, unsigned char macroCode);
|
||||
void writeFeatureNA(SafeWriter* w);
|
||||
void writeFeatureFM(SafeWriter* w, bool fui);
|
||||
void writeFeatureMA(SafeWriter* w);
|
||||
void writeFeature64(SafeWriter* w);
|
||||
void writeFeatureGB(SafeWriter* w);
|
||||
void writeFeatureSM(SafeWriter* w);
|
||||
void writeFeatureOx(SafeWriter* w, int op);
|
||||
void writeFeatureLD(SafeWriter* w);
|
||||
void writeFeatureSN(SafeWriter* w);
|
||||
void writeFeatureN1(SafeWriter* w);
|
||||
void writeFeatureFD(SafeWriter* w);
|
||||
void writeFeatureWS(SafeWriter* w);
|
||||
size_t writeFeatureSL(SafeWriter* w, std::vector<int>& list, const DivSong* song);
|
||||
size_t writeFeatureWL(SafeWriter* w, std::vector<int>& list, const DivSong* song);
|
||||
void writeFeatureMP(SafeWriter* w);
|
||||
void writeFeatureSU(SafeWriter* w);
|
||||
void writeFeatureES(SafeWriter* w);
|
||||
void writeFeatureX1(SafeWriter* w);
|
||||
|
||||
void readFeatureNA(SafeReader& reader);
|
||||
void readFeatureFM(SafeReader& reader);
|
||||
void readFeatureMA(SafeReader& reader);
|
||||
void readFeature64(SafeReader& reader);
|
||||
void readFeatureGB(SafeReader& reader);
|
||||
void readFeatureSM(SafeReader& reader);
|
||||
void readFeatureOx(SafeReader& reader, int op);
|
||||
void readFeatureLD(SafeReader& reader);
|
||||
void readFeatureSN(SafeReader& reader);
|
||||
void readFeatureN1(SafeReader& reader);
|
||||
void readFeatureFD(SafeReader& reader);
|
||||
void readFeatureWS(SafeReader& reader);
|
||||
void readFeatureSL(SafeReader& reader, DivSong* song, short version);
|
||||
void readFeatureWL(SafeReader& reader, DivSong* song, short version);
|
||||
void readFeatureMP(SafeReader& reader);
|
||||
void readFeatureSU(SafeReader& reader);
|
||||
void readFeatureES(SafeReader& reader);
|
||||
void readFeatureX1(SafeReader& reader);
|
||||
|
||||
DivDataErrors readInsDataOld(SafeReader& reader, short version);
|
||||
DivDataErrors readInsDataNew(SafeReader& reader, short version, bool fui, DivSong* song);
|
||||
|
||||
/**
|
||||
* save the instrument to a SafeWriter.
|
||||
|
|
@ -598,20 +716,28 @@ struct DivInstrument {
|
|||
*/
|
||||
void putInsData(SafeWriter* w);
|
||||
|
||||
/**
|
||||
* save the instrument to a SafeWriter using new format.
|
||||
* @param w the SafeWriter in question.
|
||||
*/
|
||||
void putInsData2(SafeWriter* w, bool fui=false, const DivSong* song=NULL);
|
||||
|
||||
/**
|
||||
* read instrument data in .fui format.
|
||||
* @param reader the reader.
|
||||
* @param version the format version.
|
||||
* @return a DivDataErrors.
|
||||
*/
|
||||
DivDataErrors readInsData(SafeReader& reader, short version);
|
||||
DivDataErrors readInsData(SafeReader& reader, short version, DivSong* song=NULL);
|
||||
|
||||
/**
|
||||
* save this instrument to a file.
|
||||
* @param path file path.
|
||||
* @param oldFormat whether to save in legacy Furnace ins format.
|
||||
* @param song if new format, a DivSong to read wavetables and samples.
|
||||
* @return whether it was successful.
|
||||
*/
|
||||
bool save(const char* path);
|
||||
bool save(const char* path, bool oldFormat=false, DivSong* song=NULL);
|
||||
|
||||
/**
|
||||
* save this instrument to a file in .dmp format.
|
||||
|
|
|
|||
|
|
@ -152,11 +152,20 @@ size_t DivDispatch::getSampleMemCapacity(int index) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
const char* DivDispatch::getSampleMemName(int index) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t DivDispatch::getSampleMemUsage(int index) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DivDispatch::renderSamples() {
|
||||
bool DivDispatch::isSampleLoaded(int index, int sample) {
|
||||
printf("you are calling.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
void DivDispatch::renderSamples(int sysID) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1191,13 +1191,25 @@ size_t DivPlatformES5506::getSampleMemUsage(int index) {
|
|||
return index == 0 ? sampleMemLen : 0;
|
||||
}
|
||||
|
||||
void DivPlatformES5506::renderSamples() {
|
||||
bool DivPlatformES5506::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
void DivPlatformES5506::renderSamples(int sysID) {
|
||||
memset(sampleMem,0,getSampleMemCapacity());
|
||||
memset(sampleOffES5506,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
|
||||
size_t memPos=128; // add silent at begin and end of each bank for reverse playback
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[0][sysID]) {
|
||||
sampleOffES5506[i]=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int length=s->length16;
|
||||
// fit sample size to single bank size
|
||||
if (length>(4194304-128)) {
|
||||
|
|
@ -1217,6 +1229,7 @@ void DivPlatformES5506::renderSamples() {
|
|||
memcpy(sampleMem+(memPos/sizeof(short)),s->data16,length);
|
||||
}
|
||||
sampleOffES5506[i]=memPos;
|
||||
sampleLoaded[i]=true;
|
||||
memPos+=length;
|
||||
}
|
||||
sampleMemLen=memPos+256;
|
||||
|
|
|
|||
|
|
@ -249,6 +249,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf {
|
|||
signed short* sampleMem; // ES5506 uses 16 bit data bus for samples
|
||||
size_t sampleMemLen;
|
||||
unsigned int sampleOffES5506[256];
|
||||
bool sampleLoaded[256];
|
||||
struct QueuedHostIntf {
|
||||
unsigned char state;
|
||||
unsigned char step;
|
||||
|
|
@ -335,7 +336,8 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf {
|
|||
virtual const void* getSampleMem(int index = 0) override;
|
||||
virtual size_t getSampleMemCapacity(int index = 0) override;
|
||||
virtual size_t getSampleMemUsage(int index = 0) override;
|
||||
virtual void renderSamples() override;
|
||||
virtual bool isSampleLoaded(int index, int sample) override;
|
||||
virtual void renderSamples(int sysID) override;
|
||||
virtual const char** getRegisterSheet() override;
|
||||
virtual int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) override;
|
||||
virtual void quit() override;
|
||||
|
|
|
|||
|
|
@ -362,8 +362,15 @@ size_t DivPlatformMSM6258::getSampleMemUsage(int index) {
|
|||
return index == 0 ? adpcmMemLen : 0;
|
||||
}
|
||||
|
||||
void DivPlatformMSM6258::renderSamples() {
|
||||
bool DivPlatformMSM6258::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
void DivPlatformMSM6258::renderSamples(int sysID) {
|
||||
memset(adpcmMem,0,getSampleMemCapacity(0));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
|
||||
// sample data
|
||||
size_t memPos=0;
|
||||
|
|
@ -371,6 +378,8 @@ void DivPlatformMSM6258::renderSamples() {
|
|||
if (sampleCount>128) sampleCount=128;
|
||||
for (int i=0; i<sampleCount; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[0][sysID]) continue;
|
||||
|
||||
int paddedLen=s->lengthVOX;
|
||||
if (memPos>=getSampleMemCapacity(0)) {
|
||||
logW("out of ADPCM memory for sample %d!",i);
|
||||
|
|
@ -381,6 +390,7 @@ void DivPlatformMSM6258::renderSamples() {
|
|||
logW("out of ADPCM memory for sample %d!",i);
|
||||
} else {
|
||||
memcpy(adpcmMem+memPos,s->dataVOX,paddedLen);
|
||||
sampleLoaded[i]=true;
|
||||
}
|
||||
memPos+=paddedLen;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ class DivPlatformMSM6258: public DivDispatch {
|
|||
|
||||
unsigned char* adpcmMem;
|
||||
size_t adpcmMemLen;
|
||||
bool sampleLoaded[256];
|
||||
unsigned char sampleBank, msmPan, msmDivider, rateSel, msmClock, clockSel;
|
||||
signed char msmDividerCount, msmClockCount;
|
||||
short msmOut;
|
||||
|
|
@ -113,7 +114,8 @@ class DivPlatformMSM6258: public DivDispatch {
|
|||
const void* getSampleMem(int index);
|
||||
size_t getSampleMemCapacity(int index);
|
||||
size_t getSampleMemUsage(int index);
|
||||
void renderSamples();
|
||||
bool isSampleLoaded(int index, int sample);
|
||||
void renderSamples(int chipID);
|
||||
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
|
|
|
|||
|
|
@ -335,11 +335,18 @@ size_t DivPlatformMSM6295::getSampleMemUsage(int index) {
|
|||
return index == 0 ? adpcmMemLen : 0;
|
||||
}
|
||||
|
||||
void DivPlatformMSM6295::renderSamples() {
|
||||
bool DivPlatformMSM6295::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
void DivPlatformMSM6295::renderSamples(int sysID) {
|
||||
unsigned int sampleOffVOX[256];
|
||||
|
||||
memset(adpcmMem,0,getSampleMemCapacity(0));
|
||||
memset(sampleOffVOX,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
|
||||
// sample data
|
||||
size_t memPos=128*8;
|
||||
|
|
@ -347,6 +354,11 @@ void DivPlatformMSM6295::renderSamples() {
|
|||
if (sampleCount>128) sampleCount=128;
|
||||
for (int i=0; i<sampleCount; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[0][sysID]) {
|
||||
sampleOffVOX[i]=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
int paddedLen=s->lengthVOX;
|
||||
if (memPos>=getSampleMemCapacity(0)) {
|
||||
logW("out of ADPCM memory for sample %d!",i);
|
||||
|
|
@ -357,6 +369,7 @@ void DivPlatformMSM6295::renderSamples() {
|
|||
logW("out of ADPCM memory for sample %d!",i);
|
||||
} else {
|
||||
memcpy(adpcmMem+memPos,s->dataVOX,paddedLen);
|
||||
sampleLoaded[i]=true;
|
||||
}
|
||||
sampleOffVOX[i]=memPos;
|
||||
memPos+=paddedLen;
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf {
|
|||
|
||||
unsigned char* adpcmMem;
|
||||
size_t adpcmMemLen;
|
||||
bool sampleLoaded[256];
|
||||
unsigned char sampleBank;
|
||||
|
||||
int delay, updateOsc;
|
||||
|
|
@ -101,7 +102,8 @@ class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf {
|
|||
virtual const void* getSampleMem(int index) override;
|
||||
virtual size_t getSampleMemCapacity(int index) override;
|
||||
virtual size_t getSampleMemUsage(int index) override;
|
||||
virtual void renderSamples() override;
|
||||
virtual bool isSampleLoaded(int index, int sample) override;
|
||||
virtual void renderSamples(int chipID) override;
|
||||
|
||||
virtual int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) override;
|
||||
virtual void quit() override;
|
||||
|
|
|
|||
|
|
@ -721,12 +721,24 @@ size_t DivPlatformNES::getSampleMemUsage(int index) {
|
|||
return index==0?dpcmMemLen:0;
|
||||
}
|
||||
|
||||
void DivPlatformNES::renderSamples() {
|
||||
memset(dpcmMem,0,getSampleMemCapacity(0));
|
||||
bool DivPlatformNES::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
void DivPlatformNES::renderSamples(int sysID) {
|
||||
memset(dpcmMem,0,getSampleMemCapacity(0));\
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
|
||||
size_t memPos=0;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[0][sysID]) {
|
||||
sampleOffDPCM[i]=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int paddedLen=(s->lengthDPCM+63)&(~0x3f);
|
||||
logV("%d padded length: %d",i,paddedLen);
|
||||
if ((memPos&(~0x3fff))!=((memPos+paddedLen)&(~0x3fff))) {
|
||||
|
|
@ -744,6 +756,7 @@ void DivPlatformNES::renderSamples() {
|
|||
logW("out of DPCM memory for sample %d!",i);
|
||||
} else {
|
||||
memcpy(dpcmMem+memPos,s->dataDPCM,MIN(s->lengthDPCM,paddedLen));
|
||||
sampleLoaded[i]=true;
|
||||
}
|
||||
sampleOffDPCM[i]=memPos;
|
||||
memPos+=paddedLen;
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ class DivPlatformNES: public DivDispatch {
|
|||
int dacSample;
|
||||
unsigned char* dpcmMem;
|
||||
size_t dpcmMemLen;
|
||||
bool sampleLoaded[256];
|
||||
unsigned char dpcmBank;
|
||||
unsigned char sampleBank;
|
||||
unsigned char writeOscBuf;
|
||||
|
|
@ -115,7 +116,8 @@ class DivPlatformNES: public DivDispatch {
|
|||
const void* getSampleMem(int index);
|
||||
size_t getSampleMemCapacity(int index);
|
||||
size_t getSampleMemUsage(int index);
|
||||
void renderSamples();
|
||||
bool isSampleLoaded(int index, int sample);
|
||||
void renderSamples(int chipID);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
~DivPlatformNES();
|
||||
|
|
|
|||
|
|
@ -1757,14 +1757,26 @@ size_t DivPlatformOPL::getSampleMemUsage(int index) {
|
|||
return (index==0 && adpcmChan>=0) ? adpcmBMemLen : 0;
|
||||
}
|
||||
|
||||
void DivPlatformOPL::renderSamples() {
|
||||
bool DivPlatformOPL::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
void DivPlatformOPL::renderSamples(int sysID) {
|
||||
if (adpcmChan<0) return;
|
||||
memset(adpcmBMem,0,getSampleMemCapacity(0));
|
||||
memset(sampleOffB,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
|
||||
size_t memPos=0;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[0][sysID]) {
|
||||
sampleOffB[i]=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
int paddedLen=(s->lengthB+255)&(~0xff);
|
||||
if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) {
|
||||
memPos=(memPos+0xfffff)&0xf00000;
|
||||
|
|
@ -1778,6 +1790,7 @@ void DivPlatformOPL::renderSamples() {
|
|||
logW("out of ADPCM memory for sample %d!",i);
|
||||
} else {
|
||||
memcpy(adpcmBMem+memPos,s->dataB,paddedLen);
|
||||
sampleLoaded[i]=true;
|
||||
}
|
||||
sampleOffB[i]=memPos;
|
||||
memPos+=paddedLen;
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ class DivPlatformOPL: public DivDispatch {
|
|||
size_t adpcmBMemLen;
|
||||
DivOPLAInterface iface;
|
||||
unsigned int sampleOffB[256];
|
||||
bool sampleLoaded[256];
|
||||
|
||||
ymfm::adpcm_b_engine* adpcmB;
|
||||
const unsigned char** slotsNonDrums;
|
||||
|
|
@ -152,7 +153,8 @@ class DivPlatformOPL: public DivDispatch {
|
|||
const void* getSampleMem(int index);
|
||||
size_t getSampleMemCapacity(int index);
|
||||
size_t getSampleMemUsage(int index);
|
||||
void renderSamples();
|
||||
bool isSampleLoaded(int index, int sample);
|
||||
void renderSamples(int chipID);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
~DivPlatformOPL();
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ void DivPlatformOPLL::tick(bool sysTick) {
|
|||
if (chan[i].freq>65535) chan[i].freq=65535;
|
||||
int freqt=toFreq(chan[i].freq);
|
||||
chan[i].freqL=freqt&0xff;
|
||||
if (i>=6 && properDrums) {
|
||||
if (i>=6 && properDrums && (i<9 || !noTopHatFreq)) {
|
||||
immWrite(0x10+drumSlot[i],freqt&0xff);
|
||||
immWrite(0x20+drumSlot[i],freqt>>8);
|
||||
} else if (i<6 || !drums) {
|
||||
|
|
@ -963,6 +963,7 @@ void DivPlatformOPLL::setFlags(const DivConfig& flags) {
|
|||
for (int i=0; i<11; i++) {
|
||||
oscBuf[i]->rate=rate/2;
|
||||
}
|
||||
noTopHatFreq=flags.getBool("noTopHatFreq",false);
|
||||
}
|
||||
|
||||
int DivPlatformOPLL::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ class DivPlatformOPLL: public DivDispatch {
|
|||
|
||||
bool useYMFM;
|
||||
bool drums;
|
||||
bool properDrums, properDrumsSys;
|
||||
bool properDrums, properDrumsSys, noTopHatFreq;
|
||||
bool vrc7;
|
||||
|
||||
unsigned char patchSet;
|
||||
|
|
|
|||
|
|
@ -252,6 +252,11 @@ void DivPlatformPCE::tick(bool sysTick) {
|
|||
chan[i].freqChanged=false;
|
||||
}
|
||||
}
|
||||
if (updateLFO) {
|
||||
rWrite(0x08,lfoSpeed);
|
||||
rWrite(0x09,lfoMode);
|
||||
updateLFO=false;
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformPCE::dispatch(DivCommand c) {
|
||||
|
|
@ -389,13 +394,11 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
} else {
|
||||
lfoMode=c.value;
|
||||
}
|
||||
rWrite(0x08,lfoSpeed);
|
||||
rWrite(0x09,lfoMode);
|
||||
updateLFO=true;
|
||||
break;
|
||||
case DIV_CMD_PCE_LFO_SPEED:
|
||||
lfoSpeed=255-c.value;
|
||||
rWrite(0x08,lfoSpeed);
|
||||
rWrite(0x09,lfoMode);
|
||||
updateLFO=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_PERIODIC(c.value2);
|
||||
|
|
@ -525,8 +528,7 @@ void DivPlatformPCE::reset() {
|
|||
rWrite(0,0);
|
||||
rWrite(0x01,0xff);
|
||||
// set LFO
|
||||
rWrite(0x08,lfoSpeed);
|
||||
rWrite(0x09,lfoMode);
|
||||
updateLFO=true;
|
||||
// set per-channel initial panning
|
||||
for (int i=0; i<6; i++) {
|
||||
chWrite(i,0x05,isMuted[i]?0:chan[i].pan);
|
||||
|
|
@ -588,6 +590,7 @@ int DivPlatformPCE::init(DivEngine* p, int channels, int sugRate, const DivConfi
|
|||
parent=p;
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
updateLFO=false;
|
||||
for (int i=0; i<6; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ class DivPlatformPCE: public DivDispatch {
|
|||
DivDispatchOscBuffer* oscBuf[6];
|
||||
bool isMuted[6];
|
||||
bool antiClickEnabled;
|
||||
bool updateLFO;
|
||||
struct QueuedWrite {
|
||||
unsigned char addr;
|
||||
unsigned char val;
|
||||
|
|
|
|||
|
|
@ -644,13 +644,25 @@ size_t DivPlatformQSound::getSampleMemUsage(int index) {
|
|||
return index == 0 ? sampleMemLen : 0;
|
||||
}
|
||||
|
||||
bool DivPlatformQSound::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
// TODO: ADPCM... come on...
|
||||
void DivPlatformQSound::renderSamples() {
|
||||
void DivPlatformQSound::renderSamples(int sysID) {
|
||||
memset(sampleMem,0,getSampleMemCapacity());
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
|
||||
size_t memPos=0;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[0][sysID]) {
|
||||
offPCM[i]=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
int length=s->length8;
|
||||
if (length>65536-16) {
|
||||
length=65536-16;
|
||||
|
|
@ -671,6 +683,7 @@ void DivPlatformQSound::renderSamples() {
|
|||
for (int i=0; i<length; i++) {
|
||||
sampleMem[(memPos+i)^0x8000]=s->data8[i];
|
||||
}
|
||||
sampleLoaded[i]=true;
|
||||
}
|
||||
offPCM[i]=memPos^0x8000;
|
||||
memPos+=length+16;
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ class DivPlatformQSound: public DivDispatch {
|
|||
|
||||
unsigned char* sampleMem;
|
||||
size_t sampleMemLen;
|
||||
bool sampleLoaded[256];
|
||||
struct qsound_chip chip;
|
||||
unsigned short regPool[512];
|
||||
|
||||
|
|
@ -103,7 +104,8 @@ class DivPlatformQSound: public DivDispatch {
|
|||
const void* getSampleMem(int index = 0);
|
||||
size_t getSampleMemCapacity(int index = 0);
|
||||
size_t getSampleMemUsage(int index = 0);
|
||||
void renderSamples();
|
||||
bool isSampleLoaded(int index, int sample);
|
||||
void renderSamples(int chipID);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -385,13 +385,25 @@ size_t DivPlatformRF5C68::getSampleMemUsage(int index) {
|
|||
return index == 0 ? sampleMemLen : 0;
|
||||
}
|
||||
|
||||
void DivPlatformRF5C68::renderSamples() {
|
||||
bool DivPlatformRF5C68::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
void DivPlatformRF5C68::renderSamples(int sysID) {
|
||||
memset(sampleMem,0,getSampleMemCapacity());
|
||||
memset(sampleOffRFC,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
|
||||
size_t memPos=0;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[0][sysID]) {
|
||||
sampleOffRFC[i]=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
int length=s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT);
|
||||
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)-31,length);
|
||||
if (actualLength>0) {
|
||||
|
|
@ -412,6 +424,7 @@ void DivPlatformRF5C68::renderSamples() {
|
|||
}
|
||||
// align memPos to 256-byte boundary
|
||||
memPos=(memPos+0xff)&~0xff;
|
||||
sampleLoaded[i]=true;
|
||||
}
|
||||
sampleMemLen=memPos;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ class DivPlatformRF5C68: public DivDispatch {
|
|||
int chipType;
|
||||
unsigned char curChan;
|
||||
unsigned int sampleOffRFC[256];
|
||||
bool sampleLoaded[256];
|
||||
|
||||
unsigned char* sampleMem;
|
||||
size_t sampleMemLen;
|
||||
|
|
@ -99,7 +100,8 @@ class DivPlatformRF5C68: public DivDispatch {
|
|||
const void* getSampleMem(int index = 0);
|
||||
size_t getSampleMemCapacity(int index = 0);
|
||||
size_t getSampleMemUsage(int index = 0);
|
||||
void renderSamples();
|
||||
bool isSampleLoaded(int index, int sample);
|
||||
void renderSamples(int chipID);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -71,10 +71,17 @@ void DivPlatformSAA1099::acquire_saaSound(short* bufL, short* bufR, size_t start
|
|||
writes.pop();
|
||||
}
|
||||
saa_saaSound->GenerateMany((unsigned char*)saaBuf[0],len,oscBuf);
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
for (size_t i=0; i<len; i++) {
|
||||
bufL[i+start]=(short)((((unsigned short)saaBuf[0][1+(i<<1)])<<8)|(((unsigned short)saaBuf[0][1+(i<<1)])>>8));
|
||||
bufR[i+start]=(short)((((unsigned short)saaBuf[0][i<<1])<<8)|(((unsigned short)saaBuf[0][i<<1])>>8));
|
||||
}
|
||||
#else
|
||||
for (size_t i=0; i<len; i++) {
|
||||
bufL[i+start]=saaBuf[0][i<<1];
|
||||
bufR[i+start]=saaBuf[0][1+(i<<1)];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void DivPlatformSAA1099::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
|
|
|
|||
|
|
@ -451,7 +451,7 @@ void DivPlatformSegaPCM::reset() {
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformSegaPCM::renderSamples() {
|
||||
void DivPlatformSegaPCM::renderSamples(int sysID) {
|
||||
size_t memPos=0;
|
||||
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ class DivPlatformSegaPCM: public DivDispatch {
|
|||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
void notifyInsChange(int ins);
|
||||
void renderSamples();
|
||||
void renderSamples(int chipID);
|
||||
void setFlags(const DivConfig& flags);
|
||||
bool isStereo();
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
|
|
|
|||
|
|
@ -119,10 +119,29 @@ void DivPlatformSMS::acquire(short* bufL, short* bufR, size_t start, size_t len)
|
|||
}
|
||||
}
|
||||
|
||||
double DivPlatformSMS::NOTE_SN(int ch, int note) {
|
||||
double CHIP_DIVIDER=toneDivider;
|
||||
if (ch==3) CHIP_DIVIDER=noiseDivider;
|
||||
if (parent->song.linearPitch==2 || !easyNoise) {
|
||||
return NOTE_PERIODIC(note);
|
||||
}
|
||||
if (note>easyThreshold) {
|
||||
return MAX(0,easyStartingPeriod-(note-easyThreshold));
|
||||
}
|
||||
return NOTE_PERIODIC(note);
|
||||
}
|
||||
|
||||
int DivPlatformSMS::snCalcFreq(int ch) {
|
||||
if (parent->song.linearPitch==2 && easyNoise && chan[ch].baseFreq+chan[ch].pitch+chan[ch].pitch2>(easyThreshold<<7)) {
|
||||
int ret=(((easyStartingPeriod<<7)+0x40)-(chan[ch].baseFreq+chan[ch].pitch+chan[ch].pitch2-(easyThreshold<<7)))>>7;
|
||||
if (ret<0) ret=0;
|
||||
return ret;
|
||||
}
|
||||
return parent->calcFreq(chan[ch].baseFreq,chan[ch].pitch,true,0,chan[ch].pitch2,chipClock,ch==3?noiseDivider:toneDivider);
|
||||
}
|
||||
|
||||
void DivPlatformSMS::tick(bool sysTick) {
|
||||
for (int i=0; i<4; i++) {
|
||||
double CHIP_DIVIDER=toneDivider;
|
||||
if (i==3) CHIP_DIVIDER=noiseDivider;
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=VOL_SCALE_LOG_BROKEN(chan[i].std.vol.val,chan[i].vol,15);
|
||||
|
|
@ -137,7 +156,7 @@ void DivPlatformSMS::tick(bool sysTick) {
|
|||
// 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].baseFreq=NOTE_SN(i,areYouSerious);
|
||||
chan[i].actualNote=areYouSerious;
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
|
|
@ -177,7 +196,7 @@ void DivPlatformSMS::tick(bool sysTick) {
|
|||
}
|
||||
for (int i=0; i<3; i++) {
|
||||
if (chan[i].freqChanged) {
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,toneDivider);
|
||||
chan[i].freq=snCalcFreq(i);
|
||||
if (chan[i].freq>1023) chan[i].freq=1023;
|
||||
if (parent->song.snNoLowPeriods) {
|
||||
if (chan[i].freq<8) chan[i].freq=1;
|
||||
|
|
@ -196,7 +215,8 @@ 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);
|
||||
chan[3].freq=snCalcFreq(3);
|
||||
//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 (parent->song.snNoLowPeriods) {
|
||||
if (chan[3].actualNote>0x5d) chan[3].freq=0x01;
|
||||
|
|
@ -244,12 +264,10 @@ void DivPlatformSMS::tick(bool sysTick) {
|
|||
}
|
||||
|
||||
int DivPlatformSMS::dispatch(DivCommand c) {
|
||||
double CHIP_DIVIDER=toneDivider;
|
||||
if (c.chan==3) CHIP_DIVIDER=noiseDivider;
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON:
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].baseFreq=NOTE_SN(c.chan,c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].actualNote=c.value;
|
||||
|
|
@ -300,7 +318,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
|
|||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_PERIODIC(c.value2);
|
||||
int destFreq=NOTE_SN(c.chan,c.value2);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -340,7 +358,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO:
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(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_SN(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;
|
||||
chan[c.chan].actualNote=c.value;
|
||||
|
|
@ -349,7 +367,7 @@ int DivPlatformSMS::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_STD));
|
||||
}
|
||||
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(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_SN(c.chan,chan[c.chan].note);
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
|
|
@ -446,27 +464,42 @@ void DivPlatformSMS::setFlags(const DivConfig& flags) {
|
|||
switch (flags.getInt("clockSel",0)) {
|
||||
case 1:
|
||||
chipClock=COLOR_PAL*4.0/5.0;
|
||||
easyThreshold=84;
|
||||
easyStartingPeriod=13;
|
||||
break;
|
||||
case 2:
|
||||
chipClock=4000000;
|
||||
easyThreshold=86;
|
||||
easyStartingPeriod=13;
|
||||
break;
|
||||
case 3:
|
||||
chipClock=COLOR_NTSC/2.0;
|
||||
easyThreshold=72;
|
||||
easyStartingPeriod=13;
|
||||
break;
|
||||
case 4:
|
||||
chipClock=3000000;
|
||||
easyThreshold=81;
|
||||
easyStartingPeriod=13;
|
||||
break;
|
||||
case 5:
|
||||
chipClock=2000000;
|
||||
easyThreshold=74;
|
||||
easyStartingPeriod=13;
|
||||
break;
|
||||
case 6:
|
||||
chipClock=COLOR_NTSC/8.0;
|
||||
easyThreshold=48;
|
||||
easyStartingPeriod=13;
|
||||
break;
|
||||
default:
|
||||
chipClock=COLOR_NTSC;
|
||||
easyThreshold=84;
|
||||
easyStartingPeriod=13;
|
||||
break;
|
||||
}
|
||||
resetPhase=!flags.getBool("noPhaseReset",false);
|
||||
easyNoise=!flags.getBool("noEasyNoise",false);
|
||||
divider=16;
|
||||
toneDivider=64.0;
|
||||
noiseDivider=64.0;
|
||||
|
|
|
|||
|
|
@ -65,11 +65,14 @@ class DivPlatformSMS: public DivDispatch {
|
|||
int divider=16;
|
||||
double toneDivider=64.0;
|
||||
double noiseDivider=64.0;
|
||||
int easyThreshold;
|
||||
int easyStartingPeriod;
|
||||
bool updateSNMode;
|
||||
bool resetPhase;
|
||||
bool isRealSN;
|
||||
bool stereo;
|
||||
bool nuked;
|
||||
bool easyNoise;
|
||||
sn76496_base_device* sn;
|
||||
ympsg_t sn_nuked;
|
||||
struct QueuedWrite {
|
||||
|
|
@ -82,6 +85,9 @@ class DivPlatformSMS: public DivDispatch {
|
|||
friend void putDispatchChip(void*,int);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
||||
double NOTE_SN(int ch, int note);
|
||||
int snCalcFreq(int ch);
|
||||
|
||||
void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len);
|
||||
void acquire_mame(short* bufL, short* bufR, size_t start, size_t len);
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -797,14 +797,26 @@ size_t DivPlatformSNES::getSampleMemUsage(int index) {
|
|||
return index == 0 ? sampleMemLen : 0;
|
||||
}
|
||||
|
||||
void DivPlatformSNES::renderSamples() {
|
||||
bool DivPlatformSNES::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
void DivPlatformSNES::renderSamples(int sysID) {
|
||||
memset(copyOfSampleMem,0,getSampleMemCapacity());
|
||||
memset(sampleOff,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
|
||||
// skip past sample table and wavetable buffer
|
||||
size_t memPos=sampleTableBase+8*4+8*9*16;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[0][sysID]) {
|
||||
sampleOff[i]=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
int length=s->lengthBRR;
|
||||
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)/9*9,length);
|
||||
if (actualLength>0) {
|
||||
|
|
@ -822,6 +834,7 @@ void DivPlatformSNES::renderSamples() {
|
|||
logW("out of BRR memory for sample %d!",i);
|
||||
break;
|
||||
}
|
||||
sampleLoaded[i]=true;
|
||||
}
|
||||
sampleMemLen=memPos;
|
||||
memcpy(sampleMem,copyOfSampleMem,65536);
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ class DivPlatformSNES: public DivDispatch {
|
|||
signed char copyOfSampleMem[65536];
|
||||
size_t sampleMemLen;
|
||||
unsigned int sampleOff[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned char regPool[0x80];
|
||||
SPC_DSP dsp;
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
|
@ -136,7 +137,8 @@ class DivPlatformSNES: public DivDispatch {
|
|||
const void* getSampleMem(int index = 0);
|
||||
size_t getSampleMemCapacity(int index = 0);
|
||||
size_t getSampleMemUsage(int index = 0);
|
||||
void renderSamples();
|
||||
bool isSampleLoaded(int index, int sample);
|
||||
void renderSamples(int chipID);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -391,7 +391,18 @@ void SoundUnit::Reset() {
|
|||
memset(chan,0,sizeof(SUChannel)*8);
|
||||
}
|
||||
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
const unsigned char suBERemap[32]={
|
||||
0x01, 0x00, 0x02, 0x03, 0x05, 0x04, 0x07, 0x06, 0x08, 0x09, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e,
|
||||
0x11, 0x10, 0x12, 0x13, 0x15, 0x14, 0x16, 0x17, 0x19, 0x18, 0x1a, 0x1b, 0x1c, 0x1d, 0x1f, 0x1e
|
||||
};
|
||||
#endif
|
||||
|
||||
void SoundUnit::Write(unsigned char addr, unsigned char data) {
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
// remap
|
||||
addr=(addr&0xe0)|(suBERemap[addr&0x1f]);
|
||||
#endif
|
||||
((unsigned char*)chan)[addr]=data;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -286,6 +286,8 @@ int ymz280b_device::generate_pcm8(struct YMZ280BVoice *voice, s16 *buffer, int s
|
|||
|
||||
***********************************************************************************************/
|
||||
|
||||
// according to this core, it should be little-endian.
|
||||
// but it's big-endian in VGMPlay...
|
||||
int ymz280b_device::generate_pcm16(struct YMZ280BVoice *voice, s16 *buffer, int samples)
|
||||
{
|
||||
u32 position = voice->position;
|
||||
|
|
@ -298,7 +300,7 @@ int ymz280b_device::generate_pcm16(struct YMZ280BVoice *voice, s16 *buffer, int
|
|||
while (samples)
|
||||
{
|
||||
/* fetch the current value */
|
||||
val = (s16)((m_ext_mem[position / 2 + 1] << 8) + m_ext_mem[position / 2 + 0]);
|
||||
val = (s16)((m_ext_mem[position / 2 + 0] << 8) + m_ext_mem[position / 2 + 1]);
|
||||
|
||||
/* output to the buffer, scaling by the volume */
|
||||
*buffer++ = val;
|
||||
|
|
@ -321,7 +323,7 @@ int ymz280b_device::generate_pcm16(struct YMZ280BVoice *voice, s16 *buffer, int
|
|||
while (samples)
|
||||
{
|
||||
/* fetch the current value */
|
||||
val = (s16)((m_ext_mem[position / 2 + 1] << 8) + m_ext_mem[position / 2 + 0]);
|
||||
val = (s16)((m_ext_mem[position / 2 + 0] << 8) + m_ext_mem[position / 2 + 1]);
|
||||
|
||||
/* output to the buffer, scaling by the volume */
|
||||
*buffer++ = val;
|
||||
|
|
|
|||
|
|
@ -524,7 +524,7 @@ void DivPlatformSoundUnit::setFlags(const DivConfig& flags) {
|
|||
sampleMemSize=flags.getInt("sampleMemSize",0);
|
||||
|
||||
su->Init(sampleMemSize?65536:8192,flags.getBool("pdm",false));
|
||||
renderSamples();
|
||||
renderSamples(sysIDCache);
|
||||
}
|
||||
|
||||
void DivPlatformSoundUnit::poke(unsigned int addr, unsigned short val) {
|
||||
|
|
@ -547,14 +547,26 @@ size_t DivPlatformSoundUnit::getSampleMemUsage(int index) {
|
|||
return (index==0)?sampleMemLen:0;
|
||||
}
|
||||
|
||||
void DivPlatformSoundUnit::renderSamples() {
|
||||
bool DivPlatformSoundUnit::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
void DivPlatformSoundUnit::renderSamples(int sysID) {
|
||||
memset(su->pcm,0,getSampleMemCapacity(0));
|
||||
memset(sampleOffSU,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
|
||||
size_t memPos=0;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (s->data8==NULL) continue;
|
||||
if (!s->renderOn[0][sysID]) {
|
||||
sampleOffSU[i]=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
int paddedLen=s->length8;
|
||||
if (memPos>=getSampleMemCapacity(0)) {
|
||||
logW("out of PCM memory for sample %d!",i);
|
||||
|
|
@ -565,12 +577,13 @@ void DivPlatformSoundUnit::renderSamples() {
|
|||
logW("out of PCM memory for sample %d!",i);
|
||||
} else {
|
||||
memcpy(su->pcm+memPos,s->data8,paddedLen);
|
||||
sampleLoaded[i]=true;
|
||||
}
|
||||
sampleOffSU[i]=memPos;
|
||||
memPos+=paddedLen;
|
||||
}
|
||||
sampleMemLen=memPos;
|
||||
|
||||
sysIDCache=sysID;
|
||||
}
|
||||
|
||||
int DivPlatformSoundUnit::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
||||
|
|
@ -582,6 +595,7 @@ int DivPlatformSoundUnit::init(DivEngine* p, int channels, int sugRate, const Di
|
|||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
}
|
||||
su=new SoundUnit();
|
||||
sysIDCache=0;
|
||||
setFlags(flags);
|
||||
reset();
|
||||
return 8;
|
||||
|
|
|
|||
|
|
@ -102,8 +102,9 @@ class DivPlatformSoundUnit: public DivDispatch {
|
|||
unsigned char initIlCtrl, initIlSize, initFil1;
|
||||
signed char echoVol, initEchoVol;
|
||||
unsigned int sampleOffSU[256];
|
||||
bool sampleLoaded[256];
|
||||
|
||||
int cycles, curChan, delay;
|
||||
int cycles, curChan, delay, sysIDCache;
|
||||
short tempL;
|
||||
short tempR;
|
||||
unsigned char sampleBank, lfoMode, lfoSpeed;
|
||||
|
|
@ -138,7 +139,8 @@ class DivPlatformSoundUnit: public DivDispatch {
|
|||
const void* getSampleMem(int index);
|
||||
size_t getSampleMemCapacity(int index);
|
||||
size_t getSampleMemUsage(int index);
|
||||
void renderSamples();
|
||||
bool isSampleLoaded(int index, int sample);
|
||||
void renderSamples(int chipID);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
~DivPlatformSoundUnit();
|
||||
|
|
|
|||
|
|
@ -81,10 +81,29 @@ void DivPlatformT6W28::writeOutVol(int ch) {
|
|||
}
|
||||
}
|
||||
|
||||
double DivPlatformT6W28::NOTE_SN(int ch, int note) {
|
||||
double CHIP_DIVIDER=16;
|
||||
if (ch==3) CHIP_DIVIDER=15;
|
||||
if (parent->song.linearPitch==2 || !easyNoise) {
|
||||
return NOTE_PERIODIC(note);
|
||||
}
|
||||
if (note>107) {
|
||||
return MAX(0,13-(note-107));
|
||||
}
|
||||
return NOTE_PERIODIC(note);
|
||||
}
|
||||
|
||||
int DivPlatformT6W28::snCalcFreq(int ch) {
|
||||
if (parent->song.linearPitch==2 && easyNoise && chan[ch].baseFreq+chan[ch].pitch+chan[ch].pitch2>(107<<7)) {
|
||||
int ret=(((13<<7)+0x40)-(chan[ch].baseFreq+chan[ch].pitch+chan[ch].pitch2-(107<<7)))>>7;
|
||||
if (ret<0) ret=0;
|
||||
return ret;
|
||||
}
|
||||
return parent->calcFreq(chan[ch].baseFreq,chan[ch].pitch,true,0,chan[ch].pitch2,chipClock,ch==3?15:16);
|
||||
}
|
||||
|
||||
void DivPlatformT6W28::tick(bool sysTick) {
|
||||
for (int i=0; i<4; i++) {
|
||||
double CHIP_DIVIDER=16;
|
||||
if (i==3) CHIP_DIVIDER=15;
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=VOL_SCALE_LOG_BROKEN(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15);
|
||||
|
|
@ -92,7 +111,7 @@ void DivPlatformT6W28::tick(bool sysTick) {
|
|||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
int noiseSeek=parent->calcArp(chan[i].note,chan[i].std.arp.val);
|
||||
chan[i].baseFreq=NOTE_PERIODIC(noiseSeek);
|
||||
chan[i].baseFreq=NOTE_SN(i,noiseSeek);
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
|
|
@ -124,7 +143,7 @@ void DivPlatformT6W28::tick(bool sysTick) {
|
|||
rWrite(1,0xe0+chan[i].duty);
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER);
|
||||
chan[i].freq=snCalcFreq(i);
|
||||
if (chan[i].freq>1023) chan[i].freq=1023;
|
||||
if (i==3) {
|
||||
rWrite(1,0x80|(2<<5)|(chan[3].freq&15));
|
||||
|
|
@ -141,13 +160,11 @@ void DivPlatformT6W28::tick(bool sysTick) {
|
|||
}
|
||||
|
||||
int DivPlatformT6W28::dispatch(DivCommand c) {
|
||||
double CHIP_DIVIDER=16;
|
||||
if (c.chan==3) CHIP_DIVIDER=15;
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_PCE);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].baseFreq=NOTE_SN(c.chan,c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
}
|
||||
|
|
@ -197,7 +214,7 @@ int DivPlatformT6W28::dispatch(DivCommand c) {
|
|||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_PERIODIC(c.value2);
|
||||
int destFreq=NOTE_SN(c.chan,c.value2);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -231,15 +248,15 @@ int DivPlatformT6W28::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO:
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(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_SN(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;
|
||||
case DIV_CMD_PRE_PORTA:
|
||||
if (chan[c.chan].active && c.value2) {
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_T6W28));
|
||||
}
|
||||
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(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_SN(c.chan,chan[c.chan].note);
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
|
|
@ -330,6 +347,7 @@ void DivPlatformT6W28::setFlags(const DivConfig& flags) {
|
|||
for (int i=0; i<4; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
easyNoise=!flags.getBool("noEasyNoise",false);
|
||||
|
||||
if (t6w!=NULL) {
|
||||
delete t6w;
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ class DivPlatformT6W28: public DivDispatch {
|
|||
DivDispatchOscBuffer* oscBuf[4];
|
||||
bool isMuted[4];
|
||||
bool antiClickEnabled;
|
||||
bool easyNoise;
|
||||
struct QueuedWrite {
|
||||
unsigned char addr;
|
||||
unsigned char val;
|
||||
|
|
@ -75,6 +76,10 @@ class DivPlatformT6W28: public DivDispatch {
|
|||
unsigned char regPool[128];
|
||||
friend void putDispatchChip(void*,int);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
||||
double NOTE_SN(int ch, int note);
|
||||
int snCalcFreq(int ch);
|
||||
|
||||
void writeOutVol(int ch);
|
||||
public:
|
||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
|
|
|
|||
|
|
@ -949,13 +949,25 @@ size_t DivPlatformX1_010::getSampleMemUsage(int index) {
|
|||
return index >= 0 ? sampleMemLen : 0;
|
||||
}
|
||||
|
||||
void DivPlatformX1_010::renderSamples() {
|
||||
bool DivPlatformX1_010::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
void DivPlatformX1_010::renderSamples(int sysID) {
|
||||
memset(sampleMem,0,getSampleMemCapacity());
|
||||
memset(sampleOffX1,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
|
||||
size_t memPos=0;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[0][sysID]) {
|
||||
sampleOffX1[i]=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
int paddedLen=(s->length8+4095)&(~0xfff);
|
||||
if (isBanked) {
|
||||
// fit sample bank size to 128KB for Seta 2 external bankswitching logic (not emulated yet!)
|
||||
|
|
@ -975,6 +987,7 @@ void DivPlatformX1_010::renderSamples() {
|
|||
logW("out of X1-010 memory for sample %d!",i);
|
||||
} else {
|
||||
memcpy(sampleMem+memPos,s->data8,paddedLen);
|
||||
sampleLoaded[i]=true;
|
||||
}
|
||||
sampleOffX1[i]=memPos;
|
||||
memPos+=paddedLen;
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf {
|
|||
bool isBanked=false;
|
||||
unsigned int bankSlot[8];
|
||||
unsigned int sampleOffX1[256];
|
||||
bool sampleLoaded[256];
|
||||
|
||||
unsigned char regPool[0x2000];
|
||||
double NoteX1_010(int ch, int note);
|
||||
|
|
@ -146,7 +147,8 @@ class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf {
|
|||
const void* getSampleMem(int index = 0);
|
||||
size_t getSampleMemCapacity(int index = 0);
|
||||
size_t getSampleMemUsage(int index = 0);
|
||||
void renderSamples();
|
||||
bool isSampleLoaded(int index, int sample);
|
||||
void renderSamples(int chipID);
|
||||
const char** getRegisterSheet();
|
||||
void setBanked(bool banked);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
|
|
|
|||
|
|
@ -1336,13 +1336,25 @@ size_t DivPlatformYM2608::getSampleMemUsage(int index) {
|
|||
return index == 0 ? adpcmBMemLen : 0;
|
||||
}
|
||||
|
||||
void DivPlatformYM2608::renderSamples() {
|
||||
bool DivPlatformYM2608::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
void DivPlatformYM2608::renderSamples(int sysID) {
|
||||
memset(adpcmBMem,0,getSampleMemCapacity(0));
|
||||
memset(sampleOffB,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
|
||||
size_t memPos=0;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[0][sysID]) {
|
||||
sampleOffB[i]=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
int paddedLen=(s->lengthB+255)&(~0xff);
|
||||
if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) {
|
||||
memPos=(memPos+0xfffff)&0xf00000;
|
||||
|
|
@ -1356,6 +1368,7 @@ void DivPlatformYM2608::renderSamples() {
|
|||
logW("out of ADPCM memory for sample %d!",i);
|
||||
} else {
|
||||
memcpy(adpcmBMem+memPos,s->dataB,paddedLen);
|
||||
sampleLoaded[i]=true;
|
||||
}
|
||||
sampleOffB[i]=memPos;
|
||||
memPos+=paddedLen;
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ class DivPlatformYM2608: public DivPlatformOPN {
|
|||
size_t adpcmBMemLen;
|
||||
DivYM2608Interface iface;
|
||||
unsigned int sampleOffB[256];
|
||||
bool sampleLoaded[256];
|
||||
|
||||
DivPlatformAY8910* ay;
|
||||
unsigned char sampleBank;
|
||||
|
|
@ -137,7 +138,8 @@ class DivPlatformYM2608: public DivPlatformOPN {
|
|||
const void* getSampleMem(int index);
|
||||
size_t getSampleMemCapacity(int index);
|
||||
size_t getSampleMemUsage(int index);
|
||||
void renderSamples();
|
||||
bool isSampleLoaded(int index, int sample);
|
||||
void renderSamples(int chipID);
|
||||
void setFlags(const DivConfig& flags);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
|
|
|
|||
|
|
@ -142,6 +142,8 @@ template<int ChanNum> class DivPlatformYM2610Base: public DivPlatformOPN {
|
|||
unsigned char sampleBank;
|
||||
|
||||
bool extMode, noExtMacros;
|
||||
|
||||
bool sampleLoaded[2][256];
|
||||
|
||||
unsigned char writeADPCMAOff, writeADPCMAOn;
|
||||
int globalADPCMAVolume;
|
||||
|
|
@ -204,18 +206,34 @@ template<int ChanNum> class DivPlatformYM2610Base: public DivPlatformOPN {
|
|||
return index == 0 ? 16777216 : index == 1 ? 16777216 : 0;
|
||||
}
|
||||
|
||||
const char* getSampleMemName(int index=0) {
|
||||
return index == 0 ? "ADPCM-A" : index == 1 ? "ADPCM-B" : NULL;
|
||||
}
|
||||
|
||||
size_t getSampleMemUsage(int index) {
|
||||
return index == 0 ? adpcmAMemLen : index == 1 ? adpcmBMemLen : 0;
|
||||
}
|
||||
|
||||
void renderSamples() {
|
||||
bool isSampleLoaded(int index, int sample) {
|
||||
if (index<0 || index>1) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
return sampleLoaded[index][sample];
|
||||
}
|
||||
|
||||
void renderSamples(int sysID) {
|
||||
memset(adpcmAMem,0,getSampleMemCapacity(0));
|
||||
memset(sampleOffA,0,256*sizeof(unsigned int));
|
||||
memset(sampleOffB,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*2*sizeof(bool));
|
||||
|
||||
size_t memPos=0;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[0][sysID]) {
|
||||
sampleOffA[i]=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
int paddedLen=(s->lengthA+255)&(~0xff);
|
||||
if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) {
|
||||
memPos=(memPos+0xfffff)&0xf00000;
|
||||
|
|
@ -229,6 +247,7 @@ template<int ChanNum> class DivPlatformYM2610Base: public DivPlatformOPN {
|
|||
logW("out of ADPCM-A memory for sample %d!",i);
|
||||
} else {
|
||||
memcpy(adpcmAMem+memPos,s->dataA,paddedLen);
|
||||
sampleLoaded[0][i]=true;
|
||||
}
|
||||
sampleOffA[i]=memPos;
|
||||
memPos+=paddedLen;
|
||||
|
|
@ -240,6 +259,11 @@ template<int ChanNum> class DivPlatformYM2610Base: public DivPlatformOPN {
|
|||
memPos=0;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[1][sysID]) {
|
||||
sampleOffB[i]=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
int paddedLen=(s->lengthB+255)&(~0xff);
|
||||
if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) {
|
||||
memPos=(memPos+0xfffff)&0xf00000;
|
||||
|
|
@ -253,6 +277,7 @@ template<int ChanNum> class DivPlatformYM2610Base: public DivPlatformOPN {
|
|||
logW("out of ADPCM-B memory for sample %d!",i);
|
||||
} else {
|
||||
memcpy(adpcmBMem+memPos,s->dataB,paddedLen);
|
||||
sampleLoaded[1][i]=true;
|
||||
}
|
||||
sampleOffB[i]=memPos;
|
||||
memPos+=paddedLen;
|
||||
|
|
|
|||
|
|
@ -420,18 +420,40 @@ size_t DivPlatformYMZ280B::getSampleMemUsage(int index) {
|
|||
return index == 0 ? sampleMemLen : 0;
|
||||
}
|
||||
|
||||
void DivPlatformYMZ280B::renderSamples() {
|
||||
bool DivPlatformYMZ280B::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
void DivPlatformYMZ280B::renderSamples(int sysID) {
|
||||
memset(sampleMem,0,getSampleMemCapacity());
|
||||
memset(sampleOff,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
|
||||
size_t memPos=0;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[0][sysID]) {
|
||||
sampleOff[i]=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
int length=s->getCurBufLen();
|
||||
unsigned char* src=(unsigned char*)s->getCurBuf();
|
||||
int actualLength=MIN((int)(getSampleMemCapacity()-memPos),length);
|
||||
if (actualLength>0) {
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
memcpy(&sampleMem[memPos],src,actualLength);
|
||||
#else
|
||||
if (s->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
for (int i=0; i<actualLength; i++) {
|
||||
sampleMem[memPos+i]=src[i^1];
|
||||
}
|
||||
} else {
|
||||
memcpy(&sampleMem[memPos],src,actualLength);
|
||||
}
|
||||
#endif
|
||||
sampleOff[i]=memPos;
|
||||
memPos+=length;
|
||||
}
|
||||
|
|
@ -439,6 +461,7 @@ void DivPlatformYMZ280B::renderSamples() {
|
|||
logW("out of YMZ280B PCM memory for sample %d!",i);
|
||||
break;
|
||||
}
|
||||
sampleLoaded[i]=true;
|
||||
}
|
||||
sampleMemLen=memPos;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ class DivPlatformYMZ280B: public DivDispatch {
|
|||
bool isMuted[8];
|
||||
int chipType;
|
||||
unsigned int sampleOff[256];
|
||||
bool sampleLoaded[256];
|
||||
|
||||
unsigned char* sampleMem;
|
||||
size_t sampleMemLen;
|
||||
|
|
@ -99,7 +100,8 @@ class DivPlatformYMZ280B: public DivDispatch {
|
|||
const void* getSampleMem(int index = 0);
|
||||
size_t getSampleMemCapacity(int index = 0);
|
||||
size_t getSampleMemUsage(int index = 0);
|
||||
void renderSamples();
|
||||
bool isSampleLoaded(int index, int sample);
|
||||
void renderSamples(int chipID);
|
||||
void setFlags(const DivConfig& flags);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
|
|
|
|||
|
|
@ -39,6 +39,186 @@ DivSampleHistory::~DivSampleHistory() {
|
|||
if (data!=NULL) delete[] data;
|
||||
}
|
||||
|
||||
void DivSample::putSampleData(SafeWriter* w) {
|
||||
size_t blockStartSeek, blockEndSeek;
|
||||
|
||||
w->write("SMP2",4);
|
||||
blockStartSeek=w->tell();
|
||||
w->writeI(0);
|
||||
|
||||
w->writeString(name,false);
|
||||
w->writeI(samples);
|
||||
w->writeI(rate);
|
||||
w->writeI(centerRate);
|
||||
w->writeC(depth);
|
||||
w->writeC(loopMode);
|
||||
w->writeC(0); // reserved
|
||||
w->writeC(0);
|
||||
w->writeI(loop?loopStart:-1);
|
||||
w->writeI(loop?loopEnd:-1);
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
w->writeI(0xffffffff);
|
||||
}
|
||||
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
// store 16-bit samples as little-endian
|
||||
if (depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
unsigned char* sampleBuf=(unsigned char*)getCurBuf();
|
||||
size_t bufLen=getCurBufLen();
|
||||
for (size_t i=0; i<bufLen; i+=2) {
|
||||
w->writeC(sampleBuf[i+1]);
|
||||
w->writeC(sampleBuf[i]);
|
||||
}
|
||||
} else {
|
||||
w->write(getCurBuf(),getCurBufLen());
|
||||
}
|
||||
#else
|
||||
w->write(getCurBuf(),getCurBufLen());
|
||||
#endif
|
||||
|
||||
blockEndSeek=w->tell();
|
||||
w->seek(blockStartSeek,SEEK_SET);
|
||||
w->writeI(blockEndSeek-blockStartSeek-4);
|
||||
w->seek(0,SEEK_END);
|
||||
}
|
||||
|
||||
// Delek why
|
||||
static double samplePitchesSD[11]={
|
||||
0.1666666666, 0.2, 0.25, 0.333333333, 0.5,
|
||||
1,
|
||||
2, 3, 4, 5, 6
|
||||
};
|
||||
|
||||
DivDataErrors DivSample::readSampleData(SafeReader& reader, short version) {
|
||||
int vol=0;
|
||||
int pitch=0;
|
||||
char magic[4];
|
||||
|
||||
reader.read(magic,4);
|
||||
if (memcmp(magic,"SMPL",4)!=0 && memcmp(magic,"SMP2",4)!=0) {
|
||||
logV("header is invalid: %c%c%c%c",magic[0],magic[1],magic[2],magic[3]);
|
||||
return DIV_DATA_INVALID_HEADER;
|
||||
}
|
||||
bool isNewSample=(memcmp(magic,"SMP2",4)==0);
|
||||
reader.readI();
|
||||
if (!isNewSample) logV("(old sample)");
|
||||
|
||||
name=reader.readString();
|
||||
samples=reader.readI();
|
||||
if (!isNewSample) {
|
||||
loopEnd=samples;
|
||||
}
|
||||
rate=reader.readI();
|
||||
|
||||
if (isNewSample) {
|
||||
centerRate=reader.readI();
|
||||
depth=(DivSampleDepth)reader.readC();
|
||||
if (version>=123) {
|
||||
loopMode=(DivSampleLoopMode)reader.readC();
|
||||
} else {
|
||||
loopMode=DIV_SAMPLE_LOOP_FORWARD;
|
||||
reader.readC();
|
||||
}
|
||||
|
||||
// reserved
|
||||
reader.readC();
|
||||
reader.readC();
|
||||
|
||||
loopStart=reader.readI();
|
||||
loopEnd=reader.readI();
|
||||
loop=(loopStart>=0)&&(loopEnd>=0);
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
reader.readI();
|
||||
}
|
||||
} else {
|
||||
if (version<58) {
|
||||
vol=reader.readS();
|
||||
pitch=reader.readS();
|
||||
} else {
|
||||
reader.readI();
|
||||
}
|
||||
depth=(DivSampleDepth)reader.readC();
|
||||
|
||||
// reserved
|
||||
reader.readC();
|
||||
|
||||
// while version 32 stored this value, it was unused.
|
||||
if (version>=38) {
|
||||
centerRate=(unsigned short)reader.readS();
|
||||
} else {
|
||||
reader.readS();
|
||||
}
|
||||
|
||||
if (version>=19) {
|
||||
loopStart=reader.readI();
|
||||
loop=(loopStart>=0)&&(loopEnd>=0);
|
||||
} else {
|
||||
reader.readI();
|
||||
}
|
||||
}
|
||||
|
||||
if (version>=58) { // modern sample
|
||||
init(samples);
|
||||
reader.read(getCurBuf(),getCurBufLen());
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
// convert 16-bit samples to big-endian
|
||||
if (depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
unsigned char* sampleBuf=(unsigned char*)getCurBuf();
|
||||
size_t sampleBufLen=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=samples;
|
||||
short* data=new short[length];
|
||||
reader.read(data,2*length);
|
||||
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
// convert 16-bit samples to big-endian
|
||||
for (int pos=0; pos<length; pos++) {
|
||||
data[pos]=((unsigned short)data[pos]>>8)|((unsigned short)data[pos]<<8);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pitch!=5) {
|
||||
logD("scaling from %d...",pitch);
|
||||
}
|
||||
|
||||
// render data
|
||||
if (depth!=DIV_SAMPLE_DEPTH_8BIT && depth!=DIV_SAMPLE_DEPTH_16BIT) {
|
||||
logW("sample depth is wrong! (%d)",depth);
|
||||
depth=DIV_SAMPLE_DEPTH_16BIT;
|
||||
}
|
||||
samples=(double)samples/samplePitchesSD[pitch];
|
||||
init(samples);
|
||||
|
||||
unsigned int k=0;
|
||||
float mult=(float)(vol)/50.0f;
|
||||
for (double j=0; j<length; j+=samplePitchesSD[pitch]) {
|
||||
if (k>=samples) {
|
||||
break;
|
||||
}
|
||||
if (depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
float next=(float)(data[(unsigned int)j]-0x80)*mult;
|
||||
data8[k++]=fmin(fmax(next,-128),127);
|
||||
} else {
|
||||
float next=(float)data[(unsigned int)j]*mult;
|
||||
data16[k++]=fmin(fmax(next,-32768),32767);
|
||||
}
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
return DIV_DATA_SUCCESS;
|
||||
}
|
||||
|
||||
bool DivSample::isLoopable() {
|
||||
return loop && ((loopStart>=0 && loopStart<loopEnd) && (loopEnd>loopStart && loopEnd<=(int)samples));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
#define _SAMPLE_H
|
||||
|
||||
#include "../ta-utils.h"
|
||||
#include "safeWriter.h"
|
||||
#include "dataErrors.h"
|
||||
#include <deque>
|
||||
|
||||
enum DivSampleLoopMode: unsigned char {
|
||||
|
|
@ -112,6 +114,8 @@ struct DivSample {
|
|||
// - 2: Pingpong loop
|
||||
DivSampleLoopMode loopMode;
|
||||
|
||||
bool renderOn[4][32];
|
||||
|
||||
// these are the new data structures.
|
||||
signed char* data8; // 8
|
||||
short* data16; // 16
|
||||
|
|
@ -131,6 +135,20 @@ struct DivSample {
|
|||
std::deque<DivSampleHistory*> undoHist;
|
||||
std::deque<DivSampleHistory*> redoHist;
|
||||
|
||||
/**
|
||||
* put sample data.
|
||||
* @param w a SafeWriter.
|
||||
*/
|
||||
void putSampleData(SafeWriter* w);
|
||||
|
||||
/**
|
||||
* read sample data.
|
||||
* @param reader the reader.
|
||||
* @param version the format version.
|
||||
* @return a DivDataErrors.
|
||||
*/
|
||||
DivDataErrors readSampleData(SafeReader& reader, short version);
|
||||
|
||||
/**
|
||||
* check if sample is loopable.
|
||||
* @return whether it is loopable.
|
||||
|
|
@ -310,7 +328,14 @@ struct DivSample {
|
|||
lengthB(0),
|
||||
lengthBRR(0),
|
||||
lengthVOX(0),
|
||||
samples(0) {}
|
||||
samples(0) {
|
||||
for (int i=0; i<32; i++) {
|
||||
renderOn[0][i]=true;
|
||||
renderOn[1][i]=true;
|
||||
renderOn[2][i]=true;
|
||||
renderOn[3][i]=true;
|
||||
}
|
||||
}
|
||||
~DivSample();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1711,8 +1711,7 @@ void DivEngine::registerSystems() {
|
|||
);
|
||||
|
||||
sysDefs[DIV_SYSTEM_T6W28]=new DivSysDef(
|
||||
// 0x0a = wild guess. it may as well be 0x83
|
||||
"T6W28", NULL, 0xbf, 0x0a, 4, false, true, 0x160, false, 0,
|
||||
"T6W28", NULL, 0xbf, 0, 4, false, true, 0x160, false, 0,
|
||||
"an SN76489 derivative used in Neo Geo Pocket, has independent stereo volume and noise channel frequency.",
|
||||
{"Square 1", "Square 2", "Square 3", "Noise"},
|
||||
{"S1", "S2", "S3", "NO"},
|
||||
|
|
|
|||
|
|
@ -1800,21 +1800,6 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
size_t sampleMemLen=writeZ280[i]->getSampleMemUsage();
|
||||
unsigned char* sampleMem=new unsigned char[sampleMemLen];
|
||||
memcpy(sampleMem,writeZ280[i]->getSampleMem(),sampleMemLen);
|
||||
// TODO: please fix this later
|
||||
/*
|
||||
for (int i=0; i<song.sampleLen; i++) {
|
||||
DivSample* s=song.sample[i];
|
||||
if (s->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||
unsigned int pos=s->offYMZ280B;
|
||||
for (unsigned int j=0; j<s->samples; j++) {
|
||||
unsigned char lo=sampleMem[pos+j*2];
|
||||
unsigned char hi=sampleMem[pos+j*2+1];
|
||||
sampleMem[pos+j*2]=hi;
|
||||
sampleMem[pos+j*2+1]=lo;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
w->writeC(0x67);
|
||||
w->writeC(0x66);
|
||||
w->writeC(0x86);
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ DivDataErrors DivWavetable::readWaveData(SafeReader& reader, short version) {
|
|||
char magic[4];
|
||||
reader.read(magic,4);
|
||||
if (memcmp(magic,"WAVE",4)!=0) {
|
||||
logV("header is invalid: %c%c%c%c",magic[0],magic[1],magic[2],magic[3]);
|
||||
return DIV_DATA_INVALID_HEADER;
|
||||
}
|
||||
reader.readI(); // reserved
|
||||
|
|
@ -57,7 +58,10 @@ DivDataErrors DivWavetable::readWaveData(SafeReader& reader, short version) {
|
|||
min=reader.readI();
|
||||
max=reader.readI();
|
||||
|
||||
if (len>256 || min!=0 || max>255) return DIV_DATA_INVALID_DATA;
|
||||
if (len>256 || min!=0 || max>255) {
|
||||
logV("invalid len/min/max: %d %d %d",len,min,max);
|
||||
return DIV_DATA_INVALID_DATA;
|
||||
}
|
||||
|
||||
for (int i=0; i<len; i++) {
|
||||
data[i]=reader.readI();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue