Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt

This commit is contained in:
cam900 2022-11-30 17:39:43 +09:00
commit 7867b59580
85 changed files with 6024 additions and 3108 deletions

View file

@ -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.

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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) {
}

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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();

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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();

View file

@ -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;

View file

@ -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();

View file

@ -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) {

View file

@ -82,7 +82,7 @@ class DivPlatformOPLL: public DivDispatch {
bool useYMFM;
bool drums;
bool properDrums, properDrumsSys;
bool properDrums, properDrumsSys, noTopHatFreq;
bool vrc7;
unsigned char patchSet;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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();
};

View file

@ -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;
}

View file

@ -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:

View file

@ -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) {

View file

@ -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++) {

View file

@ -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);

View file

@ -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;

View file

@ -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:

View file

@ -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);

View file

@ -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:

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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();

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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();

View file

@ -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;

View file

@ -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;
}

View file

@ -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();

View file

@ -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));
}

View file

@ -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();
};

View file

@ -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"},

View file

@ -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);

View file

@ -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();