start working on ADSR macro mode
This commit is contained in:
parent
2cebd75236
commit
a979bc244d
|
@ -437,6 +437,12 @@ notes:
|
|||
- the entire instrument is stored, regardless of instrument type.
|
||||
- the macro range varies depending on the instrument type.
|
||||
- "macro open" indicates whether the macro is collapsed or not in the instrument editor.
|
||||
- as of format version 120, bit 1-2 indicates macro mode:
|
||||
- 0: sequence (normal)
|
||||
- 1: ADSR
|
||||
- 2: LFO
|
||||
- 3: ADSR+LFO
|
||||
- see sub-section for information on how to interpret parameters.
|
||||
- FM operator order is:
|
||||
- 1/3/2/4 (internal order) for OPN, OPM, OPZ and OPL 4-op
|
||||
- 1/2/?/? (? = unused) for OPL 2-op and OPLL
|
||||
|
@ -1024,6 +1030,33 @@ size | description
|
|||
1 | KSR macro delay
|
||||
```
|
||||
|
||||
## interpreting macro mode values
|
||||
|
||||
- sequence (normal): I think this is obvious...
|
||||
- ADSR:
|
||||
- `val[0]`: bottom
|
||||
- `val[1]`: top
|
||||
- `val[2]`: attack
|
||||
- `val[3]`: hold time
|
||||
- `val[4]`: decay
|
||||
- `val[5]`: sustain level
|
||||
- `val[6]`: sustain hold time
|
||||
- `val[7]`: decay 2
|
||||
- `val[8]`: release
|
||||
- LFO:
|
||||
- `val[9]`: bottom
|
||||
- `val[10]`: top
|
||||
- `val[11]`: speed
|
||||
- `val[12]`: waveform
|
||||
- 0: triangle
|
||||
- 1: sine
|
||||
- 2: saw
|
||||
- 3: pulse
|
||||
- `val[13]`: phase
|
||||
- `val[14]`: loop
|
||||
- `val[15]`: global (not sure how will I implement this)
|
||||
- for ADSR+LFO just interpret both ADSR and LFO params.
|
||||
|
||||
# wavetable
|
||||
|
||||
```
|
||||
|
|
|
@ -47,8 +47,8 @@
|
|||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||
|
||||
#define DIV_VERSION "dev119"
|
||||
#define DIV_ENGINE_VERSION 119
|
||||
#define DIV_VERSION "dev120"
|
||||
#define DIV_ENGINE_VERSION 120
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
#define DIV_VERSION_FC 0xff02
|
||||
|
|
|
@ -177,7 +177,7 @@ struct DivInstrumentMacro {
|
|||
String name;
|
||||
int val[256];
|
||||
unsigned int mode;
|
||||
bool open;
|
||||
unsigned char open;
|
||||
unsigned char len, delay, speed, loop, rel;
|
||||
|
||||
// the following variables are used by the GUI and not saved in the file
|
||||
|
|
|
@ -21,9 +21,20 @@
|
|||
#include "instrument.h"
|
||||
#include "engine.h"
|
||||
|
||||
#define ADSR_LOW source.val[0]
|
||||
#define ADSR_HIGH source.val[1]
|
||||
#define ADSR_AR source.val[2]
|
||||
#define ADSR_HT source.val[3]
|
||||
#define ADSR_DR source.val[4]
|
||||
#define ADSR_SL source.val[5]
|
||||
#define ADSR_ST source.val[6]
|
||||
#define ADSR_SR source.val[7]
|
||||
#define ADSR_RR source.val[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);
|
||||
}
|
||||
|
||||
|
@ -53,7 +64,9 @@ void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tic
|
|||
}
|
||||
actualHad=has;
|
||||
had=actualHad;
|
||||
|
||||
if (has) {
|
||||
if (type==0) { // sequence
|
||||
lastPos=pos;
|
||||
val=source.val[pos++];
|
||||
if (pos>source.rel && !released) {
|
||||
|
@ -73,6 +86,50 @@ void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tic
|
|||
}
|
||||
}
|
||||
}
|
||||
if (type==1 || type==3) { // ADSR
|
||||
if (released && lastPos<3) lastPos=3;
|
||||
switch (lastPos) {
|
||||
case 0: // attack
|
||||
pos+=ADSR_AR;
|
||||
if (pos>255) {
|
||||
pos=255;
|
||||
lastPos=1;
|
||||
delay=ADSR_HT;
|
||||
}
|
||||
break;
|
||||
case 1: // decay
|
||||
pos-=ADSR_DR;
|
||||
if (pos<=ADSR_SL) {
|
||||
pos=ADSR_SL;
|
||||
lastPos=2;
|
||||
delay=ADSR_ST;
|
||||
}
|
||||
break;
|
||||
case 2: // sustain
|
||||
pos-=ADSR_SR;
|
||||
if (pos<0) {
|
||||
pos=0;
|
||||
lastPos=4;
|
||||
}
|
||||
break;
|
||||
case 3: // release
|
||||
pos-=ADSR_RR;
|
||||
if (pos<0) {
|
||||
pos=0;
|
||||
lastPos=4;
|
||||
}
|
||||
break;
|
||||
case 4: // end
|
||||
pos=0;
|
||||
if (!linger) has=false;
|
||||
break;
|
||||
}
|
||||
val=ADSR_LOW+((pos+(ADSR_HIGH-ADSR_LOW)*pos)>>8);
|
||||
}
|
||||
if (type==2 || type==3) { // LFO
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DivMacroInt::next() {
|
||||
|
|
|
@ -28,10 +28,10 @@ struct DivMacroStruct {
|
|||
int pos, lastPos, delay;
|
||||
int val;
|
||||
bool has, had, actualHad, finished, will, linger, began;
|
||||
unsigned int mode;
|
||||
unsigned int mode, type;
|
||||
void doMacro(DivInstrumentMacro& source, bool released, bool tick);
|
||||
void init() {
|
||||
pos=lastPos=mode=delay=0;
|
||||
pos=lastPos=mode=type=delay=0;
|
||||
has=had=actualHad=will=false;
|
||||
linger=false;
|
||||
began=true;
|
||||
|
@ -51,7 +51,8 @@ struct DivMacroStruct {
|
|||
will(false),
|
||||
linger(false),
|
||||
began(true),
|
||||
mode(0) {}
|
||||
mode(0),
|
||||
type(0) {}
|
||||
};
|
||||
|
||||
class DivMacroInt {
|
||||
|
|
|
@ -203,6 +203,13 @@ enum FMParams {
|
|||
#define FM_NAME(x) fmParamNames[settings.fmNames][x]
|
||||
#define FM_SHORT_NAME(x) fmParamShortNames[settings.fmNames][x]
|
||||
|
||||
const char* macroTypeLabels[4]={
|
||||
ICON_FA_BAR_CHART "##IMacroType",
|
||||
ICON_FA_AREA_CHART "##IMacroType",
|
||||
ICON_FA_LINE_CHART "##IMacroType",
|
||||
ICON_FA_SIGN_OUT "##IMacroType"
|
||||
};
|
||||
|
||||
const char* fmOperatorBits[5]={
|
||||
"op1", "op2", "op3", "op4", NULL
|
||||
};
|
||||
|
@ -1326,10 +1333,11 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
|||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",i.displayName);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton(i.macro->open?(ICON_FA_CHEVRON_UP "##IMacroOpen"):(ICON_FA_CHEVRON_DOWN "##IMacroOpen"))) {
|
||||
i.macro->open=!i.macro->open;
|
||||
if (ImGui::SmallButton((i.macro->open&1)?(ICON_FA_CHEVRON_UP "##IMacroOpen"):(ICON_FA_CHEVRON_DOWN "##IMacroOpen"))) {
|
||||
i.macro->open^=1;
|
||||
}
|
||||
if (i.macro->open) {
|
||||
if (i.macro->open&1) {
|
||||
if ((i.macro->open&6)==0) {
|
||||
ImGui::SetNextItemWidth(lenAvail);
|
||||
int macroLen=i.macro->len;
|
||||
if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED
|
||||
|
@ -1337,11 +1345,32 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
|||
if (macroLen>255) macroLen=255;
|
||||
i.macro->len=macroLen;
|
||||
}
|
||||
if (ImGui::Button(ICON_FA_BAR_CHART "##IMacroType")) {
|
||||
|
||||
}
|
||||
if (ImGui::Button(macroTypeLabels[(i.macro->open>>1)&3])) {
|
||||
i.macro->open+=2;
|
||||
if (i.macro->open>=8) {
|
||||
i.macro->open-=8;
|
||||
}
|
||||
PARAMETER;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Coming soon!");
|
||||
switch (i.macro->open&6) {
|
||||
case 0:
|
||||
ImGui::SetTooltip("Macro type: Sequence");
|
||||
break;
|
||||
case 2:
|
||||
ImGui::SetTooltip("Macro type: ADSR");
|
||||
break;
|
||||
case 4:
|
||||
ImGui::SetTooltip("Macro type: LFO");
|
||||
break;
|
||||
case 6:
|
||||
ImGui::SetTooltip("Macro type: ADSR+LFO");
|
||||
break;
|
||||
default:
|
||||
ImGui::SetTooltip("Macro type: What's going on here?");
|
||||
break;
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Button(ICON_FA_ELLIPSIS_H "##IMacroSet");
|
||||
|
@ -1372,6 +1401,7 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
|||
|
||||
// macro area
|
||||
ImGui::TableNextColumn();
|
||||
if ((i.macro->open&6)==0) {
|
||||
for (int j=0; j<256; j++) {
|
||||
bit30Indicator[j]=0;
|
||||
if (j+macroDragScroll>=i.macro->len) {
|
||||
|
@ -1429,11 +1459,11 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
|||
}
|
||||
|
||||
if (i.isBitfield) {
|
||||
PlotBitfield("##IMacro",asInt,totalFit,0,i.bitfieldBits,i.max,ImVec2(availableWidth,(i.macro->open)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),doHighlight);
|
||||
PlotBitfield("##IMacro",asInt,totalFit,0,i.bitfieldBits,i.max,ImVec2(availableWidth,(i.macro->open&1)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),doHighlight);
|
||||
} else {
|
||||
PlotCustom("##IMacro",asFloat,totalFit,macroDragScroll,NULL,i.min+i.macro->vScroll,i.min+i.macro->vScroll+i.macro->vZoom,ImVec2(availableWidth,(i.macro->open)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),i.color,i.macro->len-macroDragScroll,i.hoverFunc,i.hoverFuncUser,i.blockMode,i.macro->open?genericGuide:NULL,doHighlight);
|
||||
PlotCustom("##IMacro",asFloat,totalFit,macroDragScroll,NULL,i.min+i.macro->vScroll,i.min+i.macro->vScroll+i.macro->vZoom,ImVec2(availableWidth,(i.macro->open&1)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),i.color,i.macro->len-macroDragScroll,i.hoverFunc,i.hoverFuncUser,i.blockMode,(i.macro->open&1)?genericGuide:NULL,doHighlight);
|
||||
}
|
||||
if (i.macro->open && (ImGui::IsItemClicked(ImGuiMouseButton_Left) || ImGui::IsItemClicked(ImGuiMouseButton_Right))) {
|
||||
if ((i.macro->open&1) && (ImGui::IsItemClicked(ImGuiMouseButton_Left) || ImGui::IsItemClicked(ImGuiMouseButton_Right))) {
|
||||
macroDragStart=ImGui::GetItemRectMin();
|
||||
macroDragAreaSize=ImVec2(availableWidth,i.height*dpiScale);
|
||||
if (i.isBitfield) {
|
||||
|
@ -1458,7 +1488,7 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
|||
lastMacroDesc=i;
|
||||
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
|
||||
}
|
||||
if (i.macro->open) {
|
||||
if ((i.macro->open&1)) {
|
||||
if (ImGui::IsItemHovered()) {
|
||||
if (ctrlWheeling) {
|
||||
if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) {
|
||||
|
@ -1570,6 +1600,114 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
|||
}
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
} else {
|
||||
if (i.macro->open&2) {
|
||||
if (ImGui::BeginTable("MacroADSR",4)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.3);
|
||||
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.3);
|
||||
//ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch,0.4);
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Bottom");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::InputInt("##MABottom",&i.macro->val[0],1,16)) { PARAMETER
|
||||
if (i.macro->val[0]<i.min) i.macro->val[0]=i.min;
|
||||
if (i.macro->val[0]>i.max) i.macro->val[0]=i.max;
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Top");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::InputInt("##MATop",&i.macro->val[1],1,16)) { PARAMETER
|
||||
if (i.macro->val[1]<i.min) i.macro->val[1]=i.min;
|
||||
if (i.macro->val[1]>i.max) i.macro->val[1]=i.max;
|
||||
}
|
||||
|
||||
/*ImGui::TableNextColumn();
|
||||
ImGui::Text("the envelope goes here");*/
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Attack");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (CWSliderInt("##MAAR",&i.macro->val[2],0,255)) { PARAMETER
|
||||
if (i.macro->val[2]<0) i.macro->val[2]=0;
|
||||
if (i.macro->val[2]>255) i.macro->val[2]=255;
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Sustain");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (CWSliderInt("##MASL",&i.macro->val[5],0,255)) { PARAMETER
|
||||
if (i.macro->val[5]<0) i.macro->val[5]=0;
|
||||
if (i.macro->val[5]>255) i.macro->val[5]=255;
|
||||
}
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Hold");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (CWSliderInt("##MAHT",&i.macro->val[3],0,255)) { PARAMETER
|
||||
if (i.macro->val[3]<0) i.macro->val[3]=0;
|
||||
if (i.macro->val[3]>255) i.macro->val[3]=255;
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("SusTime");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (CWSliderInt("##MAST",&i.macro->val[6],0,255)) { PARAMETER
|
||||
if (i.macro->val[6]<0) i.macro->val[6]=0;
|
||||
if (i.macro->val[6]>255) i.macro->val[6]=255;
|
||||
}
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Decay");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (CWSliderInt("##MADR",&i.macro->val[4],0,255)) { PARAMETER
|
||||
if (i.macro->val[4]<0) i.macro->val[4]=0;
|
||||
if (i.macro->val[4]>255) i.macro->val[4]=255;
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("SusDecay");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (CWSliderInt("##MASR",&i.macro->val[7],0,255)) { PARAMETER
|
||||
if (i.macro->val[7]<0) i.macro->val[7]=0;
|
||||
if (i.macro->val[7]>255) i.macro->val[7]=255;
|
||||
}
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Release");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (CWSliderInt("##MARR",&i.macro->val[8],0,255)) { PARAMETER
|
||||
if (i.macro->val[8]<0) i.macro->val[8]=0;
|
||||
if (i.macro->val[8]>255) i.macro->val[8]=255;
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (i.macro->open&4) {
|
||||
ImGui::Text("LFO...");
|
||||
}
|
||||
}
|
||||
ImGui::PopID();
|
||||
index++;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue