dev106 - Game Boy: implement hw seq
and prepare for software envelope maybe
This commit is contained in:
parent
da8f7dabd5
commit
28698beaf3
1
TODO.md
1
TODO.md
|
@ -1,6 +1,5 @@
|
|||
# to-do for 0.6pre1.5-0.6pre2
|
||||
|
||||
- Game Boy envelope macro/sequence
|
||||
- volume commands should work on Game Boy
|
||||
- ability to customize `OFF`, `===` and `REL`
|
||||
- stereo separation control for AY
|
||||
|
|
|
@ -32,7 +32,8 @@ these fields are 0 in format versions prior to 100 (0.6pre1).
|
|||
|
||||
the format versions are:
|
||||
|
||||
- 105: Furance dev105
|
||||
- 106: Furnace dev106
|
||||
- 105: Furnace dev105
|
||||
- 104: Furnace dev104
|
||||
- 103: Furnace dev103
|
||||
- 102: Furnace 0.6pre1 (dev102)
|
||||
|
@ -846,6 +847,9 @@ size | description
|
|||
| - 2 bytes: nothing
|
||||
| - for loop/loop until release:
|
||||
| - 2 bytes: position
|
||||
--- | **Game Boy extra flags** (>=106)
|
||||
1 | use software envelope
|
||||
1 | always init hard env on new note
|
||||
```
|
||||
|
||||
# wavetable
|
||||
|
|
|
@ -45,8 +45,8 @@
|
|||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||
|
||||
#define DIV_VERSION "dev105"
|
||||
#define DIV_ENGINE_VERSION 105
|
||||
#define DIV_VERSION "dev106"
|
||||
#define DIV_ENGINE_VERSION 106
|
||||
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
|
|
|
@ -539,6 +539,10 @@ void DivInstrument::putInsData(SafeWriter* w) {
|
|||
w->writeS(gb.hwSeq[i].data);
|
||||
}
|
||||
|
||||
// GB additional flags
|
||||
w->writeC(gb.softEnv);
|
||||
w->writeC(gb.alwaysInit);
|
||||
|
||||
blockEndSeek=w->tell();
|
||||
w->seek(blockStartSeek,SEEK_SET);
|
||||
w->writeI(blockEndSeek-blockStartSeek-4);
|
||||
|
@ -1101,6 +1105,12 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) {
|
|||
}
|
||||
}
|
||||
|
||||
// GB additional flags
|
||||
if (version>=106) {
|
||||
gb.softEnv=reader.readC();
|
||||
gb.alwaysInit=reader.readC();
|
||||
}
|
||||
|
||||
return DIV_DATA_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -262,6 +262,7 @@ struct DivInstrumentSTD {
|
|||
|
||||
struct DivInstrumentGB {
|
||||
unsigned char envVol, envDir, envLen, soundLen, hwSeqLen;
|
||||
bool softEnv, alwaysInit;
|
||||
enum HWSeqCommands: unsigned char {
|
||||
DIV_GB_HWCMD_ENVELOPE=0,
|
||||
DIV_GB_HWCMD_SWEEP,
|
||||
|
@ -281,7 +282,9 @@ struct DivInstrumentGB {
|
|||
envDir(0),
|
||||
envLen(2),
|
||||
soundLen(64),
|
||||
hwSeqLen(0) {
|
||||
hwSeqLen(0),
|
||||
softEnv(false),
|
||||
alwaysInit(false) {
|
||||
memset(hwSeq,0,256*sizeof(int));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -233,12 +233,61 @@ void DivPlatformGB::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
}
|
||||
// run hardware sequence
|
||||
if (chan[i].active) {
|
||||
if (--chan[i].hwSeqDelay<=0) {
|
||||
chan[i].hwSeqDelay=0;
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_GB);
|
||||
int hwSeqCount=0;
|
||||
while (chan[i].hwSeqPos<ins->gb.hwSeqLen && hwSeqCount<4) {
|
||||
bool leave=false;
|
||||
unsigned short data=ins->gb.hwSeq[chan[i].hwSeqPos].data;
|
||||
switch (ins->gb.hwSeq[chan[i].hwSeqPos].cmd) {
|
||||
case DivInstrumentGB::DIV_GB_HWCMD_ENVELOPE:
|
||||
chan[i].envLen=data&7;
|
||||
chan[i].envDir=(data&8)?1:0;
|
||||
chan[i].envVol=(data>>4)&15;
|
||||
chan[i].soundLen=data>>8;
|
||||
chan[i].keyOn=true;
|
||||
break;
|
||||
case DivInstrumentGB::DIV_GB_HWCMD_SWEEP:
|
||||
chan[i].sweep=data;
|
||||
chan[i].sweepChanged=true;
|
||||
break;
|
||||
case DivInstrumentGB::DIV_GB_HWCMD_WAIT:
|
||||
chan[i].hwSeqDelay=data+1;
|
||||
leave=true;
|
||||
break;
|
||||
case DivInstrumentGB::DIV_GB_HWCMD_WAIT_REL:
|
||||
if (!chan[i].released) {
|
||||
chan[i].hwSeqPos--;
|
||||
leave=true;
|
||||
}
|
||||
break;
|
||||
case DivInstrumentGB::DIV_GB_HWCMD_LOOP:
|
||||
chan[i].hwSeqPos=data-1;
|
||||
break;
|
||||
case DivInstrumentGB::DIV_GB_HWCMD_LOOP_REL:
|
||||
if (!chan[i].released) {
|
||||
chan[i].hwSeqPos=data-1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
chan[i].hwSeqPos++;
|
||||
if (leave) break;
|
||||
hwSeqCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].sweepChanged) {
|
||||
chan[i].sweepChanged=false;
|
||||
if (i==0) {
|
||||
rWrite(16+i*5,chan[i].sweep);
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
if (i==3) { // noise
|
||||
int ntPos=chan[i].baseFreq;
|
||||
|
@ -300,6 +349,9 @@ int DivPlatformGB::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].hwSeqPos=0;
|
||||
chan[c.chan].hwSeqDelay=0;
|
||||
chan[c.chan].released=false;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (c.chan==2) {
|
||||
if (chan[c.chan].wave<0) {
|
||||
|
@ -308,7 +360,7 @@ int DivPlatformGB::dispatch(DivCommand c) {
|
|||
}
|
||||
ws.init(ins,32,15,chan[c.chan].insChanged);
|
||||
}
|
||||
if (chan[c.chan].insChanged) {
|
||||
if (chan[c.chan].insChanged || ins->gb.alwaysInit) {
|
||||
chan[c.chan].envVol=ins->gb.envVol;
|
||||
chan[c.chan].envLen=ins->gb.envLen;
|
||||
chan[c.chan].envDir=ins->gb.envDir;
|
||||
|
@ -320,11 +372,14 @@ int DivPlatformGB::dispatch(DivCommand c) {
|
|||
case DIV_CMD_NOTE_OFF:
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].hwSeqPos=0;
|
||||
chan[c.chan].hwSeqDelay=0;
|
||||
chan[c.chan].macroInit(NULL);
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
case DIV_CMD_ENV_RELEASE:
|
||||
chan[c.chan].std.release();
|
||||
chan[c.chan].released=true;
|
||||
break;
|
||||
case DIV_CMD_INSTRUMENT:
|
||||
if (chan[c.chan].ins!=c.value || c.value2==1) {
|
||||
|
|
|
@ -29,10 +29,11 @@ class DivPlatformGB: public DivDispatch {
|
|||
struct Channel {
|
||||
int freq, baseFreq, pitch, pitch2, note, ins;
|
||||
unsigned char duty, sweep;
|
||||
bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta;
|
||||
bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, released;
|
||||
signed char vol, outVol, wave;
|
||||
unsigned char envVol, envDir, envLen, soundLen;
|
||||
unsigned short hwSeqPos, hwSeqDelay;
|
||||
unsigned short hwSeqPos;
|
||||
short hwSeqDelay;
|
||||
DivMacroInt std;
|
||||
void macroInit(DivInstrument* which) {
|
||||
std.init(which);
|
||||
|
@ -54,6 +55,7 @@ class DivPlatformGB: public DivDispatch {
|
|||
keyOn(false),
|
||||
keyOff(false),
|
||||
inPorta(false),
|
||||
released(false),
|
||||
vol(15),
|
||||
outVol(15),
|
||||
wave(-1),
|
||||
|
|
|
@ -2965,6 +2965,10 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
}
|
||||
if (ins->type==DIV_INS_GB) if (ImGui::BeginTabItem("Game Boy")) {
|
||||
P(ImGui::Checkbox("Use software envelope",&ins->gb.softEnv));
|
||||
P(ImGui::Checkbox("Initialize envelope on every note",&ins->gb.alwaysInit));
|
||||
|
||||
ImGui::BeginDisabled(ins->gb.softEnv);
|
||||
P(CWSliderScalar("Volume",ImGuiDataType_U8,&ins->gb.envVol,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
P(CWSliderScalar("Envelope Length",ImGuiDataType_U8,&ins->gb.envLen,&_ZERO,&_SEVEN)); rightClickable
|
||||
P(CWSliderScalar("Sound Length",ImGuiDataType_U8,&ins->gb.soundLen,&_ZERO,&_SIXTY_FOUR,ins->gb.soundLen>63?"Infinity":"%d")); rightClickable
|
||||
|
@ -3060,13 +3064,13 @@ void FurnaceGUI::drawInsEdit() {
|
|||
somethingChanged=true;
|
||||
}
|
||||
|
||||
if (ImGui::RadioButton("Up",hwsDir)) { PARAMETER
|
||||
hwsDir=true;
|
||||
if (ImGui::RadioButton("Up",!hwsDir)) { PARAMETER
|
||||
hwsDir=false;
|
||||
somethingChanged=true;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::RadioButton("Down",!hwsDir)) { PARAMETER
|
||||
hwsDir=false;
|
||||
if (ImGui::RadioButton("Down",hwsDir)) { PARAMETER
|
||||
hwsDir=true;
|
||||
somethingChanged=true;
|
||||
}
|
||||
|
||||
|
@ -3128,6 +3132,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
@ -3689,8 +3694,10 @@ void FurnaceGUI::drawInsEdit() {
|
|||
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU) {
|
||||
volMax=127;
|
||||
}
|
||||
if (ins->type==DIV_INS_GB) {
|
||||
if (ins->type==DIV_INS_GB && !ins->gb.softEnv) {
|
||||
volMax=0;
|
||||
} else {
|
||||
volMax=15;
|
||||
}
|
||||
if (ins->type==DIV_INS_PET || ins->type==DIV_INS_BEEPER) {
|
||||
volMax=1;
|
||||
|
|
Loading…
Reference in New Issue