mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-15 17:25:06 +00:00
implement Furnace format saving
experimental and no loading yet
This commit is contained in:
parent
c43cc0ae80
commit
8d9cddde37
5 changed files with 390 additions and 28 deletions
|
@ -12,7 +12,7 @@ size | description
|
||||||
-----|------------------------------------
|
-----|------------------------------------
|
||||||
16 | "-Furnace module-" format magic
|
16 | "-Furnace module-" format magic
|
||||||
2 | format version
|
2 | format version
|
||||||
| - should be 1 for Furnace 0.2
|
| - should be 15 for Furnace 0.3
|
||||||
2 | reserved
|
2 | reserved
|
||||||
4 | song info pointer
|
4 | song info pointer
|
||||||
8 | reserved
|
8 | reserved
|
||||||
|
@ -22,7 +22,7 @@ size | description
|
||||||
size | description
|
size | description
|
||||||
-----|------------------------------------
|
-----|------------------------------------
|
||||||
4 | "INFO" block ID
|
4 | "INFO" block ID
|
||||||
4 | length of this block
|
4 | reserved
|
||||||
1 | time base
|
1 | time base
|
||||||
1 | speed 1
|
1 | speed 1
|
||||||
1 | speed 2
|
1 | speed 2
|
||||||
|
@ -38,10 +38,9 @@ size | description
|
||||||
2 | wavetable count
|
2 | wavetable count
|
||||||
2 | sample count
|
2 | sample count
|
||||||
4 | pattern count
|
4 | pattern count
|
||||||
1 | sound chip count
|
32 | list of sound chips
|
||||||
31 | list of sound chips
|
|
||||||
| - possible soundchips:
|
| - possible soundchips:
|
||||||
| - 0x00: invalid - 0 channels
|
| - 0x00: end of list
|
||||||
| - 0x01: YMU759 - 17 channels
|
| - 0x01: YMU759 - 17 channels
|
||||||
| - 0x02: Genesis - 10 channels
|
| - 0x02: Genesis - 10 channels
|
||||||
| - 0x03: SMS (SN76489) - 4 channels
|
| - 0x03: SMS (SN76489) - 4 channels
|
||||||
|
@ -55,10 +54,13 @@ size | description
|
||||||
| - 0x42: Genesis extended - 13 channels
|
| - 0x42: Genesis extended - 13 channels
|
||||||
| - 0x47: C64 (6581) - 3 channels
|
| - 0x47: C64 (6581) - 3 channels
|
||||||
| - 0x49: Neo Geo extended - 16 channels
|
| - 0x49: Neo Geo extended - 16 channels
|
||||||
4 | reserved
|
32 | sound chip volumes
|
||||||
124 | sound chip parameters (TODO)
|
| - signed char, 64=1.0, 127=~2.0
|
||||||
4 | pointer song name
|
32 | sound chip panning
|
||||||
4 | pointer to song author
|
| - signed char, -128=left, 127=right
|
||||||
|
128 | sound chip parameters (TODO)
|
||||||
|
??? | song name
|
||||||
|
??? | song author
|
||||||
24 | reserved for compatibility flags
|
24 | reserved for compatibility flags
|
||||||
4?? | pointers to instruments
|
4?? | pointers to instruments
|
||||||
4?? | pointers to wavetables
|
4?? | pointers to wavetables
|
||||||
|
@ -67,6 +69,7 @@ size | description
|
||||||
??? | orders
|
??? | orders
|
||||||
| - a table of shorts
|
| - a table of shorts
|
||||||
| - size=channels*ordLen
|
| - size=channels*ordLen
|
||||||
|
| - read orders than channels
|
||||||
??? | effect columns
|
??? | effect columns
|
||||||
| - size=channels
|
| - size=channels
|
||||||
|
|
||||||
|
@ -75,7 +78,7 @@ size | description
|
||||||
size | description
|
size | description
|
||||||
-----|------------------------------------
|
-----|------------------------------------
|
||||||
4 | "INST" block ID
|
4 | "INST" block ID
|
||||||
4 | length of this block
|
4 | reserved
|
||||||
2 | format version (see header)
|
2 | format version (see header)
|
||||||
1 | instrument type
|
1 | instrument type
|
||||||
| - 0: standard
|
| - 0: standard
|
||||||
|
@ -84,7 +87,7 @@ size | description
|
||||||
| - 3: C64
|
| - 3: C64
|
||||||
| - 4: Amiga/sample
|
| - 4: Amiga/sample
|
||||||
1 | reserved
|
1 | reserved
|
||||||
4 | pointer to instrument name
|
??? | instrument name
|
||||||
--- | **FM instrument data**
|
--- | **FM instrument data**
|
||||||
1 | alg
|
1 | alg
|
||||||
1 | feedback
|
1 | feedback
|
||||||
|
@ -166,8 +169,8 @@ size | description
|
||||||
size | description
|
size | description
|
||||||
-----|------------------------------------
|
-----|------------------------------------
|
||||||
4 | "WAVE" block ID
|
4 | "WAVE" block ID
|
||||||
4 | length of this block
|
4 | reserved
|
||||||
4 | pointer to wavetable name
|
??? | wavetable name
|
||||||
4 | wavetable size
|
4 | wavetable size
|
||||||
4 | wavetable min
|
4 | wavetable min
|
||||||
4 | wavetable max
|
4 | wavetable max
|
||||||
|
@ -178,8 +181,8 @@ size | description
|
||||||
size | description
|
size | description
|
||||||
-----|------------------------------------
|
-----|------------------------------------
|
||||||
4 | "SMPL" block ID
|
4 | "SMPL" block ID
|
||||||
4 | length of this block
|
4 | reserved
|
||||||
4 | pointer to sample name
|
??? | sample name
|
||||||
4 | length
|
4 | length
|
||||||
4 | rate
|
4 | rate
|
||||||
2 | volume
|
2 | volume
|
||||||
|
@ -193,7 +196,7 @@ size | description
|
||||||
size | description
|
size | description
|
||||||
-----|------------------------------------
|
-----|------------------------------------
|
||||||
4 | "PATR" block ID
|
4 | "PATR" block ID
|
||||||
4 | length of this block
|
4 | reserved
|
||||||
2 | channel
|
2 | channel
|
||||||
2 | pattern index
|
2 | pattern index
|
||||||
4 | reserved
|
4 | reserved
|
||||||
|
|
|
@ -532,6 +532,13 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
||||||
} else {
|
} else {
|
||||||
ins->mode=reader.readC();
|
ins->mode=reader.readC();
|
||||||
}
|
}
|
||||||
|
ins->type=ins->mode?DIV_INS_FM:DIV_INS_STD;
|
||||||
|
if (ds.system[0]==DIV_SYSTEM_GB) {
|
||||||
|
ins->type=DIV_INS_GB;
|
||||||
|
}
|
||||||
|
if (ds.system[0]==DIV_SYSTEM_C64_8580 || ds.system[0]==DIV_SYSTEM_C64_6581) {
|
||||||
|
ins->type=DIV_INS_C64;
|
||||||
|
}
|
||||||
|
|
||||||
if (ins->mode) { // FM
|
if (ins->mode) { // FM
|
||||||
if (!isFMSystem(ds.system[0])) {
|
if (!isFMSystem(ds.system[0])) {
|
||||||
|
@ -1018,6 +1025,333 @@ bool DivEngine::load(unsigned char* f, size_t slen) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SafeWriter* DivEngine::saveFur() {
|
||||||
|
int insPtr[256];
|
||||||
|
int wavePtr[256];
|
||||||
|
int samplePtr[256];
|
||||||
|
std::vector<int> patPtr;
|
||||||
|
size_t ptrSeek;
|
||||||
|
|
||||||
|
// fail if this is an YMU759 song
|
||||||
|
if (song.system[0]==DIV_SYSTEM_YMU759) {
|
||||||
|
logE("cannot save YMU759 song!\n");
|
||||||
|
lastError="YMU759 song saving is not supported";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeWriter* w=new SafeWriter;
|
||||||
|
w->init();
|
||||||
|
/// HEADER
|
||||||
|
// write magic
|
||||||
|
w->write(DIV_FUR_MAGIC,16);
|
||||||
|
|
||||||
|
// write version
|
||||||
|
w->writeS(DIV_ENGINE_VERSION);
|
||||||
|
|
||||||
|
// reserved
|
||||||
|
w->writeS(0);
|
||||||
|
|
||||||
|
// song info pointer
|
||||||
|
w->writeI(32);
|
||||||
|
|
||||||
|
// reserved
|
||||||
|
w->writeI(0);
|
||||||
|
w->writeI(0);
|
||||||
|
|
||||||
|
// high short is channel
|
||||||
|
// low short is pattern number
|
||||||
|
std::vector<int> patsToWrite;
|
||||||
|
bool alreadyAdded[256];
|
||||||
|
for (int i=0; i<chans; i++) {
|
||||||
|
memset(alreadyAdded,0,256*sizeof(bool));
|
||||||
|
for (int j=0; j<song.ordersLen; j++) {
|
||||||
|
if (alreadyAdded[song.orders.ord[i][j]]) continue;
|
||||||
|
patsToWrite.push_back((i<<16)|song.orders.ord[i][j]);
|
||||||
|
alreadyAdded[song.orders.ord[i][j]]=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SONG INFO
|
||||||
|
w->write("INFO",4);
|
||||||
|
w->writeI(0);
|
||||||
|
|
||||||
|
w->writeC(song.timeBase);
|
||||||
|
w->writeC(song.speed1);
|
||||||
|
w->writeC(song.speed2);
|
||||||
|
w->writeC(song.arpLen);
|
||||||
|
w->writeF(song.hz);
|
||||||
|
w->writeS(song.patLen);
|
||||||
|
w->writeS(song.ordersLen);
|
||||||
|
w->writeC(song.hilightA);
|
||||||
|
w->writeC(song.hilightB);
|
||||||
|
w->writeS(song.insLen);
|
||||||
|
w->writeS(song.waveLen);
|
||||||
|
w->writeS(song.sampleLen);
|
||||||
|
w->writeI(patsToWrite.size());
|
||||||
|
|
||||||
|
for (int i=0; i<32; i++) {
|
||||||
|
if (i>=song.systemLen) {
|
||||||
|
w->writeC(0);
|
||||||
|
} else {
|
||||||
|
w->writeC(systemToFile(song.system[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<32; i++) {
|
||||||
|
// for now
|
||||||
|
w->writeC(64);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<32; i++) {
|
||||||
|
// for now
|
||||||
|
w->writeC(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<32; i++) {
|
||||||
|
// for now
|
||||||
|
w->writeI(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// song name
|
||||||
|
w->writeString(song.name,false);
|
||||||
|
// song author
|
||||||
|
w->writeString(song.author,false);
|
||||||
|
|
||||||
|
// reserved
|
||||||
|
for (int i=0; i<24; i++) {
|
||||||
|
w->writeC(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrSeek=w->tell();
|
||||||
|
// instrument pointers (we'll seek here later)
|
||||||
|
for (int i=0; i<song.insLen; i++) {
|
||||||
|
w->writeI(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// wavetable pointers (we'll seek here later)
|
||||||
|
for (int i=0; i<song.waveLen; i++) {
|
||||||
|
w->writeI(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sample pointers (we'll seek here later)
|
||||||
|
for (int i=0; i<song.sampleLen; i++) {
|
||||||
|
w->writeI(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// pattern pointers (we'll seek here later)
|
||||||
|
for (size_t i=0; i<patsToWrite.size(); i++) {
|
||||||
|
w->writeI(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<chans; i++) {
|
||||||
|
for (int j=0; j<song.ordersLen; j++) {
|
||||||
|
w->writeC(song.orders.ord[i][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<chans; i++) {
|
||||||
|
w->writeC(song.pat[i].effectRows);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// INSTRUMENT
|
||||||
|
for (int i=0; i<song.insLen; i++) {
|
||||||
|
DivInstrument* ins=song.ins[i];
|
||||||
|
insPtr[i]=w->tell();
|
||||||
|
w->write("INST",4);
|
||||||
|
w->writeI(0);
|
||||||
|
|
||||||
|
w->writeS(DIV_ENGINE_VERSION);
|
||||||
|
|
||||||
|
w->writeC(ins->type);
|
||||||
|
w->writeC(0);
|
||||||
|
|
||||||
|
w->writeString(ins->name,false);
|
||||||
|
|
||||||
|
// FM
|
||||||
|
w->writeC(ins->fm.alg);
|
||||||
|
w->writeC(ins->fm.fb);
|
||||||
|
w->writeC(ins->fm.fms);
|
||||||
|
w->writeC(ins->fm.ams);
|
||||||
|
w->writeC(4); // operator count; always 4
|
||||||
|
w->writeC(0); // reserved
|
||||||
|
w->writeC(0);
|
||||||
|
w->writeC(0);
|
||||||
|
|
||||||
|
for (int j=0; j<4; j++) {
|
||||||
|
DivInstrumentFM::Operator& op=ins->fm.op[j];
|
||||||
|
w->writeC(op.am);
|
||||||
|
w->writeC(op.ar);
|
||||||
|
w->writeC(op.dr);
|
||||||
|
w->writeC(op.mult);
|
||||||
|
w->writeC(op.rr);
|
||||||
|
w->writeC(op.sl);
|
||||||
|
w->writeC(op.tl);
|
||||||
|
w->writeC(op.dt2);
|
||||||
|
w->writeC(op.rs);
|
||||||
|
w->writeC(op.dt);
|
||||||
|
w->writeC(op.d2r);
|
||||||
|
w->writeC(op.ssgEnv);
|
||||||
|
|
||||||
|
w->writeC(op.dam);
|
||||||
|
w->writeC(op.dvb);
|
||||||
|
w->writeC(op.egt);
|
||||||
|
w->writeC(op.ksl);
|
||||||
|
w->writeC(op.sus);
|
||||||
|
w->writeC(op.vib);
|
||||||
|
w->writeC(op.ws);
|
||||||
|
w->writeC(op.ksr);
|
||||||
|
|
||||||
|
// reserved
|
||||||
|
for (int k=0; k<12; k++) {
|
||||||
|
w->writeC(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GB
|
||||||
|
w->writeC(ins->gb.envVol);
|
||||||
|
w->writeC(ins->gb.envDir);
|
||||||
|
w->writeC(ins->gb.envLen);
|
||||||
|
w->writeC(ins->gb.soundLen);
|
||||||
|
|
||||||
|
// C64
|
||||||
|
w->writeC(ins->c64.triOn);
|
||||||
|
w->writeC(ins->c64.sawOn);
|
||||||
|
w->writeC(ins->c64.pulseOn);
|
||||||
|
w->writeC(ins->c64.noiseOn);
|
||||||
|
w->writeC(ins->c64.a);
|
||||||
|
w->writeC(ins->c64.d);
|
||||||
|
w->writeC(ins->c64.s);
|
||||||
|
w->writeC(ins->c64.r);
|
||||||
|
w->writeS((ins->c64.duty*4096)/100);
|
||||||
|
w->writeC(ins->c64.ringMod);
|
||||||
|
w->writeC(ins->c64.oscSync);
|
||||||
|
w->writeC(ins->c64.toFilter);
|
||||||
|
w->writeC(ins->c64.initFilter);
|
||||||
|
w->writeC(ins->c64.volIsCutoff);
|
||||||
|
w->writeC(ins->c64.res);
|
||||||
|
w->writeC(ins->c64.lp);
|
||||||
|
w->writeC(ins->c64.bp);
|
||||||
|
w->writeC(ins->c64.hp);
|
||||||
|
w->writeC(ins->c64.ch3off);
|
||||||
|
w->writeS((ins->c64.cut*2047)/100);
|
||||||
|
w->writeC(ins->c64.dutyIsAbs);
|
||||||
|
w->writeC(ins->c64.filterIsAbs);
|
||||||
|
|
||||||
|
// Amiga
|
||||||
|
w->writeS(ins->amiga.initSample);
|
||||||
|
for (int j=0; j<14; j++) { // reserved
|
||||||
|
w->writeC(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// standard
|
||||||
|
w->writeI(ins->std.volMacroLen);
|
||||||
|
w->writeI(ins->std.arpMacroLen);
|
||||||
|
w->writeI(ins->std.dutyMacroLen);
|
||||||
|
w->writeI(ins->std.waveMacroLen);
|
||||||
|
w->writeI(ins->std.volMacroLoop);
|
||||||
|
w->writeI(ins->std.arpMacroLoop);
|
||||||
|
w->writeI(ins->std.dutyMacroLoop);
|
||||||
|
w->writeI(ins->std.waveMacroLoop);
|
||||||
|
w->writeC(ins->std.arpMacroMode);
|
||||||
|
w->writeC(0); // reserved
|
||||||
|
w->writeC(0);
|
||||||
|
w->writeC(0);
|
||||||
|
for (int j=0; j<ins->std.volMacroLen; j++) {
|
||||||
|
w->writeI(ins->std.volMacro[j]);
|
||||||
|
}
|
||||||
|
for (int j=0; j<ins->std.arpMacroLen; j++) {
|
||||||
|
w->writeI(ins->std.arpMacro[j]);
|
||||||
|
}
|
||||||
|
for (int j=0; j<ins->std.dutyMacroLen; j++) {
|
||||||
|
w->writeI(ins->std.dutyMacro[j]);
|
||||||
|
}
|
||||||
|
for (int j=0; j<ins->std.waveMacroLen; j++) {
|
||||||
|
w->writeI(ins->std.waveMacro[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// WAVETABLE
|
||||||
|
for (int i=0; i<song.waveLen; i++) {
|
||||||
|
DivWavetable* wave=song.wave[i];
|
||||||
|
wavePtr[i]=w->tell();
|
||||||
|
w->write("WAVE",4);
|
||||||
|
w->writeI(0);
|
||||||
|
|
||||||
|
w->writeC(0); // name
|
||||||
|
w->writeI(wave->len);
|
||||||
|
w->writeI(wave->min);
|
||||||
|
w->writeI(wave->max);
|
||||||
|
for (int j=0; j<wave->len; j++) {
|
||||||
|
w->writeI(wave->data[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SAMPLE
|
||||||
|
for (int i=0; i<song.sampleLen; i++) {
|
||||||
|
DivSample* sample=song.sample[i];
|
||||||
|
samplePtr[i]=w->tell();
|
||||||
|
w->write("SMPL",4);
|
||||||
|
w->writeI(0);
|
||||||
|
|
||||||
|
w->writeString(sample->name,false);
|
||||||
|
w->writeI(sample->length);
|
||||||
|
w->writeI(sample->rate);
|
||||||
|
w->writeS(sample->vol);
|
||||||
|
w->writeS(sample->pitch);
|
||||||
|
w->writeC(sample->depth);
|
||||||
|
for (int j=0; j<7; j++) { // reserved
|
||||||
|
w->writeC(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
w->write(sample->data,sample->length*2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// PATTERN
|
||||||
|
for (int i: patsToWrite) {
|
||||||
|
DivPattern* pat=song.pat[i>>16].getPattern(i&0xffff,false);
|
||||||
|
patPtr.push_back(w->tell());
|
||||||
|
w->write("PATR",4);
|
||||||
|
w->writeI(0);
|
||||||
|
|
||||||
|
w->writeS(i>>16);
|
||||||
|
w->writeS(i&0xffff);
|
||||||
|
|
||||||
|
w->writeI(0); // reserved
|
||||||
|
|
||||||
|
for (int j=0; j<song.patLen; j++) {
|
||||||
|
w->writeS(pat->data[j][0]); // note
|
||||||
|
w->writeS(pat->data[j][1]); // octave
|
||||||
|
w->writeS(pat->data[j][2]); // instrument
|
||||||
|
w->writeS(pat->data[j][3]); // volume
|
||||||
|
w->write(&pat->data[j][4],2*song.pat[i>>16].effectRows*2); // effects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// POINTERS
|
||||||
|
w->seek(ptrSeek,SEEK_SET);
|
||||||
|
|
||||||
|
for (int i=0; i<song.insLen; i++) {
|
||||||
|
w->writeI(insPtr[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// wavetable pointers (we'll seek here later)
|
||||||
|
for (int i=0; i<song.waveLen; i++) {
|
||||||
|
w->writeI(wavePtr[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sample pointers (we'll seek here later)
|
||||||
|
for (int i=0; i<song.sampleLen; i++) {
|
||||||
|
w->writeI(samplePtr[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// pattern pointers (we'll seek here later)
|
||||||
|
for (int i: patPtr) {
|
||||||
|
w->writeI(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
SafeWriter* DivEngine::saveDMF() {
|
SafeWriter* DivEngine::saveDMF() {
|
||||||
// fail if more than one system
|
// fail if more than one system
|
||||||
if (song.systemLen!=1) {
|
if (song.systemLen!=1) {
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
#include "../ta-utils.h"
|
#include "../ta-utils.h"
|
||||||
|
|
||||||
enum DivInstrumentType {
|
enum DivInstrumentType {
|
||||||
DIV_INS_FM,
|
DIV_INS_STD=0,
|
||||||
DIV_INS_STD,
|
DIV_INS_FM=1,
|
||||||
DIV_INS_GB,
|
DIV_INS_GB=2,
|
||||||
DIV_INS_C64
|
DIV_INS_C64=3,
|
||||||
|
DIV_INS_AMIGA=4
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DivInstrumentFM {
|
struct DivInstrumentFM {
|
||||||
|
@ -117,7 +118,7 @@ struct DivInstrumentC64 {
|
||||||
unsigned char a, d, s, r;
|
unsigned char a, d, s, r;
|
||||||
unsigned char duty;
|
unsigned char duty;
|
||||||
unsigned char ringMod, oscSync;
|
unsigned char ringMod, oscSync;
|
||||||
bool toFilter, volIsCutoff, initFilter;
|
bool toFilter, volIsCutoff, initFilter, dutyIsAbs, filterIsAbs;
|
||||||
unsigned char res, cut;
|
unsigned char res, cut;
|
||||||
bool hp, lp, bp, ch3off;
|
bool hp, lp, bp, ch3off;
|
||||||
|
|
||||||
|
@ -136,6 +137,8 @@ struct DivInstrumentC64 {
|
||||||
toFilter(false),
|
toFilter(false),
|
||||||
volIsCutoff(false),
|
volIsCutoff(false),
|
||||||
initFilter(false),
|
initFilter(false),
|
||||||
|
dutyIsAbs(false),
|
||||||
|
filterIsAbs(false),
|
||||||
res(0),
|
res(0),
|
||||||
cut(0),
|
cut(0),
|
||||||
hp(false),
|
hp(false),
|
||||||
|
@ -144,6 +147,13 @@ struct DivInstrumentC64 {
|
||||||
ch3off(false) {}
|
ch3off(false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DivInstrumentAmiga {
|
||||||
|
short initSample;
|
||||||
|
|
||||||
|
DivInstrumentAmiga():
|
||||||
|
initSample(0) {}
|
||||||
|
};
|
||||||
|
|
||||||
struct DivInstrument {
|
struct DivInstrument {
|
||||||
String name;
|
String name;
|
||||||
bool mode;
|
bool mode;
|
||||||
|
@ -152,6 +162,7 @@ struct DivInstrument {
|
||||||
DivInstrumentSTD std;
|
DivInstrumentSTD std;
|
||||||
DivInstrumentGB gb;
|
DivInstrumentGB gb;
|
||||||
DivInstrumentC64 c64;
|
DivInstrumentC64 c64;
|
||||||
|
DivInstrumentAmiga amiga;
|
||||||
DivInstrument():
|
DivInstrument():
|
||||||
name(""),
|
name(""),
|
||||||
mode(false),
|
mode(false),
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
struct DivWavetable {
|
struct DivWavetable {
|
||||||
int len;
|
int len, min, max;
|
||||||
int data[32];
|
int data[32];
|
||||||
|
|
||||||
DivWavetable():
|
DivWavetable():
|
||||||
len(32) {
|
len(32),
|
||||||
|
min(0),
|
||||||
|
max(31) {
|
||||||
for (int i=0; i<32; i++) {
|
for (int i=0; i<32; i++) {
|
||||||
data[i]=i;
|
data[i]=i;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2343,10 +2343,10 @@ void FurnaceGUI::keyUp(SDL_Event& ev) {
|
||||||
void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case GUI_FILE_OPEN:
|
case GUI_FILE_OPEN:
|
||||||
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Open File","DefleMask module{.dmf},.*",workingDir);
|
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Open File","Furnace song{.fur},DefleMask module{.dmf},.*",workingDir);
|
||||||
break;
|
break;
|
||||||
case GUI_FILE_SAVE:
|
case GUI_FILE_SAVE:
|
||||||
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Save File","DefleMask module{.dmf}",workingDir);
|
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Save File","Furnace song{.fur},DefleMask module{.dmf}",workingDir);
|
||||||
break;
|
break;
|
||||||
case GUI_FILE_SAMPLE_OPEN:
|
case GUI_FILE_SAMPLE_OPEN:
|
||||||
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Load Sample","Wave file{.wav},.*",workingDir);
|
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Load Sample","Wave file{.wav},.*",workingDir);
|
||||||
|
@ -2366,7 +2366,12 @@ int FurnaceGUI::save(String path) {
|
||||||
lastError=strerror(errno);
|
lastError=strerror(errno);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
SafeWriter* w=e->saveDMF();
|
SafeWriter* w;
|
||||||
|
if (path.rfind(".dmf")==path.size()-4) {
|
||||||
|
w=e->saveDMF();
|
||||||
|
} else {
|
||||||
|
w=e->saveFur();
|
||||||
|
}
|
||||||
if (w==NULL) {
|
if (w==NULL) {
|
||||||
lastError=e->getLastError();
|
lastError=e->getLastError();
|
||||||
fclose(outFile);
|
fclose(outFile);
|
||||||
|
@ -2785,8 +2790,14 @@ bool FurnaceGUI::loop() {
|
||||||
fileName=ImGuiFileDialog::Instance()->GetFilePathName();
|
fileName=ImGuiFileDialog::Instance()->GetFilePathName();
|
||||||
if (fileName!="") {
|
if (fileName!="") {
|
||||||
if (curFileDialog==GUI_FILE_SAVE) {
|
if (curFileDialog==GUI_FILE_SAVE) {
|
||||||
if (fileName.size()<4 || fileName.rfind(".dmf")!=fileName.size()-4) {
|
if (ImGuiFileDialog::Instance()->GetCurrentFilter()=="Furnace song") {
|
||||||
fileName+=".dmf";
|
if (fileName.size()<4 || fileName.rfind(".fur")!=fileName.size()-4) {
|
||||||
|
fileName+=".fur";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (fileName.size()<4 || fileName.rfind(".dmf")!=fileName.size()-4) {
|
||||||
|
fileName+=".dmf";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (curFileDialog==GUI_FILE_SAMPLE_SAVE) {
|
if (curFileDialog==GUI_FILE_SAMPLE_SAVE) {
|
||||||
|
@ -3013,6 +3024,7 @@ bool FurnaceGUI::init() {
|
||||||
|
|
||||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir,"",ImVec4(0.0f,1.0f,1.0f,1.0f),ICON_FA_FOLDER_O);
|
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir,"",ImVec4(0.0f,1.0f,1.0f,1.0f),ICON_FA_FOLDER_O);
|
||||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeFile,"",ImVec4(0.7f,0.7f,0.7f,1.0f),ICON_FA_FILE_O);
|
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeFile,"",ImVec4(0.7f,0.7f,0.7f,1.0f),ICON_FA_FILE_O);
|
||||||
|
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fur",ImVec4(0.5f,1.0f,0.5f,1.0f),ICON_FA_FILE);
|
||||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".dmf",ImVec4(0.5f,1.0f,0.5f,1.0f),ICON_FA_FILE);
|
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".dmf",ImVec4(0.5f,1.0f,0.5f,1.0f),ICON_FA_FILE);
|
||||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".wav",ImVec4(1.0f,1.0f,0.5f,1.0f),ICON_FA_FILE_AUDIO_O);
|
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".wav",ImVec4(1.0f,1.0f,0.5f,1.0f),ICON_FA_FILE_AUDIO_O);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue