Merge branch 'master' of https://github.com/tildearrow/furnace into n163
This commit is contained in:
commit
e8d567d3df
14 changed files with 449 additions and 46 deletions
|
|
@ -38,8 +38,8 @@
|
|||
warnings+=(String("\n")+x); \
|
||||
}
|
||||
|
||||
#define DIV_VERSION "dev69"
|
||||
#define DIV_ENGINE_VERSION 69
|
||||
#define DIV_VERSION "dev70"
|
||||
#define DIV_ENGINE_VERSION 70
|
||||
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
ds.oneTickCut=false;
|
||||
ds.newInsTriggersInPorta=true;
|
||||
ds.arp0Reset=true;
|
||||
ds.brokenSpeedSel=true;
|
||||
|
||||
// 1.1 compat flags
|
||||
if (ds.version>24) {
|
||||
|
|
@ -1067,6 +1068,14 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
ds.masterVol=2.0f;
|
||||
}
|
||||
|
||||
if (ds.version>=70) {
|
||||
// extended compat flags
|
||||
ds.brokenSpeedSel=reader.readC();
|
||||
for (int i=0; i<31; i++) {
|
||||
reader.readC();
|
||||
}
|
||||
}
|
||||
|
||||
// read instruments
|
||||
for (int i=0; i<ds.insLen; i++) {
|
||||
DivInstrument* ins=new DivInstrument;
|
||||
|
|
@ -1905,6 +1914,12 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
|
||||
w->writeF(song.masterVol);
|
||||
|
||||
// extended compat flags
|
||||
w->writeC(song.brokenSpeedSel);
|
||||
for (int i=0; i<31; i++) {
|
||||
w->writeC(0);
|
||||
}
|
||||
|
||||
/// INSTRUMENT
|
||||
for (int i=0; i<song.insLen; i++) {
|
||||
DivInstrument* ins=song.ins[i];
|
||||
|
|
|
|||
|
|
@ -1236,14 +1236,24 @@ void DivEngine::nextRow() {
|
|||
if (haltOn==DIV_HALT_PATTERN) halted=true;
|
||||
}
|
||||
|
||||
if (speedAB) {
|
||||
ticks=speed2*(song.timeBase+1);
|
||||
nextSpeed=speed1;
|
||||
if (song.brokenSpeedSel) {
|
||||
if ((song.patLen&1) && curOrder&1) {
|
||||
ticks=((curRow&1)?speed2:speed1)*(song.timeBase+1);
|
||||
nextSpeed=(curRow&1)?speed1:speed2;
|
||||
} else {
|
||||
ticks=((curRow&1)?speed1:speed2)*(song.timeBase+1);
|
||||
nextSpeed=(curRow&1)?speed2:speed1;
|
||||
}
|
||||
} else {
|
||||
ticks=speed1*(song.timeBase+1);
|
||||
nextSpeed=speed2;
|
||||
if (speedAB) {
|
||||
ticks=speed2*(song.timeBase+1);
|
||||
nextSpeed=speed1;
|
||||
} else {
|
||||
ticks=speed1*(song.timeBase+1);
|
||||
nextSpeed=speed2;
|
||||
}
|
||||
speedAB=!speedAB;
|
||||
}
|
||||
speedAB=!speedAB;
|
||||
|
||||
// post row details
|
||||
for (int i=0; i<chans; i++) {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ extern "C" {
|
|||
#include "../../extern/adpcm/ymz_codec.h"
|
||||
}
|
||||
|
||||
DivSampleHistory::~DivSampleHistory() {
|
||||
if (data!=NULL) delete[] data;
|
||||
}
|
||||
|
||||
bool DivSample::save(const char* path) {
|
||||
SNDFILE* f;
|
||||
SF_INFO si;
|
||||
|
|
@ -258,7 +262,6 @@ bool DivSample::trim(unsigned int begin, unsigned int end) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// TODO: for clipboard
|
||||
bool DivSample::insert(unsigned int pos, unsigned int length) {
|
||||
unsigned int count=samples+length;
|
||||
if (depth==8) {
|
||||
|
|
@ -283,7 +286,12 @@ bool DivSample::insert(unsigned int pos, unsigned int length) {
|
|||
short* oldData16=data16;
|
||||
data16=NULL;
|
||||
initInternal(16,count);
|
||||
memcpy(data16,oldData16,sizeof(short)*count);
|
||||
if (pos>0) {
|
||||
memcpy(data16,oldData16,sizeof(short)*pos);
|
||||
}
|
||||
if (count-pos-length>0) {
|
||||
memcpy(&(data16[pos+length]),&(oldData16[pos]),sizeof(short)*(count-pos-length));
|
||||
}
|
||||
delete[] oldData16;
|
||||
} else {
|
||||
initInternal(16,count);
|
||||
|
|
@ -782,7 +790,92 @@ unsigned int DivSample::getCurBufLen() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) {
|
||||
DivSampleHistory* h;
|
||||
if (data) {
|
||||
unsigned char* duplicate;
|
||||
if (getCurBuf()==NULL) {
|
||||
duplicate=NULL;
|
||||
} else {
|
||||
duplicate=new unsigned char[getCurBufLen()];
|
||||
memcpy(duplicate,getCurBuf(),getCurBufLen());
|
||||
}
|
||||
h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart);
|
||||
} else {
|
||||
h=new DivSampleHistory(depth,rate,centerRate,loopStart);
|
||||
}
|
||||
if (!doNotPush) {
|
||||
while (!redoHist.empty()) {
|
||||
DivSampleHistory* h=redoHist.back();
|
||||
delete h;
|
||||
redoHist.pop_back();
|
||||
}
|
||||
if (undoHist.size()>100) undoHist.pop_front();
|
||||
undoHist.push_back(h);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
#define applyHistory \
|
||||
depth=h->depth; \
|
||||
if (h->hasSample) { \
|
||||
initInternal(h->depth,h->samples); \
|
||||
samples=h->samples; \
|
||||
\
|
||||
if (h->length!=getCurBufLen()) logW("undo buffer length not equal to current buffer length! %d != %d\n",h->length,getCurBufLen()); \
|
||||
\
|
||||
void* buf=getCurBuf(); \
|
||||
\
|
||||
if (buf!=NULL && h->data!=NULL) { \
|
||||
memcpy(buf,h->data,h->length); \
|
||||
} \
|
||||
} \
|
||||
rate=h->rate; \
|
||||
centerRate=h->centerRate; \
|
||||
loopStart=h->loopStart;
|
||||
|
||||
|
||||
int DivSample::undo() {
|
||||
if (undoHist.empty()) return 0;
|
||||
DivSampleHistory* h=undoHist.back();
|
||||
DivSampleHistory* redo=prepareUndo(h->hasSample,true);
|
||||
|
||||
int ret=h->hasSample?2:1;
|
||||
|
||||
applyHistory;
|
||||
|
||||
redoHist.push_back(redo);
|
||||
delete h;
|
||||
undoHist.pop_back();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int DivSample::redo() {
|
||||
if (redoHist.empty()) return 0;
|
||||
DivSampleHistory* h=redoHist.back();
|
||||
DivSampleHistory* undo=prepareUndo(h->hasSample,true);
|
||||
|
||||
int ret=h->hasSample?2:1;
|
||||
|
||||
applyHistory;
|
||||
|
||||
undoHist.push_back(undo);
|
||||
delete h;
|
||||
redoHist.pop_back();
|
||||
return ret;
|
||||
}
|
||||
|
||||
DivSample::~DivSample() {
|
||||
while (!undoHist.empty()) {
|
||||
DivSampleHistory* h=undoHist.back();
|
||||
delete h;
|
||||
undoHist.pop_back();
|
||||
}
|
||||
while (!redoHist.empty()) {
|
||||
DivSampleHistory* h=redoHist.back();
|
||||
delete h;
|
||||
redoHist.pop_back();
|
||||
}
|
||||
if (data8) delete[] data8;
|
||||
if (data16) delete[] data16;
|
||||
if (data1) delete[] data1;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "../ta-utils.h"
|
||||
#include <deque>
|
||||
|
||||
enum DivResampleFilters {
|
||||
DIV_RESAMPLE_NONE=0,
|
||||
|
|
@ -28,6 +29,33 @@ enum DivResampleFilters {
|
|||
DIV_RESAMPLE_BEST
|
||||
};
|
||||
|
||||
struct DivSampleHistory {
|
||||
unsigned char* data;
|
||||
unsigned int length, samples;
|
||||
unsigned char depth;
|
||||
int rate, centerRate, loopStart;
|
||||
bool hasSample;
|
||||
DivSampleHistory(void* d, unsigned int l, unsigned int s, unsigned char de, int r, int cr, int ls):
|
||||
data((unsigned char*)d),
|
||||
length(l),
|
||||
samples(s),
|
||||
depth(de),
|
||||
rate(r),
|
||||
centerRate(cr),
|
||||
loopStart(ls),
|
||||
hasSample(true) {}
|
||||
DivSampleHistory(unsigned char de, int r, int cr, int ls):
|
||||
data(NULL),
|
||||
length(0),
|
||||
samples(0),
|
||||
depth(de),
|
||||
rate(r),
|
||||
centerRate(cr),
|
||||
loopStart(ls),
|
||||
hasSample(false) {}
|
||||
~DivSampleHistory();
|
||||
};
|
||||
|
||||
struct DivSample {
|
||||
String name;
|
||||
int rate, centerRate, loopStart, loopOffP;
|
||||
|
|
@ -62,6 +90,9 @@ struct DivSample {
|
|||
|
||||
unsigned int samples;
|
||||
|
||||
std::deque<DivSampleHistory*> undoHist;
|
||||
std::deque<DivSampleHistory*> redoHist;
|
||||
|
||||
/**
|
||||
* @warning DO NOT USE - internal functions
|
||||
*/
|
||||
|
|
@ -154,6 +185,28 @@ struct DivSample {
|
|||
* @return the sample data length.
|
||||
*/
|
||||
unsigned int getCurBufLen();
|
||||
|
||||
/**
|
||||
* prepare an undo step for this sample.
|
||||
* @param data whether to include sample data.
|
||||
* @param doNotPush if this is true, don't push the DivSampleHistory to the undo history.
|
||||
* @return the undo step.
|
||||
*/
|
||||
DivSampleHistory* prepareUndo(bool data, bool doNotPush=false);
|
||||
|
||||
/**
|
||||
* undo. you may need to call DivEngine::renderSamples afterwards.
|
||||
* @warning do not attempt to undo outside of a synchronized block!
|
||||
* @return 0 on failure; 1 on success and 2 on success (data changed).
|
||||
*/
|
||||
int undo();
|
||||
|
||||
/**
|
||||
* redo. you may need to call DivEngine::renderSamples afterwards.
|
||||
* @warning do not attempt to redo outside of a synchronized block!
|
||||
* @return 0 on failure; 1 on success and 2 on success (data changed).
|
||||
*/
|
||||
int redo();
|
||||
DivSample():
|
||||
name(""),
|
||||
rate(32000),
|
||||
|
|
|
|||
|
|
@ -301,6 +301,7 @@ struct DivSong {
|
|||
bool oneTickCut;
|
||||
bool newInsTriggersInPorta;
|
||||
bool arp0Reset;
|
||||
bool brokenSpeedSel;
|
||||
|
||||
DivOrders orders;
|
||||
std::vector<DivInstrument*> ins;
|
||||
|
|
@ -373,7 +374,8 @@ struct DivSong {
|
|||
brokenDACMode(false),
|
||||
oneTickCut(false),
|
||||
newInsTriggersInPorta(true),
|
||||
arp0Reset(true) {
|
||||
arp0Reset(true),
|
||||
brokenSpeedSel(false) {
|
||||
for (int i=0; i<32; i++) {
|
||||
system[i]=DIV_SYSTEM_NULL;
|
||||
systemVol[i]=64;
|
||||
|
|
|
|||
|
|
@ -924,15 +924,15 @@ const char* chanNames[40][32]={
|
|||
{"Pulse 1", "Pulse 2", "PCM"}, // MMC5
|
||||
{"FM 1", "FM 2", "FM 3", "PSG 1", "PSG 2", "PSG 3"}, // OPN
|
||||
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Square 1", "Square 2", "Square 3", "Kick", "Snare", "Top", "HiHat", "Tom", "Rim", "ADPCM"}, // PC-98
|
||||
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9", "FM 10", "FM 11", "FM 12", "FM 13", "FM 14", "FM 15", "FM 16", "FM 17", "FM 18"}, // OPL3
|
||||
{"4OP 1", "FM 2", "4OP 3", "FM 4", "4OP 5", "FM 6", "4OP 7", "FM 8", "4OP 9", "FM 10", "4OP 11", "FM 12", "FM 13", "FM 14", "FM 15", "FM 16", "FM 17", "FM 18"}, // OPL3
|
||||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16", "Channel 17", "Channel 18", "Channel 19", "Channel 20", "Channel 21", "Channel 22", "Channel 23", "Channel 24", "Channel 25", "Channel 26", "Channel 27", "Channel 28"}, // MultiPCM
|
||||
{"Square"}, // PC Speaker/Pokémon Mini
|
||||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Noise"}, // Virtual Boy/SCC
|
||||
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, // YM2610B
|
||||
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick", "Snare", "Tom", "Top", "HiHat"}, // OPLL/OPL/OPL2 drums
|
||||
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9", "FM 10", "FM 11", "FM 12", "FM 13", "FM 14", "FM 15", "Kick", "Snare", "Tom", "Top", "HiHat"}, // OPL3 drums
|
||||
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "4OP 1", "4OP 2", "4OP 3", "4OP 4", "4OP 5", "4OP 6"}, // OPL3 4-op
|
||||
{"FM 1", "FM 2", "FM 3", "4OP 1", "4OP 2", "4OP 3", "4OP 4", "4OP 5", "4OP 6", "Kick", "Snare", "Tom", "Top", "HiHat"}, // OPL3 4-op + drums
|
||||
{"4OP 1", "FM 2", "4OP 3", "FM 4", "4OP 5", "FM 6", "4OP 7", "FM 8", "4OP 9", "FM 10", "4OP 11", "FM 12", "FM 13", "FM 14", "FM 15", "Kick", "Snare", "Tom", "Top", "HiHat"}, // OPL3 drums
|
||||
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "4OP 1", "4OP 2", "4OP 3", "4OP 4", "4OP 5", "4OP 6"}, // OPL3 4-op (UNUSED)
|
||||
{"FM 1", "FM 2", "FM 3", "4OP 1", "4OP 2", "4OP 3", "4OP 4", "4OP 5", "4OP 6", "Kick", "Snare", "Tom", "Top", "HiHat"}, // OPL3 4-op + drums (UNUSED)
|
||||
{"PCM 1", "PCM 2", "PCM 3", "PCM 4", "PCM 5", "PCM 6", "PCM 7", "PCM 8", "PCM 9", "PCM 10", "PCM 11", "PCM 12", "PCM 13", "PCM 14", "PCM 15", "PCM 16", "ADPCM 1", "ADPCM 2", "ADPCM 3"}, // QSound
|
||||
{"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, // YM2610B (extended channel 3)
|
||||
{"Wave", "Wave/PCM", "Wave", "Wave/Noise"}, // Swan
|
||||
|
|
@ -974,8 +974,8 @@ const char* chanShortNames[38][32]={
|
|||
{"F1", "F2", "F3", "F4", "F5", "F6", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, // YM2610B
|
||||
{"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH"}, // OPLL/OPL/OPL2 drums
|
||||
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "BD", "SD", "TM", "TP", "HH"}, // OPL3 drums
|
||||
{"F1", "F2", "F3", "F4", "F5", "F6", "Q1", "Q2", "Q3", "Q4", "Q5", "Q6"}, // OPL3 4-op
|
||||
{"F1", "F2", "F3", "Q1", "Q2", "Q3", "Q4", "Q5", "Q6", "BD", "SD", "TM", "TP", "HH"}, // OPL3 4-op + drums
|
||||
{"F1", "F2", "F3", "F4", "F5", "F6", "Q1", "Q2", "Q3", "Q4", "Q5", "Q6"}, // OPL3 4-op (UNUSED)
|
||||
{"F1", "F2", "F3", "Q1", "Q2", "Q3", "Q4", "Q5", "Q6", "BD", "SD", "TM", "TP", "HH"}, // OPL3 4-op + drums (UNUSED)
|
||||
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "A1", "A2", "A3"}, // QSound
|
||||
{"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, // YM2610B (extended channel 3)
|
||||
};
|
||||
|
|
@ -1008,15 +1008,15 @@ const int chanTypes[41][32]={
|
|||
{1, 1, 4}, // MMC5
|
||||
{0, 0, 0, 1, 1, 1}, // OPN
|
||||
{0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 4}, // PC-98
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // OPL3
|
||||
{5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 0, 0, 0, 0, 0, 0}, // OPL3
|
||||
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, // MultiPCM/QSound
|
||||
{1}, // PC Speaker/Pokémon Mini
|
||||
{3, 3, 3, 3, 3, 2}, // Virtual Boy/SCC
|
||||
{0, 0, 0, 0, 0, 0, 1, 1, 1, 4, 4, 4, 4, 4, 4, 4}, // YM2610B
|
||||
{0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2}, // OPLL/OPL/OPL2 drums
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2}, // OPL3 drums
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // OPL3 4-op
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2}, // OPL3 4-op + drums
|
||||
{5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 0, 0, 0, 2, 2, 2, 2, 2}, // OPL3 drums
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // OPL3 4-op (UNUSED)
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2}, // OPL3 4-op + drums (UNUSED)
|
||||
{3, 3, 3, 3}, // Lynx
|
||||
{0, 0, 5, 5, 5, 5, 0, 0, 0, 1, 1, 1, 4, 4, 4, 4, 4, 4, 4}, // YM2610B (extended channel 3)
|
||||
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4}, // VERA
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue