Merge branch 'master' of https://github.com/tildearrow/furnace into ymf278b

This commit is contained in:
cam900 2024-07-15 18:53:26 +09:00
commit 5837575e4a
17 changed files with 216 additions and 69 deletions

Binary file not shown.

Binary file not shown.

View file

@ -101,11 +101,6 @@ namespace IGFD
#ifndef FILTER_COMBO_WIDTH #ifndef FILTER_COMBO_WIDTH
#define FILTER_COMBO_WIDTH 150.0f #define FILTER_COMBO_WIDTH 150.0f
#endif // FILTER_COMBO_WIDTH #endif // FILTER_COMBO_WIDTH
// for lets you define your button widget
// if you have like me a special bi-color button
#ifndef IMGUI_PATH_BUTTON
#define IMGUI_PATH_BUTTON ImGui::Button
#endif // IMGUI_PATH_BUTTON
#ifndef IMGUI_BUTTON #ifndef IMGUI_BUTTON
#define IMGUI_BUTTON ImGui::Button #define IMGUI_BUTTON ImGui::Button
#endif // IMGUI_BUTTON #endif // IMGUI_BUTTON
@ -2141,7 +2136,7 @@ namespace IGFD
if (itPathDecomp != prCurrentPathDecomposition.begin()) if (itPathDecomp != prCurrentPathDecomposition.begin())
ImGui::SameLine(); ImGui::SameLine();
ImGui::PushID(_id++); ImGui::PushID(_id++);
bool click = IMGUI_PATH_BUTTON((*itPathDecomp).c_str()); bool click = ImGui::ButtonEx((*itPathDecomp).c_str(),ImVec2(0,0),ImGuiButtonFlags_NoHashTextHide);
ImGui::PopID(); ImGui::PopID();
if (click) if (click)
{ {
@ -3903,7 +3898,7 @@ namespace IGFD
auto& fdi = prFileDialogInternal.puFileManager; auto& fdi = prFileDialogInternal.puFileManager;
static ImGuiSelectableFlags selectableFlags = ImGuiSelectableFlags_AllowDoubleClick | static ImGuiSelectableFlags selectableFlags = ImGuiSelectableFlags_AllowDoubleClick |
ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_SpanAvailWidth; ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_SpanAvailWidth | ImGuiSelectableFlags_NoHashTextHide;
// TODO BUG?! // TODO BUG?!
// YES BUG: THIS JUST CRASHED FOR SOME REASON // YES BUG: THIS JUST CRASHED FOR SOME REASON

View file

@ -3426,7 +3426,7 @@ void ImGui::RenderTextWrappedNoHashHide(ImVec2 pos, const char* text, const char
// FIXME-OPT: Since we have or calculate text_size we could coarse clip whole block immediately, especally for text above draw_list->DrawList. // FIXME-OPT: Since we have or calculate text_size we could coarse clip whole block immediately, especally for text above draw_list->DrawList.
// Effectively as this is called from widget doing their own coarse clipping it's not very valuable presently. Next time function will take // Effectively as this is called from widget doing their own coarse clipping it's not very valuable presently. Next time function will take
// better advantage of the render function taking size into account for coarse clipping. // better advantage of the render function taking size into account for coarse clipping.
void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect, bool hide_after_hash)
{ {
// Perform CPU side clipping for single clipped element to avoid using scissor state // Perform CPU side clipping for single clipped element to avoid using scissor state
ImVec2 pos = pos_min; ImVec2 pos = pos_min;
@ -3446,11 +3446,19 @@ void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, co
if (need_clipping) if (need_clipping)
{ {
ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y); ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y);
draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect); if (hide_after_hash) {
draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect);
} else {
draw_list->AddTextNoHashHide(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect);
}
} }
else else
{ {
draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL); if (hide_after_hash) {
draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL);
} else {
draw_list->AddTextNoHashHide(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL);
}
} }
} }
@ -3479,7 +3487,7 @@ void ImGui::RenderTextClippedNoHashHide(const ImVec2& pos_min, const ImVec2& pos
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect); RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect, false);
if (g.LogEnabled) if (g.LogEnabled)
LogRenderedText(&pos_min, text, text_display_end); LogRenderedText(&pos_min, text, text_display_end);
} }

View file

@ -881,6 +881,7 @@ enum ImGuiButtonFlagsPrivate_
ImGuiButtonFlags_NoHoveredOnFocus = 1 << 19, // don't report as hovered when nav focus is on this item ImGuiButtonFlags_NoHoveredOnFocus = 1 << 19, // don't report as hovered when nav focus is on this item
ImGuiButtonFlags_NoSetKeyOwner = 1 << 20, // don't set key/input owner on the initial click (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!) ImGuiButtonFlags_NoSetKeyOwner = 1 << 20, // don't set key/input owner on the initial click (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!)
ImGuiButtonFlags_NoTestKeyOwner = 1 << 21, // don't test key/input owner when polling the key (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!) ImGuiButtonFlags_NoTestKeyOwner = 1 << 21, // don't test key/input owner when polling the key (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!)
ImGuiButtonFlags_NoHashTextHide = 1 << 22, // tildearrow: Don't hide text after hash
ImGuiButtonFlags_PressedOnMask_ = ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_PressedOnDragDropHold, ImGuiButtonFlags_PressedOnMask_ = ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_PressedOnDragDropHold,
ImGuiButtonFlags_PressedOnDefault_ = ImGuiButtonFlags_PressedOnClickRelease, ImGuiButtonFlags_PressedOnDefault_ = ImGuiButtonFlags_PressedOnClickRelease,
}; };
@ -3456,7 +3457,7 @@ namespace ImGui
IMGUI_API void RenderTextWrappedNoHashHide(ImVec2 pos, const char* text, const char* text_end, float wrap_width); IMGUI_API void RenderTextWrappedNoHashHide(ImVec2 pos, const char* text, const char* text_end, float wrap_width);
IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL);
IMGUI_API void RenderTextClippedNoHashHide(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); IMGUI_API void RenderTextClippedNoHashHide(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL);
IMGUI_API void RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); IMGUI_API void RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL, bool hide_after_hash = true);
IMGUI_API void RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end, const ImVec2* text_size_if_known); IMGUI_API void RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end, const ImVec2* text_size_if_known);
IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f);
IMGUI_API void RenderFrameDrawList(ImDrawList* dl, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); // MODIFIED - draw list version of RenderFrame IMGUI_API void RenderFrameDrawList(ImDrawList* dl, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); // MODIFIED - draw list version of RenderFrame

View file

@ -816,7 +816,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label); const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 label_size = CalcTextSize(label, NULL, (flags&ImGuiButtonFlags_NoHashTextHide)?false:true);
ImVec2 pos = window->DC.CursorPos; ImVec2 pos = window->DC.CursorPos;
if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag) if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
@ -838,7 +838,12 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags
if (g.LogEnabled) if (g.LogEnabled)
LogSetNextTextDecoration("[", "]"); LogSetNextTextDecoration("[", "]");
RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb);
if (flags & ImGuiButtonFlags_NoHashTextHide) {
RenderTextClippedNoHashHide(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb);
} else {
RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb);
}
// Automatically close popups // Automatically close popups
//if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))

View file

@ -247,8 +247,14 @@ size | description
| - 0xd7: Game Boy Advance (direct) - 2 channels | - 0xd7: Game Boy Advance (direct) - 2 channels
| - 0xd8: Game Boy Advance (MinMod) - 16 channels | - 0xd8: Game Boy Advance (MinMod) - 16 channels
| - 0xd9: Bifurcator - 4 channels | - 0xd9: Bifurcator - 4 channels
| - 0xda: SCSP - 32 channels (UNAVAILABLE)
| - 0xdb: YMF271 (OPX) - 48 channels (UNAVAILABLE)
| - 0xdc: RF5C400 - 32 channels (UNAVAILABLE)
| - 0xdd: YM2612 XGM - 9 channels (UNAVAILABLE)
| - 0xde: YM2610B extended - 19 channels | - 0xde: YM2610B extended - 19 channels
| - 0xdf: YM2612 XGM extended - 13 channels (UNAVAILABLE)
| - 0xe0: QSound - 19 channels | - 0xe0: QSound - 19 channels
| - 0xe1: PS1 - 24 channels (UNAVAILABLE)
| - 0xf0: SID2 - 3 channels | - 0xf0: SID2 - 3 channels
| - 0xf1: 5E01 - 5 channels | - 0xf1: 5E01 - 5 channels
| - 0xfc: Pong - 1 channel | - 0xfc: Pong - 1 channel

View file

@ -697,6 +697,14 @@ class DivDispatch {
*/ */
virtual int mapVelocity(int ch, float vel); virtual int mapVelocity(int ch, float vel);
/**
* map chip volume to gain.
* @param ch the chip channel. -1 means N/A.
* @param vol input volume.
* @return output gain fron 0.0 to 1.0.
*/
virtual float getGain(int ch, int vol);
/** /**
* get the lowest note in a portamento. * get the lowest note in a portamento.
* @param ch the channel in question. * @param ch the channel in question.

View file

@ -181,6 +181,8 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
unsigned short patLen[256]; unsigned short patLen[256];
unsigned char defVol[256]; unsigned char defVol[256];
unsigned char defPan[256];
unsigned char defPanIns[256];
unsigned char noteMap[256][128]; unsigned char noteMap[256][128];
bool doesPitchSlide[64]; bool doesPitchSlide[64];
@ -210,6 +212,8 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
memset(patLen,0,256*sizeof(unsigned short)); memset(patLen,0,256*sizeof(unsigned short));
memset(defVol,0,256); memset(defVol,0,256);
memset(defPan,0,256);
memset(defPanIns,128,256);
memset(noteMap,0,256*128); memset(noteMap,0,256*128);
try { try {
@ -436,9 +440,7 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
reader.readC(); reader.readC();
insVol=reader.readC(); insVol=reader.readC();
unsigned char defPan=reader.readC(); defPanIns[i]=reader.readC();
logV("defPan: %d",defPan);
// vol/pan randomization // vol/pan randomization
reader.readC(); reader.readC();
@ -572,9 +574,7 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
s->name=reader.readStringLatin1(26); s->name=reader.readStringLatin1(26);
unsigned char convert=reader.readC(); unsigned char convert=reader.readC();
unsigned char defPan=reader.readC(); defPan[i]=reader.readC();
logV("defPan: %d",defPan);
if (flags&2) { if (flags&2) {
s->depth=DIV_SAMPLE_DEPTH_16BIT; s->depth=DIV_SAMPLE_DEPTH_16BIT;
@ -946,6 +946,7 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
bool panSliding[64]; bool panSliding[64];
bool panSlidingOld[64]; bool panSlidingOld[64];
bool did[64]; bool did[64];
unsigned char lastRetrig[64];
if (patPtr[i]==0) continue; if (patPtr[i]==0) continue;
@ -989,6 +990,7 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
memset(panSliding,0,64*sizeof(bool)); memset(panSliding,0,64*sizeof(bool));
memset(panSlidingOld,0,64*sizeof(bool)); memset(panSlidingOld,0,64*sizeof(bool));
memset(did,0,64*sizeof(bool)); memset(did,0,64*sizeof(bool));
memset(lastRetrig,0,64);
memset(mask,0,64); memset(mask,0,64);
memset(note,0,64); memset(note,0,64);
@ -1118,7 +1120,6 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
} }
readRow++; readRow++;
memset(effectCol,4,64);
memcpy(vibingOld,vibing,64*sizeof(bool)); memcpy(vibingOld,vibing,64*sizeof(bool));
memcpy(volSlidingOld,volSliding,64*sizeof(bool)); memcpy(volSlidingOld,volSliding,64*sizeof(bool));
memcpy(portingOld,porting,64*sizeof(bool)); memcpy(portingOld,porting,64*sizeof(bool));
@ -1155,6 +1156,7 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
} }
break; break;
} }
memset(effectCol,4,64);
continue; continue;
} }
@ -1216,6 +1218,29 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
} }
if (hasIns) { if (hasIns) {
p->data[readRow][2]=ins[chan]-1; p->data[readRow][2]=ins[chan]-1;
if ((note[chan]<120 || ds.insLen==0) && ins[chan]>0) {
unsigned char targetPan=0;
if (ds.insLen==0) {
targetPan=defPan[(ins[chan]-1)&255];
} else {
targetPan=defPan[noteMap[(ins[chan]-1)&255][note[chan]]];
if (!(targetPan&128)) {
targetPan=defPanIns[(ins[chan]-1)&255]^0x80;
}
}
if (targetPan&128) {
p->data[readRow][effectCol[chan]++]=0x80;
p->data[readRow][effectCol[chan]++]=CLAMP((targetPan&127)<<2,0,255);
}
}
if (hasNote && (note[chan]<120 || ds.insLen==0) && ins[chan]>0) {
if (ds.insLen==0) {
p->data[readRow][3]=defVol[(ins[chan]-1)&255];
} else {
p->data[readRow][3]=defVol[noteMap[(ins[chan]-1)&255][note[chan]]];
}
}
} }
if (hasVol) { if (hasVol) {
if (vol[chan]<=64) { if (vol[chan]<=64) {
@ -1227,7 +1252,23 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
} else if (vol[chan]>=65 && vol[chan]<=74) { // fine vol up } else if (vol[chan]>=65 && vol[chan]<=74) { // fine vol up
} else if (vol[chan]>=75 && vol[chan]<=84) { // fine vol down } else if (vol[chan]>=75 && vol[chan]<=84) { // fine vol down
} else if (vol[chan]>=85 && vol[chan]<=94) { // vol slide up } else if (vol[chan]>=85 && vol[chan]<=94) { // vol slide up
if ((vol[chan]-85)!=0) {
volSlideStatus[chan]=(vol[chan]-85)<<4;
volSlideStatusChanged[chan]=true;
}
if (hasNote || hasIns) {
volSlideStatusChanged[chan]=true;
}
volSliding[chan]=true;
} else if (vol[chan]>=95 && vol[chan]<=104) { // vol slide down } else if (vol[chan]>=95 && vol[chan]<=104) { // vol slide down
if ((vol[chan]-95)!=0) {
volSlideStatus[chan]=vol[chan]-95;
volSlideStatusChanged[chan]=true;
}
if (hasNote || hasIns) {
volSlideStatusChanged[chan]=true;
}
volSliding[chan]=true;
} else if (vol[chan]>=105 && vol[chan]<=114) { // pitch down } else if (vol[chan]>=105 && vol[chan]<=114) { // pitch down
} else if (vol[chan]>=115 && vol[chan]<=124) { // pitch up } else if (vol[chan]>=115 && vol[chan]<=124) { // pitch up
} else if (vol[chan]>=193 && vol[chan]<=202) { // porta } else if (vol[chan]>=193 && vol[chan]<=202) { // porta
@ -1242,14 +1283,14 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
portaType[chan]=3; portaType[chan]=3;
porting[chan]=true; porting[chan]=true;
} else if (vol[chan]>=203 && vol[chan]<=212) { // vibrato } else if (vol[chan]>=203 && vol[chan]<=212) { // vibrato
if ((vol[chan]-203)!=0) {
vibStatus[chan]&=0xf0;
vibStatus[chan]|=(vol[chan]-203);
vibStatusChanged[chan]=true;
}
vibing[chan]=true;
} }
} }
} else if (hasNote && hasIns && (note[chan]<120 || ds.insLen==0) && ins[chan]>0) {
if (ds.insLen==0) {
p->data[readRow][3]=defVol[(ins[chan]-1)&255];
} else {
p->data[readRow][3]=defVol[noteMap[(ins[chan]-1)&255][note[chan]]];
}
} }
if (hasEffect) { if (hasEffect) {
switch (effect[chan]+'A'-1) { switch (effect[chan]+'A'-1) {
@ -1302,7 +1343,7 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
portaStatus[chan]=effectVal[chan]; portaStatus[chan]=effectVal[chan];
portaStatusChanged[chan]=true; portaStatusChanged[chan]=true;
} }
if (portaType[chan]!=3) { if (portaType[chan]!=3 || hasNote) {
portaStatusChanged[chan]=true; portaStatusChanged[chan]=true;
} }
portaType[chan]=3; portaType[chan]=3;
@ -1357,8 +1398,11 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
panSliding[chan]=true; panSliding[chan]=true;
break; break;
case 'Q': // retrigger case 'Q': // retrigger
if (effectVal[chan]!=0) {
lastRetrig[chan]=effectVal[chan];
}
p->data[readRow][effectCol[chan]++]=0x0c; p->data[readRow][effectCol[chan]++]=0x0c;
p->data[readRow][effectCol[chan]++]=effectVal[chan]&15; p->data[readRow][effectCol[chan]++]=lastRetrig[chan]&15;
break; break;
case 'R': // tremolo case 'R': // tremolo
if (effectVal[chan]!=0) { if (effectVal[chan]!=0) {
@ -1369,6 +1413,10 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
break; break;
case 'S': // special... case 'S': // special...
switch (effectVal[chan]>>4) { switch (effectVal[chan]>>4) {
case 0x8:
p->data[readRow][effectCol[chan]++]=0x80;
p->data[readRow][effectCol[chan]++]=(effectVal[chan]&15)<<4;
break;
case 0xc: case 0xc:
p->data[readRow][effectCol[chan]++]=0xec; p->data[readRow][effectCol[chan]++]=0xec;
p->data[readRow][effectCol[chan]++]=effectVal[chan]&15; p->data[readRow][effectCol[chan]++]=effectVal[chan]&15;
@ -1380,8 +1428,10 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
} }
break; break;
case 'T': // tempo case 'T': // tempo
p->data[readRow][effectCol[chan]++]=0xf0; if (effectVal[chan]>=0x20) {
p->data[readRow][effectCol[chan]++]=effectVal[chan]; p->data[readRow][effectCol[chan]++]=0xf0;
p->data[readRow][effectCol[chan]++]=effectVal[chan];
}
break; break;
case 'U': // fine vibrato case 'U': // fine vibrato
if (effectVal[chan]!=0) { if (effectVal[chan]!=0) {
@ -1471,6 +1521,7 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
} }
} }
ds.systemLen=(maxChan+32)>>5; ds.systemLen=(maxChan+32)>>5;
ds.systemName="PC";
// find subsongs // find subsongs
ds.findSubSongs(maxChan); ds.findSubSongs(maxChan);

View file

@ -1075,6 +1075,10 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
break; break;
case 'S': // special... case 'S': // special...
switch (effectVal>>4) { switch (effectVal>>4) {
case 0x8:
p->data[readRow][effectCol[chan]++]=0x80;
p->data[readRow][effectCol[chan]++]=(effectVal&15)<<4;
break;
case 0xc: case 0xc:
p->data[readRow][effectCol[chan]++]=0xec; p->data[readRow][effectCol[chan]++]=0xec;
p->data[readRow][effectCol[chan]++]=effectVal&15; p->data[readRow][effectCol[chan]++]=effectVal&15;

View file

@ -87,7 +87,10 @@ void readEnvelope(DivInstrument* ins, int env, unsigned char flags, unsigned cha
} }
} }
if ((point+1)>=numPoints) { if ((point+1)>=numPoints) {
target->len=i; target->len=i-1;
if (((flags&4) && (!(flags&2))) || ((flags&6)==0)) {
target->rel=i-2;
}
//target->val[i]=p0; //target->val[i]=p0;
break; break;
} }
@ -103,7 +106,7 @@ void readEnvelope(DivInstrument* ins, int env, unsigned char flags, unsigned cha
// split L/R // split L/R
if (env==1) { if (env==1) {
for (int i=0; i<ins->std.panLMacro.len; i++) { for (int i=0; i<ins->std.panLMacro.len; i++) {
int val=ins->std.panLMacro.val[i]; int val=ins->std.panLMacro.val[i]-32;
if (val==0) { if (val==0) {
ins->std.panLMacro.val[i]=4095; ins->std.panLMacro.val[i]=4095;
ins->std.panRMacro.val[i]=4095; ins->std.panRMacro.val[i]=4095;
@ -166,7 +169,7 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
ds.noSlidesOnFirstTick=true; ds.noSlidesOnFirstTick=true;
ds.rowResetsArpPos=true; ds.rowResetsArpPos=true;
ds.ignoreJumpAtEnd=false; ds.ignoreJumpAtEnd=false;
ds.pitchSlideSpeed=12; ds.pitchSlideSpeed=8;
logV("Extended Module"); logV("Extended Module");
@ -421,6 +424,9 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
} }
} }
if (hasEffectVal) { if (hasEffectVal) {
if (!hasEffect) {
doesArp[k]=true;
}
effectVal=reader.readC(); effectVal=reader.readC();
if (effect==0xe) { if (effect==0xe) {
switch (effectVal>>4) { switch (effectVal>>4) {
@ -525,21 +531,40 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
if (volType&1) { if (volType&1) {
// add fade-out // add fade-out
int cur=64; if (volFade!=0) {
if (ins->std.volMacro.len>0) { int cur=64;
cur=ins->std.volMacro.val[ins->std.volMacro.len-1]; int macroLen=ins->std.volMacro.len;
} int curPos=ins->std.volMacro.len-1;
for (int fadeOut=32767; fadeOut>0 && ins->std.volMacro.len<254; fadeOut-=volFade) { if (ins->std.volMacro.loop<macroLen) {
ins->std.volMacro.val[ins->std.volMacro.len++]=(cur*fadeOut)>>15; curPos=ins->std.volMacro.loop;
} }
if (ins->std.volMacro.len<255) { if (ins->std.volMacro.len>0) {
ins->std.volMacro.val[ins->std.volMacro.len++]=0; cur=ins->std.volMacro.val[curPos];
}
for (int fadeOut=32767; fadeOut>0 && ins->std.volMacro.len<254; fadeOut-=volFade) {
cur=ins->std.volMacro.val[curPos];
ins->std.volMacro.val[ins->std.volMacro.len++]=(cur*fadeOut)>>15;
if (++curPos>=macroLen) {
if (ins->std.volMacro.loop<macroLen) {
curPos=ins->std.volMacro.loop;
} else {
curPos=macroLen-1;
}
}
}
if (ins->std.volMacro.len<255) {
ins->std.volMacro.val[ins->std.volMacro.len++]=0;
}
if (ins->std.volMacro.rel<ins->std.volMacro.len && ins->std.volMacro.rel<ins->std.volMacro.loop) {
ins->std.volMacro.loop=255;
}
} }
} else { } else {
// add a one-tick macro to make note release happy // add a one-tick macro to make note release happy
ins->std.volMacro.val[0]=64; ins->std.volMacro.val[0]=64;
ins->std.volMacro.val[1]=0; ins->std.volMacro.val[1]=0;
ins->std.volMacro.rel=0; ins->std.volMacro.rel=0;
ins->std.volMacro.loop=255;
ins->std.volMacro.len=2; ins->std.volMacro.len=2;
} }
@ -908,6 +933,15 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
panSliding[k]=true; panSliding[k]=true;
break; break;
case 0xf: // porta case 0xf: // porta
if ((vol&15)!=0) {
portaStatus[k]=(vol&15)<<4;
portaStatusChanged[k]=true;
}
if (portaType[k]!=3 || (hasNote && note>0)) {
portaStatusChanged[k]=true;
}
portaType[k]=3;
porting[k]=true;
break; break;
} }
} }
@ -955,7 +989,7 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
portaStatus[k]=effectVal; portaStatus[k]=effectVal;
portaStatusChanged[k]=true; portaStatusChanged[k]=true;
} }
if (portaType[k]!=3) { if (portaType[k]!=3 || (hasNote && note>0)) {
portaStatusChanged[k]=true; portaStatusChanged[k]=true;
} }
portaType[k]=3; portaType[k]=3;
@ -1006,8 +1040,10 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
writePanning=false; writePanning=false;
break; break;
case 9: // offset case 9: // offset
p->data[j][effectCol[k]++]=0x91; if (hasNote) {
p->data[j][effectCol[k]++]=effectVal; p->data[j][effectCol[k]++]=0x91;
p->data[j][effectCol[k]++]=effectVal;
}
break; break;
case 0xa: // vol slide case 0xa: // vol slide
if (effectVal!=0) { if (effectVal!=0) {
@ -1037,19 +1073,25 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
p->data[j][effectCol[k]++]=0xe5; p->data[j][effectCol[k]++]=0xe5;
p->data[j][effectCol[k]++]=(effectVal&15)<<4; p->data[j][effectCol[k]++]=(effectVal&15)<<4;
break; break;
case 0x9:
p->data[j][effectCol[k]++]=0x0c;
p->data[j][effectCol[k]++]=(effectVal&15);
break;
case 0xc: case 0xc:
p->data[j][effectCol[k]++]=0xec; p->data[j][effectCol[k]++]=0xec;
p->data[j][effectCol[k]++]=effectVal&15; p->data[j][effectCol[k]++]=MAX(1,effectVal&15);
break; break;
case 0xd: case 0xd:
p->data[j][effectCol[k]++]=0xed; p->data[j][effectCol[k]++]=0xed;
p->data[j][effectCol[k]++]=effectVal&15; p->data[j][effectCol[k]++]=MAX(1,effectVal&15);
break; break;
} }
break; break;
case 0xf: // speed/tempp case 0xf: // speed/tempo
if (effectVal>=0x20) { if (effectVal>=0x20) {
p->data[j][effectCol[k]++]=0xf0; p->data[j][effectCol[k]++]=0xf0;
} else if (effectVal==0) {
p->data[j][effectCol[k]++]=0xff;
} else { } else {
p->data[j][effectCol[k]++]=0x0f; p->data[j][effectCol[k]++]=0x0f;
} }
@ -1128,14 +1170,8 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
} }
if (porting[k]!=portingOld[k] || portaStatusChanged[k]) { if (porting[k]!=portingOld[k] || portaStatusChanged[k]) {
if (portaStatus[k]>=0xe0 && portaType[k]!=3 && porting[k]) { p->data[j][effectCol[k]++]=portaType[k];
p->data[j][effectCol[k]++]=portaType[k]|0xf0; p->data[j][effectCol[k]++]=porting[k]?portaStatus[k]:0;
p->data[j][effectCol[k]++]=(portaStatus[k]&15)*((portaStatus[k]>=0xf0)?1:1);
porting[k]=false;
} else {
p->data[j][effectCol[k]++]=portaType[k];
p->data[j][effectCol[k]++]=porting[k]?portaStatus[k]:0;
}
doesPitchSlide[k]=true; doesPitchSlide[k]=true;
} else if (doesPitchSlide[k] && mustCommitInitial) { } else if (doesPitchSlide[k] && mustCommitInitial) {
p->data[j][effectCol[k]++]=0x01; p->data[j][effectCol[k]++]=0x01;
@ -1183,7 +1219,6 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
} }
} }
memset(effectCol,4,64);
memcpy(vibingOld,vibing,64*sizeof(bool)); memcpy(vibingOld,vibing,64*sizeof(bool));
memcpy(volSlidingOld,volSliding,64*sizeof(bool)); memcpy(volSlidingOld,volSliding,64*sizeof(bool));
memcpy(portingOld,porting,64*sizeof(bool)); memcpy(portingOld,porting,64*sizeof(bool));
@ -1207,6 +1242,7 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
ds.subsong[0]->pat[0].effectCols=(effectCol[0]>>1)-1; ds.subsong[0]->pat[0].effectCols=(effectCol[0]>>1)-1;
} }
} }
memset(effectCol,4,64);
} }
logV("seeking to %x...",packedSeek); logV("seeking to %x...",packedSeek);

View file

@ -107,6 +107,11 @@ int DivDispatch::mapVelocity(int ch, float vel) {
return round(vel*volMax); return round(vel*volMax);
} }
float DivDispatch::getGain(int ch, int vol) {
const float volMax=MAX(1,dispatch(DivCommand(DIV_CMD_GET_VOLMAX,MAX(ch,0))));
return (float)vol/volMax;
}
int DivDispatch::getPortaFloor(int ch) { int DivDispatch::getPortaFloor(int ch) {
return 0x00; return 0x00;
} }

View file

@ -156,14 +156,14 @@ void FurnaceGUI::insListItem(int i, int dir, int asset) {
if (i<(int)e->song.ins.size()) { if (i<(int)e->song.ins.size()) {
DivInstrument* ins=e->song.ins[i]; DivInstrument* ins=e->song.ins[i];
ImGui::SameLine(); ImGui::SameLine();
ImGui::Text("%.2X: %s",i,ins->name.c_str()); ImGui::TextNoHashHide("%.2X: %s",i,ins->name.c_str());
} else { } else {
ImGui::SameLine(); ImGui::SameLine();
ImGui::Text("%.2X: <INVALID>",i); ImGui::TextNoHashHide("%.2X: <INVALID>",i);
} }
} else { } else {
ImGui::SameLine(); ImGui::SameLine();
ImGui::Text("- None -"); ImGui::TextNoHashHide("- None -");
} }
ImGui::PopID(); ImGui::PopID();
ImGui::PopStyleColor(); ImGui::PopStyleColor();
@ -219,7 +219,7 @@ void FurnaceGUI::sampleListItem(int i, int dir, int asset) {
if (memWarning) break; if (memWarning) break;
} }
if (memWarning) ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_SAMPLE_CHIP_WARNING]); if (memWarning) ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_SAMPLE_CHIP_WARNING]);
if (ImGui::Selectable(fmt::sprintf("%d: %s##_SAM%d",i,sample->name,i).c_str(),curSample==i)) { if (ImGui::Selectable(fmt::sprintf("%d:##_SAM%d",i,i).c_str(),curSample==i)) {
curSample=i; curSample=i;
samplePos=0; samplePos=0;
updateSampleTex=true; updateSampleTex=true;
@ -235,6 +235,8 @@ void FurnaceGUI::sampleListItem(int i, int dir, int asset) {
DRAG_SOURCE(dir,asset,"FUR_SDIR"); DRAG_SOURCE(dir,asset,"FUR_SDIR");
DRAG_TARGET(dir,asset,e->song.sampleDir,"FUR_SDIR"); DRAG_TARGET(dir,asset,e->song.sampleDir,"FUR_SDIR");
} }
ImGui::SameLine();
ImGui::TextNoHashHide("%s",sample->name.c_str());
if (memWarning) { if (memWarning) {
ImGui::SameLine(); ImGui::SameLine();
ImGui::Text(ICON_FA_EXCLAMATION_TRIANGLE); ImGui::Text(ICON_FA_EXCLAMATION_TRIANGLE);

View file

@ -4281,6 +4281,19 @@ bool FurnaceGUI::loop() {
ImGui::EndMenu(); ImGui::EndMenu();
} }
} }
bool hasTiunaCompat=false;
for (int i=0; i<e->song.systemLen; i++) {
if (e->song.system[i]==DIV_SYSTEM_TIA) {
hasTiunaCompat=true;
break;
}
}
if (hasTiunaCompat) {
if (ImGui::BeginMenu(_("export TIunA..."))) {
drawExportTiuna();
ImGui::EndMenu();
}
}
int numAmiga=0; int numAmiga=0;
for (int i=0; i<e->song.systemLen; i++) { for (int i=0; i<e->song.systemLen; i++) {
if (e->song.system[i]==DIV_SYSTEM_AMIGA) numAmiga++; if (e->song.system[i]==DIV_SYSTEM_AMIGA) numAmiga++;
@ -4322,6 +4335,19 @@ bool FurnaceGUI::loop() {
displayExport=true; displayExport=true;
} }
} }
bool hasTiunaCompat=false;
for (int i=0; i<e->song.systemLen; i++) {
if (e->song.system[i]==DIV_SYSTEM_TIA) {
hasTiunaCompat=true;
break;
}
}
if (hasTiunaCompat) {
if (ImGui::MenuItem(_("export TIunA..."))) {
curExportType=GUI_EXPORT_TIUNA;
displayExport=true;
}
}
int numAmiga=0; int numAmiga=0;
for (int i=0; i<e->song.systemLen; i++) { for (int i=0; i<e->song.systemLen; i++) {
if (e->song.system[i]==DIV_SYSTEM_AMIGA) numAmiga++; if (e->song.system[i]==DIV_SYSTEM_AMIGA) numAmiga++;

View file

@ -282,7 +282,7 @@ void FurnaceGUI::drawOrders() {
for (int i=0; i<e->getTotalChannelCount(); i++) { for (int i=0; i<e->getTotalChannelCount(); i++) {
if (!e->curSubSong->chanShow[i]) continue; if (!e->curSubSong->chanShow[i]) continue;
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Text("%s",e->getChannelShortName(i)); ImGui::TextNoHashHide("%s",e->getChannelShortName(i));
} }
ImGui::PopStyleColor(); ImGui::PopStyleColor();
for (int i=0; i<e->curSubSong->ordersLen; i++) { for (int i=0; i<e->curSubSong->ordersLen; i++) {

View file

@ -686,7 +686,7 @@ void FurnaceGUI::drawPattern() {
bool hovered=ImGui::ItemHoverable(rect,ImGui::GetID(chanID),0); bool hovered=ImGui::ItemHoverable(rect,ImGui::GetID(chanID),0);
ImU32 col=(hovered || (mobileUI && ImGui::IsMouseDown(ImGuiMouseButton_Left)))?ImGui::GetColorU32(ImGuiCol_HeaderHovered):ImGui::GetColorU32(ImGuiCol_Header); ImU32 col=(hovered || (mobileUI && ImGui::IsMouseDown(ImGuiMouseButton_Left)))?ImGui::GetColorU32(ImGuiCol_HeaderHovered):ImGui::GetColorU32(ImGuiCol_Header);
dl->AddRectFilled(rect.Min,rect.Max,col); dl->AddRectFilled(rect.Min,rect.Max,col);
dl->AddText(ImVec2(minLabelArea.x,rect.Min.y),ImGui::GetColorU32(channelTextColor(i)),chanID); dl->AddTextNoHashHide(ImVec2(minLabelArea.x,rect.Min.y),ImGui::GetColorU32(channelTextColor(i)),chanID);
} }
break; break;
case 1: { // line case 1: { // line
@ -707,7 +707,7 @@ void FurnaceGUI::drawPattern() {
)); ));
dl->AddRectFilledMultiColor(rect.Min,rect.Max,fadeCol0,fadeCol0,fadeCol,fadeCol); dl->AddRectFilledMultiColor(rect.Min,rect.Max,fadeCol0,fadeCol0,fadeCol,fadeCol);
dl->AddLine(ImVec2(rect.Min.x,rect.Max.y),ImVec2(rect.Max.x,rect.Max.y),ImGui::GetColorU32(chanHeadBase),2.0f*dpiScale); dl->AddLine(ImVec2(rect.Min.x,rect.Max.y),ImVec2(rect.Max.x,rect.Max.y),ImGui::GetColorU32(chanHeadBase),2.0f*dpiScale);
dl->AddText(ImVec2(minLabelArea.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID); dl->AddTextNoHashHide(ImVec2(minLabelArea.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID);
} }
break; break;
} }
@ -734,14 +734,14 @@ void FurnaceGUI::drawPattern() {
rMax.x-=3.0f*dpiScale; rMax.x-=3.0f*dpiScale;
rMax.y-=6.0f*dpiScale; rMax.y-=6.0f*dpiScale;
dl->AddRectFilledMultiColor(rMin,rMax,fadeCol0,fadeCol0,fadeCol,fadeCol,4.0f*dpiScale); dl->AddRectFilledMultiColor(rMin,rMax,fadeCol0,fadeCol0,fadeCol,fadeCol,4.0f*dpiScale);
dl->AddText(ImVec2(minLabelArea.x,rect.Min.y+6.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID); dl->AddTextNoHashHide(ImVec2(minLabelArea.x,rect.Min.y+6.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID);
} }
break; break;
} }
case 3: // split button case 3: // split button
ImGui::Dummy(ImVec2(1.0f,2.0f*dpiScale)); ImGui::Dummy(ImVec2(1.0f,2.0f*dpiScale));
//ImGui::SetCursorPosX(minLabelArea.x); //ImGui::SetCursorPosX(minLabelArea.x);
ImGui::TextUnformatted(chanID); ImGui::TextNoHashHide("%s",chanID);
ImGui::SameLine(); ImGui::SameLine();
ImGui::PushFont(mainFont); ImGui::PushFont(mainFont);
ImGui::SmallButton(muted?ICON_FA_VOLUME_OFF:ICON_FA_VOLUME_UP); ImGui::SmallButton(muted?ICON_FA_VOLUME_OFF:ICON_FA_VOLUME_UP);
@ -764,7 +764,7 @@ void FurnaceGUI::drawPattern() {
rMax.x-=3.0f*dpiScale; rMax.x-=3.0f*dpiScale;
rMax.y-=3.0f*dpiScale; rMax.y-=3.0f*dpiScale;
dl->AddRect(rMin,rMax,fadeCol,0.0f,2.0*dpiScale); dl->AddRect(rMin,rMax,fadeCol,0.0f,2.0*dpiScale);
dl->AddText(ImVec2(minLabelArea.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID); dl->AddTextNoHashHide(ImVec2(minLabelArea.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID);
} }
break; break;
} }
@ -785,7 +785,7 @@ void FurnaceGUI::drawPattern() {
rMax.x-=3.0f*dpiScale; rMax.x-=3.0f*dpiScale;
rMax.y-=3.0f*dpiScale; rMax.y-=3.0f*dpiScale;
dl->AddRect(rMin,rMax,fadeCol,4.0f*dpiScale,ImDrawFlags_RoundCornersAll,2.0*dpiScale); dl->AddRect(rMin,rMax,fadeCol,4.0f*dpiScale,ImDrawFlags_RoundCornersAll,2.0*dpiScale);
dl->AddText(ImVec2(minLabelArea.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID); dl->AddTextNoHashHide(ImVec2(minLabelArea.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID);
} }
break; break;
} }