Merge branch 'master' of https://github.com/tildearrow/furnace into nmk112
This commit is contained in:
commit
15bdb19336
1785 changed files with 523362 additions and 4372 deletions
|
|
@ -267,6 +267,29 @@ struct DivCommand {
|
|||
value2(0) {}
|
||||
};
|
||||
|
||||
struct DivPitchTable {
|
||||
int pitch[(12*128)+1];
|
||||
unsigned char linearity, blockBits;
|
||||
bool period;
|
||||
|
||||
// get pitch
|
||||
int get(int base, int pitch, int pitch2);
|
||||
|
||||
// linear: note
|
||||
// non-linear: get(note,0,0)
|
||||
int getBase(int note);
|
||||
|
||||
// calculate pitch table
|
||||
void init(float tuning, double clock, double divider, int octave, unsigned char linear, bool isPeriod, unsigned char block=0);
|
||||
|
||||
DivPitchTable():
|
||||
linearity(2),
|
||||
blockBits(0),
|
||||
period(false) {
|
||||
memset(pitch,0,sizeof(pitch));
|
||||
}
|
||||
};
|
||||
|
||||
struct DivDelayedCommand {
|
||||
int ticks;
|
||||
DivCommand cmd;
|
||||
|
|
@ -339,6 +362,40 @@ struct DivDispatchOscBuffer {
|
|||
}
|
||||
};
|
||||
|
||||
struct DivChannelPair {
|
||||
const char* label;
|
||||
// -1: none
|
||||
signed char pairs[8];
|
||||
|
||||
DivChannelPair(const char* l, signed char p0, signed char p1, signed char p2, signed char p3, signed char p4, signed char p5, signed char p6, signed char p7):
|
||||
label(l),
|
||||
pairs{p0,p1,p2,p3,p4,p5,p6,p7} {}
|
||||
DivChannelPair(const char* l, signed char p):
|
||||
label(l),
|
||||
pairs{p,-1,-1,-1,-1,-1,-1,-1} {}
|
||||
DivChannelPair():
|
||||
label(NULL),
|
||||
pairs{-1,-1,-1,-1,-1,-1,-1,-1} {}
|
||||
};
|
||||
|
||||
struct DivChannelModeHints {
|
||||
const char* hint[4];
|
||||
// valid types:
|
||||
// - 0: disabled
|
||||
// - 1: volume
|
||||
// - 2: pitch
|
||||
// - 3: panning
|
||||
// - 4: ???
|
||||
unsigned char type[4];
|
||||
// up to 4
|
||||
unsigned char count;
|
||||
|
||||
DivChannelModeHints():
|
||||
hint{NULL,NULL,NULL,NULL},
|
||||
type{0,0,0,0},
|
||||
count(0) {}
|
||||
};
|
||||
|
||||
class DivEngine;
|
||||
class DivMacroInt;
|
||||
|
||||
|
|
@ -418,6 +475,21 @@ class DivDispatch {
|
|||
*/
|
||||
virtual unsigned short getPan(int chan);
|
||||
|
||||
/**
|
||||
* get "paired" channels.
|
||||
* @param chan the channel to query.
|
||||
* @return a DivChannelPair.
|
||||
*/
|
||||
virtual DivChannelPair getPaired(int chan);
|
||||
|
||||
/**
|
||||
* get channel mode hints.
|
||||
* @param chan the channel to query.
|
||||
* @return a DivChannelModeHints.
|
||||
*/
|
||||
virtual DivChannelModeHints getModeHints(int chan);
|
||||
|
||||
|
||||
/**
|
||||
* get currently playing sample (and its position).
|
||||
* @param chan the channel.
|
||||
|
|
@ -643,6 +715,11 @@ class DivDispatch {
|
|||
*/
|
||||
virtual void renderSamples(int sysID);
|
||||
|
||||
/**
|
||||
* tell this DivDispatch that the tuning and/or pitch linearity has changed, and therefore the pitch table must be regenerated.
|
||||
*/
|
||||
virtual void notifyPitchTable();
|
||||
|
||||
/**
|
||||
* initialize this DivDispatch.
|
||||
* @param parent the parent DivEngine.
|
||||
|
|
@ -669,6 +746,7 @@ class DivDispatch {
|
|||
if (chipClock<getClockRangeMin()) chipClock=getClockRangeMin(); \
|
||||
}
|
||||
|
||||
// NOTE: these definitions may be deprecated in the future. see DivPitchTable.
|
||||
// pitch calculation:
|
||||
// - a DivDispatch usually contains four variables per channel:
|
||||
// - baseFreq: this changes on new notes, legato, arpeggio and slides.
|
||||
|
|
|
|||
|
|
@ -150,6 +150,10 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
|
|||
if (iter!=sysDef->postEffectHandlers.end()) {
|
||||
return iter->second.description;
|
||||
}
|
||||
iter=sysDef->preEffectHandlers.find(effect);
|
||||
if (iter!=sysDef->preEffectHandlers.end()) {
|
||||
return iter->second.description;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -541,6 +545,7 @@ void DivEngine::initSongWithDesc(const char* description, bool inBase64, bool ol
|
|||
|
||||
// extra attributes
|
||||
song.subsong[0]->hz=c.getDouble("tickRate",60.0);
|
||||
song.author=getConfString("defaultAuthorName","");
|
||||
}
|
||||
|
||||
void DivEngine::createNew(const char* description, String sysName, bool inBase64) {
|
||||
|
|
@ -1414,6 +1419,11 @@ void* DivEngine::getDispatchChanState(int ch) {
|
|||
return disCont[dispatchOfChan[ch]].dispatch->getChanState(dispatchChanOfChan[ch]);
|
||||
}
|
||||
|
||||
DivChannelPair DivEngine::getChanPaired(int ch) {
|
||||
if (ch<0 || ch>=chans) return DivChannelPair();
|
||||
return disCont[dispatchOfChan[ch]].dispatch->getPaired(dispatchChanOfChan[ch]);
|
||||
}
|
||||
|
||||
unsigned char* DivEngine::getRegisterPool(int sys, int& size, int& depth) {
|
||||
if (sys<0 || sys>=song.systemLen) return NULL;
|
||||
if (disCont[sys].dispatch==NULL) return NULL;
|
||||
|
|
@ -1908,11 +1918,13 @@ void DivEngine::recalcChans() {
|
|||
memset(isInsTypePossible,0,DIV_INS_MAX*sizeof(bool));
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
int chanCount=getChannelCount(song.system[i]);
|
||||
int firstChan=chans;
|
||||
chans+=chanCount;
|
||||
for (int j=0; j<chanCount; j++) {
|
||||
sysOfChan[chanIndex]=song.system[i];
|
||||
dispatchOfChan[chanIndex]=i;
|
||||
dispatchChanOfChan[chanIndex]=j;
|
||||
dispatchFirstChan[chanIndex]=firstChan;
|
||||
chanIndex++;
|
||||
|
||||
if (sysDefs[song.system[i]]!=NULL) {
|
||||
|
|
@ -2295,6 +2307,65 @@ void DivEngine::unmuteAll() {
|
|||
BUSY_END;
|
||||
}
|
||||
|
||||
void DivEngine::dumpSongInfo() {
|
||||
printf(
|
||||
"SONG INFORMATION\n"
|
||||
"- name: %s\n"
|
||||
"- author: %s\n"
|
||||
"- album: %s\n"
|
||||
"- system: %s\n"
|
||||
"- %d ins, %d waves, %d samples\n"
|
||||
"<<<\n%s\n>>>\n\n",
|
||||
song.name.c_str(),
|
||||
song.author.c_str(),
|
||||
song.category.c_str(),
|
||||
song.systemName.c_str(),
|
||||
song.insLen,
|
||||
song.waveLen,
|
||||
song.sampleLen,
|
||||
song.notes.c_str()
|
||||
);
|
||||
|
||||
printf("SUB-SONGS\n");
|
||||
int index=0;
|
||||
for (DivSubSong* i: song.subsong) {
|
||||
printf(
|
||||
"=== %d: %s\n"
|
||||
"<<<\n%s\n>>>\n",
|
||||
index,
|
||||
i->name.c_str(),
|
||||
i->notes.c_str()
|
||||
);
|
||||
index++;
|
||||
}
|
||||
|
||||
if (!song.ins.empty()) {
|
||||
printf("\nINSTRUMENTS\n");
|
||||
index=0;
|
||||
for (DivInstrument* i: song.ins) {
|
||||
printf(
|
||||
"- %d: %s\n",
|
||||
index,
|
||||
i->name.c_str()
|
||||
);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!song.sample.empty()) {
|
||||
printf("\nSAMPLES\n");
|
||||
index=0;
|
||||
for (DivSample* i: song.sample) {
|
||||
printf(
|
||||
"- %d: %s\n",
|
||||
index,
|
||||
i->name.c_str()
|
||||
);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int DivEngine::addInstrument(int refChan, DivInstrumentType fallbackType) {
|
||||
if (song.ins.size()>=256) return -1;
|
||||
BUSY_BEGIN;
|
||||
|
|
@ -3094,7 +3165,7 @@ void DivEngine::noteOff(int chan) {
|
|||
BUSY_END;
|
||||
}
|
||||
|
||||
void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) {
|
||||
bool DivEngine::autoNoteOn(int ch, int ins, int note, int vol) {
|
||||
bool isViable[DIV_MAX_CHANS];
|
||||
bool canPlayAnyway=false;
|
||||
bool notInViableChannel=false;
|
||||
|
|
@ -3130,7 +3201,7 @@ void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!canPlayAnyway) return;
|
||||
if (!canPlayAnyway) return false;
|
||||
|
||||
// 2. find a free channel
|
||||
do {
|
||||
|
|
@ -3138,7 +3209,7 @@ void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) {
|
|||
chan[finalChan].midiNote=note;
|
||||
chan[finalChan].midiAge=midiAgeCounter++;
|
||||
pendingNotes.push_back(DivNoteEvent(finalChan,ins,note,vol,true));
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
if (++finalChan>=chans) {
|
||||
finalChan=0;
|
||||
|
|
@ -3159,6 +3230,7 @@ void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) {
|
|||
chan[candidate].midiNote=note;
|
||||
chan[candidate].midiAge=midiAgeCounter++;
|
||||
pendingNotes.push_back(DivNoteEvent(candidate,ins,note,vol,true));
|
||||
return true;
|
||||
}
|
||||
|
||||
void DivEngine::autoNoteOff(int ch, int note, int vol) {
|
||||
|
|
@ -3201,10 +3273,11 @@ void DivEngine::setOrder(unsigned char order) {
|
|||
BUSY_END;
|
||||
}
|
||||
|
||||
void DivEngine::updateSysFlags(int system, bool restart) {
|
||||
void DivEngine::updateSysFlags(int system, bool restart, bool render) {
|
||||
BUSY_BEGIN_SOFT;
|
||||
disCont[system].dispatch->setFlags(song.systemFlags[system]);
|
||||
disCont[system].setRates(got.rate);
|
||||
if (render) renderSamples();
|
||||
|
||||
// patchbay
|
||||
if (song.patchbayAuto) {
|
||||
|
|
@ -3620,7 +3693,8 @@ bool DivEngine::deinitAudioBackend(bool dueToSwitchMaster) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void DivEngine::preInit() {
|
||||
bool DivEngine::preInit(bool noSafeMode) {
|
||||
bool wantSafe=false;
|
||||
// register systems
|
||||
if (!systemsRegistered) registerSystems();
|
||||
|
||||
|
|
@ -3628,6 +3702,13 @@ void DivEngine::preInit() {
|
|||
initConfDir();
|
||||
logD("config path: %s",configPath.c_str());
|
||||
|
||||
if (!noSafeMode) {
|
||||
String safeModePath=configPath+DIR_SEPARATOR_STR+"safemode";
|
||||
if (touchFile(safeModePath.c_str())==-EEXIST) {
|
||||
wantSafe=true;
|
||||
}
|
||||
}
|
||||
|
||||
String logPath=configPath+DIR_SEPARATOR_STR+"furnace.log";
|
||||
startLogFile(logPath.c_str());
|
||||
|
||||
|
|
@ -3641,6 +3722,17 @@ void DivEngine::preInit() {
|
|||
SDL_SetHint("SDL_HINT_AUDIODRIVER",audioDriver.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wantSafe) {
|
||||
logW("requesting safe mode.");
|
||||
}
|
||||
|
||||
return wantSafe;
|
||||
}
|
||||
|
||||
void DivEngine::everythingOK() {
|
||||
String safeModePath=configPath+DIR_SEPARATOR_STR+"safemode";
|
||||
deleteFile(safeModePath.c_str());
|
||||
}
|
||||
|
||||
bool DivEngine::init() {
|
||||
|
|
|
|||
|
|
@ -52,10 +52,10 @@ class DivWorkPool;
|
|||
#define EXTERN_BUSY_BEGIN_SOFT e->softLocked=true; e->isBusy.lock();
|
||||
#define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false;
|
||||
|
||||
//#define DIV_UNSTABLE
|
||||
#define DIV_UNSTABLE
|
||||
|
||||
#define DIV_VERSION "0.6"
|
||||
#define DIV_ENGINE_VERSION 181
|
||||
#define DIV_VERSION "dev184"
|
||||
#define DIV_ENGINE_VERSION 184
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
#define DIV_VERSION_FC 0xff02
|
||||
|
|
@ -105,7 +105,7 @@ struct DivChannelState {
|
|||
int vibratoDepth, vibratoRate, vibratoPos, vibratoPosGiant, vibratoDir, vibratoFine;
|
||||
int tremoloDepth, tremoloRate, tremoloPos;
|
||||
unsigned char arp, arpStage, arpTicks, panL, panR, panRL, panRR, lastVibrato, lastPorta;
|
||||
bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff;
|
||||
bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff, releasing;
|
||||
bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, wasShorthandPorta, noteOnInhibit, resetArp;
|
||||
bool wentThroughNote, goneThroughNote;
|
||||
|
||||
|
|
@ -154,6 +154,7 @@ struct DivChannelState {
|
|||
keyOff(false),
|
||||
nowYouCanStop(true),
|
||||
stopOnOff(false),
|
||||
releasing(false),
|
||||
arpYield(false),
|
||||
delayLocked(false),
|
||||
inPorta(false),
|
||||
|
|
@ -595,6 +596,7 @@ class DivEngine {
|
|||
DivSystem sysOfChan[DIV_MAX_CHANS];
|
||||
int dispatchOfChan[DIV_MAX_CHANS];
|
||||
int dispatchChanOfChan[DIV_MAX_CHANS];
|
||||
int dispatchFirstChan[DIV_MAX_CHANS];
|
||||
bool keyHit[DIV_MAX_CHANS];
|
||||
float* oscBuf[DIV_MAX_OUTPUTS];
|
||||
float oscSize;
|
||||
|
|
@ -879,6 +881,9 @@ class DivEngine {
|
|||
// get ext value
|
||||
unsigned char getExtValue();
|
||||
|
||||
// dump song info to stdout
|
||||
void dumpSongInfo();
|
||||
|
||||
// is playing
|
||||
bool isPlaying();
|
||||
|
||||
|
|
@ -983,7 +988,8 @@ class DivEngine {
|
|||
// stop note
|
||||
void noteOff(int chan);
|
||||
|
||||
void autoNoteOn(int chan, int ins, int note, int vol=-1);
|
||||
// returns whether it could
|
||||
bool autoNoteOn(int chan, int ins, int note, int vol=-1);
|
||||
void autoNoteOff(int chan, int note, int vol=-1);
|
||||
void autoNoteOffAll();
|
||||
|
||||
|
|
@ -994,7 +1000,7 @@ class DivEngine {
|
|||
void setOrder(unsigned char order);
|
||||
|
||||
// update system flags
|
||||
void updateSysFlags(int system, bool restart);
|
||||
void updateSysFlags(int system, bool restart, bool render);
|
||||
|
||||
// set Hz
|
||||
void setSongRate(float hz);
|
||||
|
|
@ -1008,6 +1014,9 @@ class DivEngine {
|
|||
// get dispatch channel state
|
||||
void* getDispatchChanState(int chan);
|
||||
|
||||
// get channel pairs
|
||||
DivChannelPair getChanPaired(int chan);
|
||||
|
||||
// get register pool
|
||||
unsigned char* getRegisterPool(int sys, int& size, int& depth);
|
||||
|
||||
|
|
@ -1190,12 +1199,15 @@ class DivEngine {
|
|||
// quit dispatch
|
||||
void quitDispatch();
|
||||
|
||||
// pre-initialize the engine.
|
||||
void preInit();
|
||||
// pre-initialize the engine. returns whether Furnace should run in safe mode.
|
||||
bool preInit(bool noSafeMode=true);
|
||||
|
||||
// initialize the engine.
|
||||
bool init();
|
||||
|
||||
// confirm that the engine is running (delete safe mode file).
|
||||
void everythingOK();
|
||||
|
||||
// terminate the engine.
|
||||
bool quit();
|
||||
|
||||
|
|
@ -1319,6 +1331,7 @@ class DivEngine {
|
|||
mu5ROM(NULL) {
|
||||
memset(isMuted,0,DIV_MAX_CHANS*sizeof(bool));
|
||||
memset(keyHit,0,DIV_MAX_CHANS*sizeof(bool));
|
||||
memset(dispatchFirstChan,0,DIV_MAX_CHANS*sizeof(int));
|
||||
memset(dispatchChanOfChan,0,DIV_MAX_CHANS*sizeof(int));
|
||||
memset(dispatchOfChan,0,DIV_MAX_CHANS*sizeof(int));
|
||||
memset(sysOfChan,0,DIV_MAX_CHANS*sizeof(int));
|
||||
|
|
|
|||
|
|
@ -184,6 +184,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
ds.snNoLowPeriods=true;
|
||||
ds.disableSampleMacro=true;
|
||||
ds.preNoteNoEffect=true;
|
||||
ds.oldDPCM=true;
|
||||
ds.delayBehavior=0;
|
||||
ds.jumpTreatment=2;
|
||||
|
||||
|
|
@ -1856,6 +1857,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
if (ds.version<168) {
|
||||
ds.preNoteNoEffect=true;
|
||||
}
|
||||
if (ds.version<183) {
|
||||
ds.oldDPCM=true;
|
||||
}
|
||||
if (ds.version<184) {
|
||||
ds.resetArpPhaseOnNewNote=false;
|
||||
}
|
||||
ds.isDMF=false;
|
||||
|
||||
reader.readS(); // reserved
|
||||
|
|
@ -2374,7 +2381,17 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
} else {
|
||||
reader.readC();
|
||||
}
|
||||
for (int i=0; i<5; i++) {
|
||||
if (ds.version>=183) {
|
||||
ds.oldDPCM=reader.readC();
|
||||
} else {
|
||||
reader.readC();
|
||||
}
|
||||
if (ds.version>=184) {
|
||||
ds.resetArpPhaseOnNewNote=reader.readC();
|
||||
} else {
|
||||
reader.readC();
|
||||
}
|
||||
for (int i=0; i<3; i++) {
|
||||
reader.readC();
|
||||
}
|
||||
}
|
||||
|
|
@ -5438,7 +5455,9 @@ SafeWriter* DivEngine::saveFur(bool notPrimary, bool newPatternFormat) {
|
|||
w->writeC(song.brokenPortaLegato);
|
||||
w->writeC(song.brokenFMOff);
|
||||
w->writeC(song.preNoteNoEffect);
|
||||
for (int i=0; i<5; i++) {
|
||||
w->writeC(song.oldDPCM);
|
||||
w->writeC(song.resetArpPhaseOnNewNote);
|
||||
for (int i=0; i<3; i++) {
|
||||
w->writeC(0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -291,7 +291,7 @@ void DivInstrument::writeFeatureFM(SafeWriter* w, bool fui) {
|
|||
FEATURE_END;
|
||||
}
|
||||
|
||||
void DivInstrument::writeMacro(SafeWriter* w, const DivInstrumentMacro& m, unsigned char macroCode) {
|
||||
void DivInstrument::writeMacro(SafeWriter* w, const DivInstrumentMacro& m) {
|
||||
if (!m.len) return;
|
||||
|
||||
// determine word size
|
||||
|
|
@ -314,12 +314,12 @@ void DivInstrument::writeMacro(SafeWriter* w, const DivInstrumentMacro& m, unsig
|
|||
wordSize=192; // 32-bit signed
|
||||
}
|
||||
|
||||
w->writeC(macroCode);
|
||||
w->writeC(m.macroType&31);
|
||||
w->writeC(m.len);
|
||||
w->writeC(m.loop);
|
||||
w->writeC(m.rel);
|
||||
w->writeC(m.mode);
|
||||
w->writeC(m.open|wordSize);
|
||||
w->writeC((m.open&0x3f)|wordSize);
|
||||
w->writeC(m.delay);
|
||||
w->writeC(m.speed);
|
||||
|
||||
|
|
@ -355,26 +355,26 @@ void DivInstrument::writeFeatureMA(SafeWriter* w) {
|
|||
w->writeS(8);
|
||||
|
||||
// write macros
|
||||
writeMacro(w,std.volMacro,0);
|
||||
writeMacro(w,std.arpMacro,1);
|
||||
writeMacro(w,std.dutyMacro,2);
|
||||
writeMacro(w,std.waveMacro,3);
|
||||
writeMacro(w,std.pitchMacro,4);
|
||||
writeMacro(w,std.ex1Macro,5);
|
||||
writeMacro(w,std.ex2Macro,6);
|
||||
writeMacro(w,std.ex3Macro,7);
|
||||
writeMacro(w,std.algMacro,8);
|
||||
writeMacro(w,std.fbMacro,9);
|
||||
writeMacro(w,std.fmsMacro,10);
|
||||
writeMacro(w,std.amsMacro,11);
|
||||
writeMacro(w,std.panLMacro,12);
|
||||
writeMacro(w,std.panRMacro,13);
|
||||
writeMacro(w,std.phaseResetMacro,14);
|
||||
writeMacro(w,std.ex4Macro,15);
|
||||
writeMacro(w,std.ex5Macro,16);
|
||||
writeMacro(w,std.ex6Macro,17);
|
||||
writeMacro(w,std.ex7Macro,18);
|
||||
writeMacro(w,std.ex8Macro,19);
|
||||
writeMacro(w,std.volMacro);
|
||||
writeMacro(w,std.arpMacro);
|
||||
writeMacro(w,std.dutyMacro);
|
||||
writeMacro(w,std.waveMacro);
|
||||
writeMacro(w,std.pitchMacro);
|
||||
writeMacro(w,std.ex1Macro);
|
||||
writeMacro(w,std.ex2Macro);
|
||||
writeMacro(w,std.ex3Macro);
|
||||
writeMacro(w,std.algMacro);
|
||||
writeMacro(w,std.fbMacro);
|
||||
writeMacro(w,std.fmsMacro);
|
||||
writeMacro(w,std.amsMacro);
|
||||
writeMacro(w,std.panLMacro);
|
||||
writeMacro(w,std.panRMacro);
|
||||
writeMacro(w,std.phaseResetMacro);
|
||||
writeMacro(w,std.ex4Macro);
|
||||
writeMacro(w,std.ex5Macro);
|
||||
writeMacro(w,std.ex6Macro);
|
||||
writeMacro(w,std.ex7Macro);
|
||||
writeMacro(w,std.ex8Macro);
|
||||
|
||||
// "stop reading" code
|
||||
w->writeC(-1);
|
||||
|
|
@ -471,26 +471,26 @@ void DivInstrument::writeFeatureOx(SafeWriter* w, int ope) {
|
|||
// write macros
|
||||
const DivInstrumentSTD::OpMacro& o=std.opMacros[ope];
|
||||
|
||||
writeMacro(w,o.amMacro,0);
|
||||
writeMacro(w,o.arMacro,1);
|
||||
writeMacro(w,o.drMacro,2);
|
||||
writeMacro(w,o.multMacro,3);
|
||||
writeMacro(w,o.rrMacro,4);
|
||||
writeMacro(w,o.slMacro,5);
|
||||
writeMacro(w,o.tlMacro,6);
|
||||
writeMacro(w,o.dt2Macro,7);
|
||||
writeMacro(w,o.rsMacro,8);
|
||||
writeMacro(w,o.dtMacro,9);
|
||||
writeMacro(w,o.d2rMacro,10);
|
||||
writeMacro(w,o.ssgMacro,11);
|
||||
writeMacro(w,o.damMacro,12);
|
||||
writeMacro(w,o.dvbMacro,13);
|
||||
writeMacro(w,o.egtMacro,14);
|
||||
writeMacro(w,o.kslMacro,15);
|
||||
writeMacro(w,o.susMacro,16);
|
||||
writeMacro(w,o.vibMacro,17);
|
||||
writeMacro(w,o.wsMacro,18);
|
||||
writeMacro(w,o.ksrMacro,19);
|
||||
writeMacro(w,o.amMacro);
|
||||
writeMacro(w,o.arMacro);
|
||||
writeMacro(w,o.drMacro);
|
||||
writeMacro(w,o.multMacro);
|
||||
writeMacro(w,o.rrMacro);
|
||||
writeMacro(w,o.slMacro);
|
||||
writeMacro(w,o.tlMacro);
|
||||
writeMacro(w,o.dt2Macro);
|
||||
writeMacro(w,o.rsMacro);
|
||||
writeMacro(w,o.dtMacro);
|
||||
writeMacro(w,o.d2rMacro);
|
||||
writeMacro(w,o.ssgMacro);
|
||||
writeMacro(w,o.damMacro);
|
||||
writeMacro(w,o.dvbMacro);
|
||||
writeMacro(w,o.egtMacro);
|
||||
writeMacro(w,o.kslMacro);
|
||||
writeMacro(w,o.susMacro);
|
||||
writeMacro(w,o.vibMacro);
|
||||
writeMacro(w,o.wsMacro);
|
||||
writeMacro(w,o.ksrMacro);
|
||||
|
||||
// "stop reading" code
|
||||
w->writeC(-1);
|
||||
|
|
@ -719,6 +719,21 @@ void DivInstrument::writeFeatureX1(SafeWriter* w) {
|
|||
FEATURE_END;
|
||||
}
|
||||
|
||||
void DivInstrument::writeFeatureNE(SafeWriter* w) {
|
||||
FEATURE_BEGIN("NE");
|
||||
|
||||
w->writeC(amiga.useNoteMap?1:0);
|
||||
|
||||
if (amiga.useNoteMap) {
|
||||
for (int note=0; note<120; note++) {
|
||||
w->writeC(amiga.noteMap[note].dpcmFreq);
|
||||
w->writeC(amiga.noteMap[note].dpcmDelta);
|
||||
}
|
||||
}
|
||||
|
||||
FEATURE_END;
|
||||
}
|
||||
|
||||
void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song, bool insName) {
|
||||
size_t blockStartSeek=0;
|
||||
size_t blockEndSeek=0;
|
||||
|
|
@ -761,6 +776,7 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song, bo
|
|||
bool featureSU=false;
|
||||
bool featureES=false;
|
||||
bool featureX1=false;
|
||||
bool featureNE=false;
|
||||
|
||||
bool checkForWL=false;
|
||||
|
||||
|
|
@ -904,6 +920,9 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song, bo
|
|||
featureFM=true;
|
||||
break;
|
||||
case DIV_INS_NES:
|
||||
featureSM=true;
|
||||
featureNE=true;
|
||||
featureSL=true;
|
||||
break;
|
||||
case DIV_INS_MSM6258:
|
||||
featureSM=true;
|
||||
|
|
@ -993,6 +1012,7 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song, bo
|
|||
}
|
||||
if (amiga!=defaultIns.amiga) {
|
||||
featureSM=true;
|
||||
featureNE=true;
|
||||
}
|
||||
if (snes!=defaultIns.snes) {
|
||||
featureSN=true;
|
||||
|
|
@ -1157,6 +1177,9 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song, bo
|
|||
if (featureX1) {
|
||||
writeFeatureX1(w);
|
||||
}
|
||||
if (featureNE) {
|
||||
writeFeatureNE(w);
|
||||
}
|
||||
|
||||
if (fui && (featureSL || featureWL)) {
|
||||
w->write("EN",2);
|
||||
|
|
@ -2024,7 +2047,7 @@ void DivInstrument::readFeatureMA(SafeReader& reader, short version) {
|
|||
target->mode=reader.readC();
|
||||
|
||||
unsigned char wordSize=reader.readC();
|
||||
target->open=wordSize&7;
|
||||
target->open=wordSize&15;
|
||||
wordSize>>=6;
|
||||
|
||||
target->delay=reader.readC();
|
||||
|
|
@ -2416,7 +2439,7 @@ void DivInstrument::readFeatureSL(SafeReader& reader, DivSong* song, short versi
|
|||
}
|
||||
}
|
||||
|
||||
reader.seek(lastSeek,SEEK_CUR);
|
||||
reader.seek(lastSeek,SEEK_SET);
|
||||
|
||||
// re-map samples
|
||||
if (amiga.initSample>=0 && amiga.initSample<256) {
|
||||
|
|
@ -2475,7 +2498,7 @@ void DivInstrument::readFeatureWL(SafeReader& reader, DivSong* song, short versi
|
|||
}
|
||||
}
|
||||
|
||||
reader.seek(lastSeek,SEEK_CUR);
|
||||
reader.seek(lastSeek,SEEK_SET);
|
||||
|
||||
// re-map wavetables
|
||||
if (ws.enabled) {
|
||||
|
|
@ -2541,6 +2564,21 @@ void DivInstrument::readFeatureX1(SafeReader& reader, short version) {
|
|||
READ_FEAT_END;
|
||||
}
|
||||
|
||||
void DivInstrument::readFeatureNE(SafeReader& reader, short version) {
|
||||
READ_FEAT_BEGIN;
|
||||
|
||||
amiga.useNoteMap=reader.readC();
|
||||
|
||||
if (amiga.useNoteMap) {
|
||||
for (int note=0; note<120; note++) {
|
||||
amiga.noteMap[note].dpcmFreq=reader.readC();
|
||||
amiga.noteMap[note].dpcmDelta=reader.readC();
|
||||
}
|
||||
}
|
||||
|
||||
READ_FEAT_END;
|
||||
}
|
||||
|
||||
DivDataErrors DivInstrument::readInsDataNew(SafeReader& reader, short version, bool fui, DivSong* song) {
|
||||
unsigned char featCode[2];
|
||||
|
||||
|
|
@ -2606,6 +2644,8 @@ DivDataErrors DivInstrument::readInsDataNew(SafeReader& reader, short version, b
|
|||
readFeatureES(reader,version);
|
||||
} else if (memcmp(featCode,"X1",2)==0) { // X1-010
|
||||
readFeatureX1(reader,version);
|
||||
} else if (memcmp(featCode,"NE",2)==0) { // NES (DPCM)
|
||||
readFeatureNE(reader,version);
|
||||
} else {
|
||||
if (song==NULL && (memcmp(featCode,"SL",2)==0 || (memcmp(featCode,"WL",2)==0))) {
|
||||
// nothing
|
||||
|
|
|
|||
|
|
@ -89,6 +89,52 @@ enum DivInstrumentType: unsigned short {
|
|||
DIV_INS_NULL
|
||||
};
|
||||
|
||||
enum DivMacroType: unsigned char {
|
||||
DIV_MACRO_VOL=0,
|
||||
DIV_MACRO_ARP,
|
||||
DIV_MACRO_DUTY,
|
||||
DIV_MACRO_WAVE,
|
||||
DIV_MACRO_PITCH,
|
||||
DIV_MACRO_EX1,
|
||||
DIV_MACRO_EX2,
|
||||
DIV_MACRO_EX3,
|
||||
DIV_MACRO_ALG,
|
||||
DIV_MACRO_FB,
|
||||
DIV_MACRO_FMS,
|
||||
DIV_MACRO_AMS,
|
||||
DIV_MACRO_PAN_LEFT,
|
||||
DIV_MACRO_PAN_RIGHT,
|
||||
DIV_MACRO_PHASE_RESET,
|
||||
DIV_MACRO_EX4,
|
||||
DIV_MACRO_EX5,
|
||||
DIV_MACRO_EX6,
|
||||
DIV_MACRO_EX7,
|
||||
DIV_MACRO_EX8
|
||||
};
|
||||
|
||||
enum DivMacroTypeOp: unsigned char {
|
||||
DIV_MACRO_OP_AM=32,
|
||||
DIV_MACRO_OP_AR,
|
||||
DIV_MACRO_OP_DR,
|
||||
DIV_MACRO_OP_MULT,
|
||||
DIV_MACRO_OP_RR,
|
||||
DIV_MACRO_OP_SL,
|
||||
DIV_MACRO_OP_TL,
|
||||
DIV_MACRO_OP_DT2,
|
||||
DIV_MACRO_OP_RS,
|
||||
DIV_MACRO_OP_DT,
|
||||
DIV_MACRO_OP_D2R,
|
||||
DIV_MACRO_OP_SSG,
|
||||
DIV_MACRO_OP_DAM,
|
||||
DIV_MACRO_OP_DVB,
|
||||
DIV_MACRO_OP_EGT,
|
||||
DIV_MACRO_OP_KSL,
|
||||
DIV_MACRO_OP_SUS,
|
||||
DIV_MACRO_OP_VIB,
|
||||
DIV_MACRO_OP_WS,
|
||||
DIV_MACRO_OP_KSR,
|
||||
};
|
||||
|
||||
// FM operator structure:
|
||||
// - OPN:
|
||||
// - AM, AR, DR, MULT, RR, SL, TL, RS, DT, D2R, SSG-EG
|
||||
|
|
@ -198,19 +244,20 @@ struct DivInstrumentFM {
|
|||
|
||||
// this is getting out of hand
|
||||
struct DivInstrumentMacro {
|
||||
String name;
|
||||
int val[256];
|
||||
unsigned int mode;
|
||||
unsigned char open;
|
||||
unsigned char len, delay, speed, loop, rel;
|
||||
// 0-31: normal
|
||||
// 32+: operator (top 3 bits select operator, starting from 1)
|
||||
unsigned char macroType;
|
||||
|
||||
// the following variables are used by the GUI and not saved in the file
|
||||
int vScroll, vZoom;
|
||||
int typeMemory[16];
|
||||
unsigned char lenMemory;
|
||||
|
||||
explicit DivInstrumentMacro(const String& n, bool initOpen=false):
|
||||
name(n),
|
||||
explicit DivInstrumentMacro(unsigned char initType, bool initOpen=false):
|
||||
mode(0),
|
||||
open(initOpen),
|
||||
len(0),
|
||||
|
|
@ -218,6 +265,7 @@ struct DivInstrumentMacro {
|
|||
speed(1),
|
||||
loop(255),
|
||||
rel(255),
|
||||
macroType(initType),
|
||||
vScroll(0),
|
||||
vZoom(-1),
|
||||
lenMemory(0) {
|
||||
|
|
@ -271,33 +319,57 @@ struct DivInstrumentSTD {
|
|||
DivInstrumentMacro wsMacro;
|
||||
DivInstrumentMacro ksrMacro;
|
||||
OpMacro():
|
||||
amMacro("am"), arMacro("ar"), drMacro("dr"), multMacro("mult"),
|
||||
rrMacro("rr"), slMacro("sl"), tlMacro("tl",true), dt2Macro("dt2"),
|
||||
rsMacro("rs"), dtMacro("dt"), d2rMacro("d2r"), ssgMacro("ssg"),
|
||||
damMacro("dam"), dvbMacro("dvb"), egtMacro("egt"), kslMacro("ksl"),
|
||||
susMacro("sus"), vibMacro("vib"), wsMacro("ws"), ksrMacro("ksr") {}
|
||||
amMacro(DIV_MACRO_OP_AM), arMacro(DIV_MACRO_OP_AR), drMacro(DIV_MACRO_OP_DR), multMacro(DIV_MACRO_OP_MULT),
|
||||
rrMacro(DIV_MACRO_OP_RR), slMacro(DIV_MACRO_OP_SL), tlMacro(DIV_MACRO_OP_TL,true), dt2Macro(DIV_MACRO_OP_DT2),
|
||||
rsMacro(DIV_MACRO_OP_RS), dtMacro(DIV_MACRO_OP_DT), d2rMacro(DIV_MACRO_OP_D2R), ssgMacro(DIV_MACRO_OP_SSG),
|
||||
damMacro(DIV_MACRO_OP_DAM), dvbMacro(DIV_MACRO_OP_DVB), egtMacro(DIV_MACRO_OP_EGT), kslMacro(DIV_MACRO_OP_KSL),
|
||||
susMacro(DIV_MACRO_OP_SUS), vibMacro(DIV_MACRO_OP_VIB), wsMacro(DIV_MACRO_OP_WS), ksrMacro(DIV_MACRO_OP_KSR) {}
|
||||
} opMacros[4];
|
||||
DivInstrumentSTD():
|
||||
volMacro("vol",true),
|
||||
arpMacro("arp"),
|
||||
dutyMacro("duty"),
|
||||
waveMacro("wave"),
|
||||
pitchMacro("pitch"),
|
||||
ex1Macro("ex1"),
|
||||
ex2Macro("ex2"),
|
||||
ex3Macro("ex3"),
|
||||
algMacro("alg"),
|
||||
fbMacro("fb"),
|
||||
fmsMacro("fms"),
|
||||
amsMacro("ams"),
|
||||
panLMacro("panL"),
|
||||
panRMacro("panR"),
|
||||
phaseResetMacro("phaseReset"),
|
||||
ex4Macro("ex4"),
|
||||
ex5Macro("ex5"),
|
||||
ex6Macro("ex6"),
|
||||
ex7Macro("ex7"),
|
||||
ex8Macro("ex8") {}
|
||||
volMacro(DIV_MACRO_VOL,true),
|
||||
arpMacro(DIV_MACRO_ARP),
|
||||
dutyMacro(DIV_MACRO_DUTY),
|
||||
waveMacro(DIV_MACRO_WAVE),
|
||||
pitchMacro(DIV_MACRO_PITCH),
|
||||
ex1Macro(DIV_MACRO_EX1),
|
||||
ex2Macro(DIV_MACRO_EX2),
|
||||
ex3Macro(DIV_MACRO_EX3),
|
||||
algMacro(DIV_MACRO_ALG),
|
||||
fbMacro(DIV_MACRO_FB),
|
||||
fmsMacro(DIV_MACRO_FMS),
|
||||
amsMacro(DIV_MACRO_AMS),
|
||||
panLMacro(DIV_MACRO_PAN_LEFT),
|
||||
panRMacro(DIV_MACRO_PAN_RIGHT),
|
||||
phaseResetMacro(DIV_MACRO_PHASE_RESET),
|
||||
ex4Macro(DIV_MACRO_EX4),
|
||||
ex5Macro(DIV_MACRO_EX5),
|
||||
ex6Macro(DIV_MACRO_EX6),
|
||||
ex7Macro(DIV_MACRO_EX7),
|
||||
ex8Macro(DIV_MACRO_EX8) {
|
||||
for (int i=0; i<4; i++) {
|
||||
opMacros[i].amMacro.macroType=DIV_MACRO_OP_AM+(i<<5);
|
||||
opMacros[i].arMacro.macroType=DIV_MACRO_OP_AR+(i<<5);
|
||||
opMacros[i].drMacro.macroType=DIV_MACRO_OP_DR+(i<<5);
|
||||
opMacros[i].multMacro.macroType=DIV_MACRO_OP_MULT+(i<<5);
|
||||
opMacros[i].rrMacro.macroType=DIV_MACRO_OP_RR+(i<<5);
|
||||
opMacros[i].slMacro.macroType=DIV_MACRO_OP_SL+(i<<5);
|
||||
opMacros[i].tlMacro.macroType=DIV_MACRO_OP_TL+(i<<5);
|
||||
opMacros[i].dt2Macro.macroType=DIV_MACRO_OP_DT2+(i<<5);
|
||||
opMacros[i].rsMacro.macroType=DIV_MACRO_OP_RS+(i<<5);
|
||||
opMacros[i].dtMacro.macroType=DIV_MACRO_OP_DT+(i<<5);
|
||||
opMacros[i].d2rMacro.macroType=DIV_MACRO_OP_D2R+(i<<5);
|
||||
opMacros[i].ssgMacro.macroType=DIV_MACRO_OP_SSG+(i<<5);
|
||||
|
||||
opMacros[i].damMacro.macroType=DIV_MACRO_OP_DAM+(i<<5);
|
||||
opMacros[i].dvbMacro.macroType=DIV_MACRO_OP_DVB+(i<<5);
|
||||
opMacros[i].egtMacro.macroType=DIV_MACRO_OP_EGT+(i<<5);
|
||||
opMacros[i].kslMacro.macroType=DIV_MACRO_OP_KSL+(i<<5);
|
||||
opMacros[i].susMacro.macroType=DIV_MACRO_OP_SUS+(i<<5);
|
||||
opMacros[i].vibMacro.macroType=DIV_MACRO_OP_VIB+(i<<5);
|
||||
opMacros[i].wsMacro.macroType=DIV_MACRO_OP_WS+(i<<5);
|
||||
opMacros[i].ksrMacro.macroType=DIV_MACRO_OP_KSR+(i<<5);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct DivInstrumentGB {
|
||||
|
|
@ -380,9 +452,13 @@ struct DivInstrumentAmiga {
|
|||
struct SampleMap {
|
||||
int freq;
|
||||
short map;
|
||||
SampleMap(int f=0, short m=-1):
|
||||
signed char dpcmFreq;
|
||||
signed char dpcmDelta;
|
||||
SampleMap(int f=0, short m=-1, signed char df=15, signed char dd=-1):
|
||||
freq(f),
|
||||
map(m) {}
|
||||
map(m),
|
||||
dpcmFreq(df),
|
||||
dpcmDelta(dd) {}
|
||||
};
|
||||
short initSample;
|
||||
bool useNoteMap;
|
||||
|
|
@ -410,8 +486,8 @@ struct DivInstrumentAmiga {
|
|||
}
|
||||
|
||||
/**
|
||||
* get the sample frequency at specified note.
|
||||
* @return the frequency, or -1 if not using note map.
|
||||
* get the sample playback note at specified note.
|
||||
* @return the note, or -1 if not using note map.
|
||||
*/
|
||||
inline int getFreq(int note) {
|
||||
if (useNoteMap) {
|
||||
|
|
@ -422,6 +498,32 @@ struct DivInstrumentAmiga {
|
|||
return note;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the DPCM pitch at specified note.
|
||||
* @return the pitch, or -1 if not using note map.
|
||||
*/
|
||||
inline signed char getDPCMFreq(int note) {
|
||||
if (useNoteMap) {
|
||||
if (note<0) note=0;
|
||||
if (note>119) note=119;
|
||||
return noteMap[note].dpcmFreq;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the DPCM delta counter value at specified note.
|
||||
* @return the delta counter value, or -1 if not using note map.
|
||||
*/
|
||||
inline signed char getDPCMDelta(int note) {
|
||||
if (useNoteMap) {
|
||||
if (note<0) note=0;
|
||||
if (note>119) note=119;
|
||||
return noteMap[note].dpcmDelta;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
DivInstrumentAmiga():
|
||||
initSample(0),
|
||||
useNoteMap(false),
|
||||
|
|
@ -668,7 +770,7 @@ struct DivInstrument {
|
|||
/**
|
||||
* these are internal functions.
|
||||
*/
|
||||
void writeMacro(SafeWriter* w, const DivInstrumentMacro& m, unsigned char macroCode);
|
||||
void writeMacro(SafeWriter* w, const DivInstrumentMacro& m);
|
||||
void writeFeatureNA(SafeWriter* w);
|
||||
void writeFeatureFM(SafeWriter* w, bool fui);
|
||||
void writeFeatureMA(SafeWriter* w);
|
||||
|
|
@ -687,6 +789,7 @@ struct DivInstrument {
|
|||
void writeFeatureSU(SafeWriter* w);
|
||||
void writeFeatureES(SafeWriter* w);
|
||||
void writeFeatureX1(SafeWriter* w);
|
||||
void writeFeatureNE(SafeWriter* w);
|
||||
|
||||
void readFeatureNA(SafeReader& reader, short version);
|
||||
void readFeatureFM(SafeReader& reader, short version);
|
||||
|
|
@ -706,6 +809,7 @@ struct DivInstrument {
|
|||
void readFeatureSU(SafeReader& reader, short version);
|
||||
void readFeatureES(SafeReader& reader, short version);
|
||||
void readFeatureX1(SafeReader& reader, short version);
|
||||
void readFeatureNE(SafeReader& reader, short version);
|
||||
|
||||
DivDataErrors readInsDataOld(SafeReader& reader, short version);
|
||||
DivDataErrors readInsDataNew(SafeReader& reader, short version, bool fui, DivSong* song);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ void DivMacroStruct::prepare(DivInstrumentMacro& source, DivEngine* e) {
|
|||
has=had=actualHad=will=true;
|
||||
mode=source.mode;
|
||||
type=(source.open>>1)&3;
|
||||
linger=(source.name=="vol" && e->song.volMacroLinger);
|
||||
activeRelease=source.open&8;
|
||||
linger=(source.macroType==DIV_MACRO_VOL && e->song.volMacroLinger);
|
||||
lfoPos=LFO_PHASE;
|
||||
}
|
||||
|
||||
|
|
@ -57,6 +58,10 @@ void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tic
|
|||
return;
|
||||
}
|
||||
if (released && type==1 && lastPos<3) delay=0;
|
||||
if (released && type==0 && pos<source.rel && source.rel<source.len && activeRelease) {
|
||||
delay=0;
|
||||
pos=source.rel;
|
||||
}
|
||||
if (delay>0) {
|
||||
delay--;
|
||||
if (!linger) had=false;
|
||||
|
|
@ -419,108 +424,58 @@ void DivMacroInt::notifyInsDeletion(DivInstrument* which) {
|
|||
}
|
||||
}
|
||||
|
||||
// randomly-generated
|
||||
constexpr unsigned int hashTable[256]={
|
||||
0x0718657, 0xe904eb33, 0x14b2da2b, 0x0ef67ca9,
|
||||
0x0f0559a, 0x4142065a, 0x4d9ab4ba, 0x3cdd601a,
|
||||
0x6635aca, 0x2c41ab72, 0xf98e8d31, 0x1003ee63,
|
||||
0x3fd9fb5, 0x30734d16, 0xe8964431, 0x29bb9b79,
|
||||
0x817f580, 0xfe083b9e, 0x974b5e85, 0x3b5729c2,
|
||||
0x2afea96, 0xf1573b4b, 0x308a1024, 0xaa94b92d,
|
||||
0x693fa93, 0x547ba3da, 0xac4f206c, 0x93f72ea9,
|
||||
0xcc44001, 0x37e27670, 0xf35a63d0, 0xd1cdbb92,
|
||||
0x7c7ee24, 0xfa267ee9, 0xf9cd9956, 0x6a6768d4,
|
||||
0x9e6a108, 0xf6ca4bd0, 0xa53cba9f, 0x526a523a,
|
||||
0xf46f0c8, 0xf131bd4c, 0x82800d48, 0xabff9214,
|
||||
0x40eabd4, 0xea0ef8f7, 0xdc3968d6, 0x54c3cb63,
|
||||
0x8855023, 0xaab73861, 0xff0bea2c, 0x139b9765,
|
||||
0x4a21279, 0x6b2aa29a, 0xf147cc3f, 0xc42edc1a,
|
||||
0xfe2f86f, 0x6d352047, 0xd3cac3e4, 0x35e5c389,
|
||||
0xe923727, 0x12fe3b32, 0x204295c5, 0x254a8b7a,
|
||||
0xc1d995d, 0x26a512d2, 0xa3e34033, 0x9a968df0,
|
||||
0x53447ed, 0x36cf4077, 0x189b03a7, 0x558790e8,
|
||||
0x01f921a, 0x840f260c, 0x93dd2b86, 0x12f69cb0,
|
||||
0x117d93a, 0xcb2cbc2b, 0xd41e3aed, 0x5ff6ec75,
|
||||
0x607290d, 0xd41adb92, 0x64f94ba7, 0xaff720f7,
|
||||
0x6bf1d5d, 0xc8e36c6d, 0x7095bab5, 0xdfbf7b0d,
|
||||
0x01ddeea, 0xe8f262da, 0xf589512f, 0xc2ecac5d,
|
||||
0xbe29d98, 0xff8b5a2e, 0x18e7279e, 0x6ad24dcb,
|
||||
0x2b3b9b1, 0x6f5227d8, 0x076d7553, 0x6c5856e2,
|
||||
0x995f655, 0xe9fcf5a6, 0x83671b70, 0xaf3aed1e,
|
||||
0xac340f0, 0x5c7008b4, 0x14651282, 0x8bf855b9,
|
||||
0x4a933af, 0x829b87f1, 0x9a673070, 0xb19da64f,
|
||||
0x77d8f36, 0x584c9fdc, 0xa9e52c0d, 0x6da5e13d,
|
||||
0xae1051f, 0xe85e976f, 0xfeac2d9a, 0x19c46754,
|
||||
0x1cba6f3, 0xaf21bc31, 0x16b6a8d4, 0xe08b0fdb,
|
||||
0x97e6e54, 0x5da499ae, 0xab472e19, 0xc2491f2e,
|
||||
0xc08c563, 0xe91b131b, 0xc8e22451, 0x6995c8fe,
|
||||
0x7042718, 0x01043738, 0xc7d88b28, 0x2d9f330f,
|
||||
0x4b3aae5, 0xf1e705ba, 0xc5b8ee59, 0xa8ba4e8f,
|
||||
0x55f65a2, 0xa1899e41, 0x296243c8, 0x1e502bf2,
|
||||
0x20080de, 0x841d2239, 0x37b082af, 0xbdd7f7da,
|
||||
0x4075090, 0x1dc7dc49, 0x5cd3c69a, 0x7fb13b62,
|
||||
0xb382bf1, 0xa0cfbc2f, 0x9eca4dc1, 0xb9355453,
|
||||
0x5d0dd24, 0x834f4d8e, 0xe9b136b2, 0xe7b8738d,
|
||||
0x1c91d41, 0x8cb3ddb5, 0xdc600590, 0x607cff55,
|
||||
0x2ca7675, 0x4622a8e4, 0x9340e414, 0xcb44928a,
|
||||
0xa9e791c, 0x68849920, 0xc5b5fcd8, 0xbc352269,
|
||||
0x3ab13cf, 0xaa3cbbd0, 0x1abacc64, 0x623b5b49,
|
||||
0xcc8c4c3, 0x3c8f2f70, 0x3e584a28, 0x9316d24d,
|
||||
0xfe315a2, 0x10f0ba7a, 0xed15a523, 0x4f987369,
|
||||
0x7aa4a4a, 0x90eaf98f, 0xcf0af610, 0x1b38f4e7,
|
||||
0x19df72d, 0xd8306808, 0xd54e25ac, 0x76b79c6d,
|
||||
0x58110cf, 0x06a3e5f2, 0x873a6039, 0xf52684e3,
|
||||
0xecf39c3, 0x7cbb2759, 0xe280d361, 0x91e8471a,
|
||||
0xa67cdd3, 0x17cac3be, 0xfc9eff1f, 0x71abdf49,
|
||||
0x6168624, 0xb68f86f7, 0x67a8e72a, 0xe746911d,
|
||||
0xca48fd7, 0x8f3cc436, 0x3a3851a8, 0x30a7e26e,
|
||||
0xca49308, 0xb598ef74, 0x49ef167a, 0xa9e17632,
|
||||
0x0f7308a, 0xf156efed, 0xcf799645, 0xbae4b85a,
|
||||
0xecba3fe, 0xd97f861d, 0xc164af62, 0xb1aca42f,
|
||||
0xf249576, 0x83d1bf4e, 0x2f486a9c, 0xd3b53cc2,
|
||||
0x17d7c26, 0xd95ddae1, 0x76c1a2f5, 0xf8af6782,
|
||||
0xdbaece4, 0x010b2b53, 0x049be200, 0xd9fd0d1a,
|
||||
0x37d7e6c, 0x5b848651, 0x203c98c7, 0x669681b0,
|
||||
0x683086f, 0xdd0ee8ab, 0x5dbe008b, 0xe5d0690d,
|
||||
0x23dd758, 0x6b34acbc, 0x4b2b3e65, 0xcc7b56c1,
|
||||
0x196b0a0, 0x7b065105, 0xb731b01a, 0xd37daa16,
|
||||
0xf77816b, 0x3c9fa546, 0x81dfadb8, 0x39b1fb8b
|
||||
};
|
||||
#define CONSIDER(x,y) case (y&0x1f): return &x; break;
|
||||
|
||||
constexpr unsigned int NAME_HASH(const char* name) {
|
||||
unsigned int nameHash=0xffffffff;
|
||||
for (const char* i=name; *i; i++) {
|
||||
nameHash=(nameHash>>8)^hashTable[(unsigned char)*i];
|
||||
DivMacroStruct* DivMacroInt::structByType(unsigned char type) {
|
||||
if (type>=0x20) {
|
||||
unsigned char o=((type>>5)-1)&3;
|
||||
switch (type&0x1f) {
|
||||
CONSIDER(op[o].am,DIV_MACRO_OP_AM)
|
||||
CONSIDER(op[o].ar,DIV_MACRO_OP_AR)
|
||||
CONSIDER(op[o].dr,DIV_MACRO_OP_DR)
|
||||
CONSIDER(op[o].mult,DIV_MACRO_OP_MULT)
|
||||
CONSIDER(op[o].rr,DIV_MACRO_OP_RR)
|
||||
CONSIDER(op[o].sl,DIV_MACRO_OP_SL)
|
||||
CONSIDER(op[o].tl,DIV_MACRO_OP_TL)
|
||||
CONSIDER(op[o].dt2,DIV_MACRO_OP_DT2)
|
||||
CONSIDER(op[o].rs,DIV_MACRO_OP_RS)
|
||||
CONSIDER(op[o].dt,DIV_MACRO_OP_DT)
|
||||
CONSIDER(op[o].d2r,DIV_MACRO_OP_D2R)
|
||||
CONSIDER(op[o].ssg,DIV_MACRO_OP_SSG)
|
||||
CONSIDER(op[o].dam,DIV_MACRO_OP_DAM)
|
||||
CONSIDER(op[o].dvb,DIV_MACRO_OP_DVB)
|
||||
CONSIDER(op[o].egt,DIV_MACRO_OP_EGT)
|
||||
CONSIDER(op[o].ksl,DIV_MACRO_OP_KSL)
|
||||
CONSIDER(op[o].sus,DIV_MACRO_OP_SUS)
|
||||
CONSIDER(op[o].vib,DIV_MACRO_OP_VIB)
|
||||
CONSIDER(op[o].ws,DIV_MACRO_OP_WS)
|
||||
CONSIDER(op[o].ksr,DIV_MACRO_OP_KSR)
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
return nameHash;
|
||||
}
|
||||
|
||||
#define CONSIDER(x) case NAME_HASH(#x): return &x; break;
|
||||
|
||||
DivMacroStruct* DivMacroInt::structByName(const String& name) {
|
||||
unsigned int hash=NAME_HASH(name.c_str());
|
||||
|
||||
switch (hash) {
|
||||
CONSIDER(vol)
|
||||
CONSIDER(arp)
|
||||
CONSIDER(duty)
|
||||
CONSIDER(wave)
|
||||
CONSIDER(pitch)
|
||||
CONSIDER(ex1)
|
||||
CONSIDER(ex2)
|
||||
CONSIDER(ex3)
|
||||
CONSIDER(alg)
|
||||
CONSIDER(fb)
|
||||
CONSIDER(fms)
|
||||
CONSIDER(ams)
|
||||
CONSIDER(panL)
|
||||
CONSIDER(panR)
|
||||
CONSIDER(phaseReset)
|
||||
CONSIDER(ex4)
|
||||
CONSIDER(ex5)
|
||||
CONSIDER(ex6)
|
||||
CONSIDER(ex7)
|
||||
CONSIDER(ex8)
|
||||
switch (type) {
|
||||
CONSIDER(vol,DIV_MACRO_VOL)
|
||||
CONSIDER(arp,DIV_MACRO_ARP)
|
||||
CONSIDER(duty,DIV_MACRO_DUTY)
|
||||
CONSIDER(wave,DIV_MACRO_WAVE)
|
||||
CONSIDER(pitch,DIV_MACRO_PITCH)
|
||||
CONSIDER(ex1,DIV_MACRO_EX1)
|
||||
CONSIDER(ex2,DIV_MACRO_EX2)
|
||||
CONSIDER(ex3,DIV_MACRO_EX3)
|
||||
CONSIDER(alg,DIV_MACRO_ALG)
|
||||
CONSIDER(fb,DIV_MACRO_FB)
|
||||
CONSIDER(fms,DIV_MACRO_FMS)
|
||||
CONSIDER(ams,DIV_MACRO_AMS)
|
||||
CONSIDER(panL,DIV_MACRO_PAN_LEFT)
|
||||
CONSIDER(panR,DIV_MACRO_PAN_RIGHT)
|
||||
CONSIDER(phaseReset,DIV_MACRO_PHASE_RESET)
|
||||
CONSIDER(ex4,DIV_MACRO_EX4)
|
||||
CONSIDER(ex5,DIV_MACRO_EX5)
|
||||
CONSIDER(ex6,DIV_MACRO_EX6)
|
||||
CONSIDER(ex7,DIV_MACRO_EX7)
|
||||
CONSIDER(ex8,DIV_MACRO_EX8)
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -27,8 +27,9 @@ class DivEngine;
|
|||
struct DivMacroStruct {
|
||||
int pos, lastPos, lfoPos, delay;
|
||||
int val;
|
||||
bool has, had, actualHad, finished, will, linger, began, masked;
|
||||
bool has, had, actualHad, finished, will, linger, began, masked, activeRelease;
|
||||
unsigned int mode, type;
|
||||
unsigned char macroType;
|
||||
void doMacro(DivInstrumentMacro& source, bool released, bool tick);
|
||||
void init() {
|
||||
pos=lastPos=lfoPos=mode=type=delay=0;
|
||||
|
|
@ -39,7 +40,7 @@ struct DivMacroStruct {
|
|||
val=0;
|
||||
}
|
||||
void prepare(DivInstrumentMacro& source, DivEngine* e);
|
||||
DivMacroStruct():
|
||||
DivMacroStruct(unsigned char mType):
|
||||
pos(0),
|
||||
lastPos(0),
|
||||
lfoPos(0),
|
||||
|
|
@ -53,8 +54,10 @@ struct DivMacroStruct {
|
|||
linger(false),
|
||||
began(true),
|
||||
masked(false),
|
||||
activeRelease(false),
|
||||
mode(0),
|
||||
type(0) {}
|
||||
type(0),
|
||||
macroType(mType) {}
|
||||
};
|
||||
|
||||
class DivMacroInt {
|
||||
|
|
@ -81,26 +84,26 @@ class DivMacroInt {
|
|||
DivMacroStruct dam, dvb, egt, ksl;
|
||||
DivMacroStruct sus, vib, ws, ksr;
|
||||
IntOp():
|
||||
am(),
|
||||
ar(),
|
||||
dr(),
|
||||
mult(),
|
||||
rr(),
|
||||
sl(),
|
||||
tl(),
|
||||
dt2(),
|
||||
rs(),
|
||||
dt(),
|
||||
d2r(),
|
||||
ssg(),
|
||||
dam(),
|
||||
dvb(),
|
||||
egt(),
|
||||
ksl(),
|
||||
sus(),
|
||||
vib(),
|
||||
ws(),
|
||||
ksr() {}
|
||||
am(DIV_MACRO_OP_AM),
|
||||
ar(DIV_MACRO_OP_AR),
|
||||
dr(DIV_MACRO_OP_DR),
|
||||
mult(DIV_MACRO_OP_MULT),
|
||||
rr(DIV_MACRO_OP_RR),
|
||||
sl(DIV_MACRO_OP_SL),
|
||||
tl(DIV_MACRO_OP_TL),
|
||||
dt2(DIV_MACRO_OP_DT2),
|
||||
rs(DIV_MACRO_OP_RS),
|
||||
dt(DIV_MACRO_OP_DT),
|
||||
d2r(DIV_MACRO_OP_D2R),
|
||||
ssg(DIV_MACRO_OP_SSG),
|
||||
dam(DIV_MACRO_OP_DAM),
|
||||
dvb(DIV_MACRO_OP_DVB),
|
||||
egt(DIV_MACRO_OP_EGT),
|
||||
ksl(DIV_MACRO_OP_KSL),
|
||||
sus(DIV_MACRO_OP_SUS),
|
||||
vib(DIV_MACRO_OP_VIB),
|
||||
ws(DIV_MACRO_OP_WS),
|
||||
ksr(DIV_MACRO_OP_KSR) {}
|
||||
} op[4];
|
||||
|
||||
// state
|
||||
|
|
@ -140,11 +143,11 @@ class DivMacroInt {
|
|||
void notifyInsDeletion(DivInstrument* which);
|
||||
|
||||
/**
|
||||
* get DivMacroStruct by macro name.
|
||||
* @param which the macro name.
|
||||
* get DivMacroStruct by macro type.
|
||||
* @param which the macro type.
|
||||
* @return a DivMacroStruct, or NULL if none found.
|
||||
*/
|
||||
DivMacroStruct* structByName(const String& name);
|
||||
DivMacroStruct* structByType(unsigned char which);
|
||||
|
||||
DivMacroInt():
|
||||
e(NULL),
|
||||
|
|
@ -152,26 +155,26 @@ class DivMacroInt {
|
|||
macroListLen(0),
|
||||
subTick(1),
|
||||
released(false),
|
||||
vol(),
|
||||
arp(),
|
||||
duty(),
|
||||
wave(),
|
||||
pitch(),
|
||||
ex1(),
|
||||
ex2(),
|
||||
ex3(),
|
||||
alg(),
|
||||
fb(),
|
||||
fms(),
|
||||
ams(),
|
||||
panL(),
|
||||
panR(),
|
||||
phaseReset(),
|
||||
ex4(),
|
||||
ex5(),
|
||||
ex6(),
|
||||
ex7(),
|
||||
ex8(),
|
||||
vol(DIV_MACRO_VOL),
|
||||
arp(DIV_MACRO_ARP),
|
||||
duty(DIV_MACRO_DUTY),
|
||||
wave(DIV_MACRO_WAVE),
|
||||
pitch(DIV_MACRO_PITCH),
|
||||
ex1(DIV_MACRO_EX1),
|
||||
ex2(DIV_MACRO_EX2),
|
||||
ex3(DIV_MACRO_EX3),
|
||||
alg(DIV_MACRO_ALG),
|
||||
fb(DIV_MACRO_FB),
|
||||
fms(DIV_MACRO_FMS),
|
||||
ams(DIV_MACRO_AMS),
|
||||
panL(DIV_MACRO_PAN_LEFT),
|
||||
panR(DIV_MACRO_PAN_RIGHT),
|
||||
phaseReset(DIV_MACRO_PHASE_RESET),
|
||||
ex4(DIV_MACRO_EX4),
|
||||
ex5(DIV_MACRO_EX5),
|
||||
ex6(DIV_MACRO_EX6),
|
||||
ex7(DIV_MACRO_EX7),
|
||||
ex8(DIV_MACRO_EX8),
|
||||
hasRelease(false) {
|
||||
memset(macroList,0,128*sizeof(void*));
|
||||
memset(macroSource,0,128*sizeof(void*));
|
||||
|
|
|
|||
23
src/engine/pitchTable.cpp
Normal file
23
src/engine/pitchTable.cpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "dispatch.h"
|
||||
|
||||
|
||||
|
||||
|
|
@ -37,6 +37,14 @@ unsigned short DivDispatch::getPan(int chan) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
DivChannelPair DivDispatch::getPaired(int chan) {
|
||||
return DivChannelPair();
|
||||
}
|
||||
|
||||
DivChannelModeHints DivDispatch::getModeHints(int chan) {
|
||||
return DivChannelModeHints();
|
||||
}
|
||||
|
||||
DivMacroInt* DivDispatch::getChanMacroInt(int chan) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -191,6 +199,9 @@ void DivDispatch::renderSamples(int sysID) {
|
|||
|
||||
}
|
||||
|
||||
void DivDispatch::notifyPitchTable() {
|
||||
}
|
||||
|
||||
int DivDispatch::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -271,6 +271,14 @@ void DivPlatformC140::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
switch (bankType) {
|
||||
case 0:
|
||||
bank=((bank&8)<<2)|(bank&7);
|
||||
break;
|
||||
case 1:
|
||||
bank=((bank&0x18)<<1)|(bank&7);
|
||||
break;
|
||||
}
|
||||
rWrite(0x04+(i<<4),bank);
|
||||
}
|
||||
rWrite(0x06+(i<<4),(start>>8)&0xff);
|
||||
|
|
@ -548,7 +556,15 @@ const void* DivPlatformC140::getSampleMem(int index) {
|
|||
}
|
||||
|
||||
size_t DivPlatformC140::getSampleMemCapacity(int index) {
|
||||
return index == 0 ? (is219?524288:16777216) : 0;
|
||||
if (index!=0) return 0;
|
||||
if (is219) return 524288;
|
||||
switch (bankType) {
|
||||
case 0:
|
||||
return 2097152;
|
||||
case 1:
|
||||
return 4194304;
|
||||
}
|
||||
return 16777216;
|
||||
}
|
||||
|
||||
size_t DivPlatformC140::getSampleMemUsage(int index) {
|
||||
|
|
@ -562,7 +578,7 @@ bool DivPlatformC140::isSampleLoaded(int index, int sample) {
|
|||
}
|
||||
|
||||
void DivPlatformC140::renderSamples(int sysID) {
|
||||
memset(sampleMem,0,getSampleMemCapacity());
|
||||
memset(sampleMem,0,is219?524288:16777216);
|
||||
memset(sampleOff,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
|
||||
|
|
@ -701,6 +717,10 @@ void DivPlatformC140::setFlags(const DivConfig& flags) {
|
|||
CHECK_CUSTOM_CLOCK;
|
||||
rate=chipClock/192;
|
||||
}
|
||||
bankType=flags.getInt("bankType",0);
|
||||
if (!is219) {
|
||||
c140_bank_type(&c140,bankType);
|
||||
}
|
||||
for (int i=0; i<totalChans; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
|
|
@ -710,12 +730,13 @@ int DivPlatformC140::init(DivEngine* p, int channels, int sugRate, const DivConf
|
|||
parent=p;
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
bankType=2;
|
||||
|
||||
for (int i=0; i<totalChans; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
}
|
||||
sampleMem=new unsigned char[getSampleMemCapacity()];
|
||||
sampleMem=new unsigned char[is219?524288:16777216];
|
||||
sampleMemLen=0;
|
||||
if (is219) {
|
||||
c219_init(&c219);
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ class DivPlatformC140: public DivDispatch {
|
|||
bool is219;
|
||||
int totalChans;
|
||||
unsigned char groupBank[4];
|
||||
unsigned char bankType;
|
||||
|
||||
unsigned char* sampleMem;
|
||||
size_t sampleMemLen;
|
||||
|
|
|
|||
|
|
@ -1057,7 +1057,11 @@ DivMacroInt* DivPlatformES5506::getChanMacroInt(int ch) {
|
|||
}
|
||||
|
||||
unsigned short DivPlatformES5506::getPan(int ch) {
|
||||
return ((chan[ch].lVol>>4)<<8)|(chan[ch].rVol>>4);
|
||||
float expL=255.0f*pow(((float)(chan[ch].resLVol>>4))/4095.0f,4.0f);
|
||||
float expR=255.0f*pow(((float)(chan[ch].resRVol>>4))/4095.0f,4.0f);
|
||||
if (expL>255.0f) expL=255.0f;
|
||||
if (expR>255.0f) expR=255.0f;
|
||||
return (((unsigned int)expL)<<8)|((unsigned int)expR);
|
||||
}
|
||||
|
||||
void DivPlatformES5506::reset() {
|
||||
|
|
|
|||
|
|
@ -343,6 +343,10 @@ void DivPlatformNES::tick(bool sysTick) {
|
|||
} else {
|
||||
rWrite(0x4010,calcDPCMRate(dacRate)|(goingToLoop?0x40:0));
|
||||
}
|
||||
if (nextDPCMDelta>=0) {
|
||||
rWrite(0x4011,nextDPCMDelta);
|
||||
nextDPCMDelta=-1;
|
||||
}
|
||||
rWrite(0x4012,(dpcmAddr>>6)&0xff);
|
||||
rWrite(0x4013,dpcmLen&0xff);
|
||||
rWrite(0x4015,31);
|
||||
|
|
@ -373,11 +377,38 @@ int DivPlatformNES::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON:
|
||||
if (c.chan==4) { // PCM
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_STD);
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_NES);
|
||||
if (ins->type==DIV_INS_AMIGA || (ins->type==DIV_INS_NES && !parent->song.oldDPCM)) {
|
||||
if (ins->type==DIV_INS_NES) {
|
||||
if (!dpcmMode) {
|
||||
dpcmMode=true;
|
||||
if (dumpWrites) addWrite(0xffff0002,0);
|
||||
dacSample=-1;
|
||||
rWrite(0x4015,15);
|
||||
rWrite(0x4010,0);
|
||||
rWrite(0x4012,0);
|
||||
rWrite(0x4013,0);
|
||||
rWrite(0x4015,31);
|
||||
}
|
||||
|
||||
if (ins->amiga.useNoteMap) {
|
||||
nextDPCMFreq=ins->amiga.getDPCMFreq(c.value);
|
||||
if (nextDPCMFreq<0 || nextDPCMFreq>15) nextDPCMFreq=lastDPCMFreq;
|
||||
lastDPCMFreq=nextDPCMFreq;
|
||||
nextDPCMDelta=ins->amiga.getDPCMDelta(c.value);
|
||||
} else {
|
||||
if (c.value==DIV_NOTE_NULL) {
|
||||
nextDPCMFreq=lastDPCMFreq;
|
||||
} else {
|
||||
nextDPCMFreq=c.value&15;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
dacSample=ins->amiga.getSample(c.value);
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
}
|
||||
}
|
||||
if (dacSample<0 || dacSample>=parent->song.sampleLen) {
|
||||
dacSample=-1;
|
||||
|
|
@ -452,7 +483,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
|
||||
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_NES));
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
|
|
@ -614,7 +645,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
|
|||
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_STD));
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_NES));
|
||||
}
|
||||
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
|
||||
chan[c.chan].inPorta=c.value;
|
||||
|
|
@ -700,6 +731,8 @@ void DivPlatformNES::reset() {
|
|||
goingToLoop=false;
|
||||
countMode=false;
|
||||
nextDPCMFreq=-1;
|
||||
nextDPCMDelta=-1;
|
||||
lastDPCMFreq=15;
|
||||
linearCount=255;
|
||||
|
||||
if (useNP) {
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ class DivPlatformNES: public DivDispatch {
|
|||
unsigned char apuType;
|
||||
unsigned char linearCount;
|
||||
signed char nextDPCMFreq;
|
||||
signed char nextDPCMDelta;
|
||||
signed char lastDPCMFreq;
|
||||
bool dpcmMode;
|
||||
bool dpcmModeDefault;
|
||||
bool dacAntiClickOn;
|
||||
|
|
|
|||
|
|
@ -1582,6 +1582,15 @@ unsigned short DivPlatformOPL::getPan(int ch) {
|
|||
return ((chan[ch].pan&1)<<8)|((chan[ch].pan&2)>>1);
|
||||
}
|
||||
|
||||
DivChannelPair DivPlatformOPL::getPaired(int ch) {
|
||||
if (oplType==3 && ch<12 && !(ch&1)) {
|
||||
if (chan[ch].fourOp) {
|
||||
return DivChannelPair("4OP",ch+1);
|
||||
}
|
||||
}
|
||||
return DivChannelPair();
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformOPL::getOscBuffer(int ch) {
|
||||
if (oplType==759 || chipType==8950) {
|
||||
if (ch>=totalChans+1) return NULL;
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ class DivPlatformOPL: public DivDispatch {
|
|||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
unsigned short getPan(int chan);
|
||||
DivChannelPair getPaired(int chan);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -406,6 +406,24 @@ DivMacroInt* DivPlatformPOKEY::getChanMacroInt(int ch) {
|
|||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivChannelPair DivPlatformPOKEY::getPaired(int ch) {
|
||||
switch (ch) {
|
||||
case 0:
|
||||
if (audctl&4) return DivChannelPair("filter",2);
|
||||
break;
|
||||
case 1:
|
||||
if (audctl&16) return DivChannelPair("16-bit",0);
|
||||
break;
|
||||
case 2:
|
||||
if (audctl&8) return DivChannelPair("16-bit",3);
|
||||
break;
|
||||
case 3:
|
||||
if (audctl&2) return DivChannelPair("filter",1);
|
||||
break;
|
||||
}
|
||||
return DivChannelPair();
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformPOKEY::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ class DivPlatformPOKEY: public DivDispatch {
|
|||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivChannelPair getPaired(int chan);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -472,7 +472,7 @@ int DivPlatformSNES::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_SNES_INVERT:
|
||||
chan[c.chan].invertL=(c.value>>4);
|
||||
chan[c.chan].invertR=c.chan&15;
|
||||
chan[c.chan].invertR=c.value&15;
|
||||
chan[c.chan].shallWriteVol=true;
|
||||
break;
|
||||
case DIV_CMD_SNES_GAIN_MODE:
|
||||
|
|
@ -703,6 +703,13 @@ unsigned short DivPlatformSNES::getPan(int ch) {
|
|||
return (chan[ch].panL<<8)|chan[ch].panR;
|
||||
}
|
||||
|
||||
DivChannelPair DivPlatformSNES::getPaired(int ch) {
|
||||
if (chan[ch].pitchMod) {
|
||||
return DivChannelPair("mod",(ch-1)&7);
|
||||
}
|
||||
return DivChannelPair();
|
||||
}
|
||||
|
||||
DivSamplePos DivPlatformSNES::getSamplePos(int ch) {
|
||||
if (ch>=8) return DivSamplePos();
|
||||
if (!chan[ch].active) return DivSamplePos();
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ class DivPlatformSNES: public DivDispatch {
|
|||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
unsigned short getPan(int chan);
|
||||
DivChannelPair getPaired(int chan);
|
||||
DivSamplePos getSamplePos(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
|
|
|
|||
|
|
@ -333,6 +333,11 @@ void c219_reset(struct c219_t *c219)
|
|||
}
|
||||
}
|
||||
|
||||
// TILDEARROW
|
||||
void c140_bank_type(struct c140_t *c140, unsigned char type) {
|
||||
c140->bank_type = type;
|
||||
}
|
||||
|
||||
void c140_write(struct c140_t *c140, const unsigned short addr, const unsigned char data)
|
||||
{
|
||||
// voice register
|
||||
|
|
@ -345,7 +350,16 @@ void c140_write(struct c140_t *c140, const unsigned short addr, const unsigned c
|
|||
case 0x1: voice->lvol = data; break;
|
||||
case 0x2: voice->freq = (voice->freq & ~0xff00) | (unsigned int)(data << 8); break;
|
||||
case 0x3: voice->freq = (voice->freq & ~0x00ff) | data; break;
|
||||
case 0x4: voice->bank = data; break;
|
||||
case 0x4: { // TILDEARROW
|
||||
if (c140->bank_type == 0) {
|
||||
voice->bank = ((data&0x20)>>2)|(data&7);
|
||||
} else if (c140->bank_type == 1) {
|
||||
voice->bank = ((data&0x30)>>1)|(data&7);
|
||||
} else {
|
||||
voice->bank = data;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x5:
|
||||
voice->compressed = c140_bit(data, 3);
|
||||
voice->loop = c140_bit(data, 4);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
MODIFIED Namco C140/C219 sound emulator - MODIFIED VERSION
|
||||
by cam900
|
||||
|
||||
MODIFICATION by tildearrow - adds muting function
|
||||
MODIFICATION by tildearrow - adds muting function AND VGM banking
|
||||
THIS IS NOT THE ORIGINAL VERSION - you can find the original one in
|
||||
commit 72d04777c013988ed8cf6da27c62a9d784a59dff
|
||||
|
||||
|
|
@ -78,6 +78,7 @@ struct c140_t
|
|||
signed int lout, rout;
|
||||
signed short mulaw[256];
|
||||
signed short *sample_mem;
|
||||
unsigned char bank_type;
|
||||
};
|
||||
|
||||
struct c219_t
|
||||
|
|
@ -106,6 +107,8 @@ void c140_write(struct c140_t *c140, const unsigned short addr, const unsigned c
|
|||
|
||||
void c219_write(struct c219_t *c219, const unsigned short addr, const unsigned char data);
|
||||
|
||||
void c140_bank_type(struct c140_t *c140, unsigned char type);
|
||||
|
||||
void c140_init(struct c140_t *c140);
|
||||
|
||||
void c219_init(struct c219_t *c219);
|
||||
|
|
|
|||
|
|
@ -447,6 +447,7 @@ void DivPlatformSoundUnit::forceIns() {
|
|||
chWrite(i,0x03,chan[i].pan);
|
||||
writeControl(i);
|
||||
writeControlUpper(i);
|
||||
chWrite(i,0x08,chan[i].duty);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -591,8 +591,10 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
chan[i].scheduledSlideReset=true;
|
||||
}
|
||||
dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF_ENV,i));
|
||||
chan[i].releasing=true;
|
||||
} else if (pat->data[whatRow][0]==102) { // env release
|
||||
dispatchCmd(DivCommand(DIV_CMD_ENV_RELEASE,i));
|
||||
chan[i].releasing=true;
|
||||
} else if (!(pat->data[whatRow][0]==0 && pat->data[whatRow][1]==0)) {
|
||||
chan[i].oldNote=chan[i].note;
|
||||
chan[i].note=pat->data[whatRow][0]+((signed char)pat->data[whatRow][1])*12;
|
||||
|
|
@ -1067,6 +1069,10 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
}
|
||||
} else if (!chan[i].noteOnInhibit) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,i,chan[i].note,chan[i].volume>>8));
|
||||
chan[i].releasing=false;
|
||||
if (song.resetArpPhaseOnNewNote) {
|
||||
chan[i].arpStage=-1;
|
||||
}
|
||||
chan[i].goneThroughNote=true;
|
||||
chan[i].wentThroughNote=true;
|
||||
keyHit[i]=true;
|
||||
|
|
@ -1366,6 +1372,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
//dispatchCmd(DivCommand(DIV_CMD_VOLUME,note.channel,(note.volume*(chan[note.channel].volMax>>8))/127));
|
||||
dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,note.channel,note.note));
|
||||
keyHit[note.channel]=true;
|
||||
chan[note.channel].releasing=false;
|
||||
chan[note.channel].noteOnInhibit=true;
|
||||
chan[note.channel].lastIns=note.ins;
|
||||
} else {
|
||||
|
|
@ -1604,7 +1611,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
}
|
||||
if (totalTicks>=1000000) {
|
||||
totalTicks-=1000000;
|
||||
totalSeconds++;
|
||||
if (totalSeconds<0x7fffffff) totalSeconds++;
|
||||
cmdsPerSecond=totalCmds-lastCmds;
|
||||
lastCmds=totalCmds;
|
||||
}
|
||||
|
|
@ -1856,7 +1863,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
output->midiIn->queue.pop();
|
||||
}
|
||||
|
||||
// process audio
|
||||
// process sample/wave preview
|
||||
if ((sPreview.sample>=0 && sPreview.sample<(int)song.sample.size()) || (sPreview.wave>=0 && sPreview.wave<(int)song.wave.size())) {
|
||||
unsigned int samp_bbOff=0;
|
||||
unsigned int prevAvail=blip_samples_avail(samp_bb);
|
||||
|
|
@ -2003,7 +2010,9 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
memset(samp_bbOut,0,size*sizeof(short));
|
||||
}
|
||||
|
||||
if (playing && !halted) {
|
||||
// process audio
|
||||
bool mustPlay=playing && !halted;
|
||||
if (mustPlay) {
|
||||
// logic starts here
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
// TODO: we may have a problem here
|
||||
|
|
@ -2132,6 +2141,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
renderPool->wait();
|
||||
}
|
||||
|
||||
// process metronome
|
||||
if (metroBufLen<size || metroBuf==NULL) {
|
||||
if (metroBuf!=NULL) delete[] metroBuf;
|
||||
metroBuf=new float[size];
|
||||
|
|
@ -2140,7 +2150,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
|
||||
memset(metroBuf,0,metroBufLen*sizeof(float));
|
||||
|
||||
if (playing && !halted && metronome) {
|
||||
if (mustPlay && metronome) {
|
||||
for (size_t i=0; i<size; i++) {
|
||||
if (metroTick[i]) {
|
||||
if (metroTick[i]==2) {
|
||||
|
|
@ -2222,6 +2232,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
// nothing/invalid
|
||||
}
|
||||
|
||||
// dump to oscillator buffer
|
||||
for (unsigned int i=0; i<size; i++) {
|
||||
for (int j=0; j<outChans; j++) {
|
||||
if (oscBuf[j]==NULL) continue;
|
||||
|
|
@ -2231,6 +2242,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
}
|
||||
oscSize=size;
|
||||
|
||||
// force mono audio (if enabled)
|
||||
if (forceMono && outChans>1) {
|
||||
for (size_t i=0; i<size; i++) {
|
||||
float chanSum=out[0][i];
|
||||
|
|
@ -2243,6 +2255,8 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clamp output (if enabled)
|
||||
if (clampSamples) {
|
||||
for (size_t i=0; i<size; i++) {
|
||||
for (int j=0; j<outChans; j++) {
|
||||
|
|
|
|||
|
|
@ -377,6 +377,8 @@ struct DivSong {
|
|||
bool brokenPortaLegato;
|
||||
bool brokenFMOff;
|
||||
bool preNoteNoEffect;
|
||||
bool oldDPCM;
|
||||
bool resetArpPhaseOnNewNote;
|
||||
|
||||
std::vector<DivInstrument*> ins;
|
||||
std::vector<DivWavetable*> wave;
|
||||
|
|
@ -496,7 +498,9 @@ struct DivSong {
|
|||
patchbayAuto(true),
|
||||
brokenPortaLegato(false),
|
||||
brokenFMOff(false),
|
||||
preNoteNoEffect(false) {
|
||||
preNoteNoEffect(false),
|
||||
oldDPCM(false),
|
||||
resetArpPhaseOnNewNote(false) {
|
||||
for (int i=0; i<DIV_MAX_CHIPS; i++) {
|
||||
system[i]=DIV_SYSTEM_NULL;
|
||||
systemVol[i]=1.0;
|
||||
|
|
|
|||
|
|
@ -674,7 +674,7 @@ void DivEngine::registerSystems() {
|
|||
|
||||
sysDefs[DIV_SYSTEM_PCE]=new DivSysDef(
|
||||
"PC Engine/TurboGrafx-16", NULL, 0x05, 0x05, 6, false, true, 0x161, false, 1U<<DIV_SAMPLE_DEPTH_8BIT,
|
||||
"an '80's game console with a wavetable sound chip, popular in Japan.",
|
||||
"an '80s game console with a wavetable sound chip, popular in Japan.",
|
||||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6"},
|
||||
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6"},
|
||||
{DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE},
|
||||
|
|
@ -691,12 +691,12 @@ void DivEngine::registerSystems() {
|
|||
|
||||
sysDefs[DIV_SYSTEM_NES]=new DivSysDef(
|
||||
"NES (Ricoh 2A03)", NULL, 0x06, 0x06, 5, false, true, 0x161, false, (1U<<DIV_SAMPLE_DEPTH_1BIT_DPCM)|(1U<<DIV_SAMPLE_DEPTH_8BIT),
|
||||
"also known as Famicom in Japan, it's the most well-known game console of the '80's.",
|
||||
"also known as Famicom in Japan, it's the most well-known game console of the '80s.",
|
||||
{"Pulse 1", "Pulse 2", "Triangle", "Noise", "DPCM"},
|
||||
{"S1", "S2", "TR", "NO", "DMC"},
|
||||
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_WAVE, DIV_CH_NOISE, DIV_CH_PCM},
|
||||
{DIV_INS_NES, DIV_INS_NES, DIV_INS_NES, DIV_INS_NES, DIV_INS_AMIGA},
|
||||
{},
|
||||
{DIV_INS_NES, DIV_INS_NES, DIV_INS_NES, DIV_INS_NES, DIV_INS_NES},
|
||||
{DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA},
|
||||
{
|
||||
{0x11, {DIV_CMD_NES_DMC, "11xx: Write to delta modulation counter (0 to 7F)"}},
|
||||
{0x12, {DIV_CMD_STD_NOISE_MODE, "12xx: Set duty cycle/noise mode (pulse: 0 to 3; noise: 0 or 1)"}},
|
||||
|
|
@ -792,7 +792,7 @@ void DivEngine::registerSystems() {
|
|||
|
||||
sysDefs[DIV_SYSTEM_AMIGA]=new DivSysDef(
|
||||
"Amiga", NULL, 0x81, 0, 4, false, true, 0, false, 1U<<DIV_SAMPLE_DEPTH_8BIT,
|
||||
"a computer from the '80's with full sampling capabilities, giving it a sound ahead of its time.",
|
||||
"a computer from the '80s with full sampling capabilities, giving it a sound ahead of its time.",
|
||||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4"},
|
||||
{"CH1", "CH2", "CH3", "CH4"},
|
||||
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
||||
|
|
@ -1617,7 +1617,7 @@ void DivEngine::registerSystems() {
|
|||
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM},
|
||||
{DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_ADPCMB},
|
||||
{DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_AMIGA},
|
||||
fmEffectHandlerMap,
|
||||
fmOPLDrumsEffectHandlerMap,
|
||||
fmOPLPostEffectHandlerMap
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1834,6 +1834,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
CHIP_VOL(40,1.0);
|
||||
willExport[i]=true;
|
||||
writeC140[0]=disCont[i].dispatch;
|
||||
c140Type=(song.systemFlags[i].getInt("bankType",0)==1)?1:0;
|
||||
} else if (!(hasC140&0x40000000)) {
|
||||
isSecond[i]=true;
|
||||
CHIP_VOL_SECOND(40,1.0);
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ void DivEngine::runExportThread() {
|
|||
if (lastLoopPos>-1 && i>=lastLoopPos && totalLoops>=exportLoopCount) {
|
||||
logD("start fading out...");
|
||||
isFadingOut=true;
|
||||
if (fadeOutSamples==0) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -197,6 +198,7 @@ void DivEngine::runExportThread() {
|
|||
if (lastLoopPos>-1 && j>=lastLoopPos && totalLoops>=exportLoopCount) {
|
||||
logD("start fading out...");
|
||||
isFadingOut=true;
|
||||
if (fadeOutSamples==0) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -239,7 +241,6 @@ void DivEngine::runExportThread() {
|
|||
outBuf[0]=new float[EXPORT_BUFSIZE];
|
||||
outBuf[1]=new float[EXPORT_BUFSIZE];
|
||||
outBuf[2]=new float[EXPORT_BUFSIZE*2];
|
||||
int loopCount=remainingLoops;
|
||||
|
||||
logI("rendering to files...");
|
||||
|
||||
|
|
@ -281,11 +282,7 @@ void DivEngine::runExportThread() {
|
|||
lastLoopPos=-1;
|
||||
totalLoops=0;
|
||||
isFadingOut=false;
|
||||
if (exportFadeOut<=0.01) {
|
||||
remainingLoops=loopCount;
|
||||
} else {
|
||||
remainingLoops=-1;
|
||||
}
|
||||
remainingLoops=-1;
|
||||
playSub(false);
|
||||
|
||||
while (playing) {
|
||||
|
|
@ -311,6 +308,7 @@ void DivEngine::runExportThread() {
|
|||
if (lastLoopPos>-1 && j>=lastLoopPos && totalLoops>=exportLoopCount) {
|
||||
logD("start fading out...");
|
||||
isFadingOut=true;
|
||||
if (fadeOutSamples==0) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -399,11 +397,7 @@ bool DivEngine::saveAudio(const char* path, int loops, DivAudioExportModes mode,
|
|||
stop();
|
||||
repeatPattern=false;
|
||||
setOrder(0);
|
||||
if (exportFadeOut<=0.01) {
|
||||
remainingLoops=loops;
|
||||
} else {
|
||||
remainingLoops=-1;
|
||||
}
|
||||
remainingLoops=-1;
|
||||
|
||||
if (shallSwitchCores()) {
|
||||
bool isMutedBefore[DIV_MAX_CHANS];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue