diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 9e0ec7fd5..48edf51e2 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -681,30 +681,7 @@ void FurnaceGUI::doAction(int what) { latchNibble=false; break; case GUI_ACTION_PAT_ABSORB_INSTRUMENT: { - DivPattern* pat=e->curPat[cursor.xCoarse].getPattern(e->curOrders->ord[cursor.xCoarse][curOrder],false); - if (!pat) break; - bool foundIns=false; - bool foundOctave=false; - for (int i=cursor.y; i>=0 && !(foundIns && foundOctave); i--) { - // absorb most recent instrument - if (!foundIns && pat->data[i][2] >= 0) { - curIns=pat->data[i][2]; - foundIns=true; - } - // absorb most recent octave (i.e. set curOctave such that the "main row" (QWERTY) of notes - // will result in an octave number equal to the previous note). - if (!foundOctave && pat->data[i][0] != 0) { - // decode octave data (was signed cast to unsigned char) - int octave=pat->data[i][1]; - if (octave>128) octave-=256; - // @NOTE the special handling when note==12, which is really an octave above what's - // stored in the octave data. without this handling, if you press Q, then - // "ABSORB_INSTRUMENT", then Q again, you'd get a different octave! - if (pat->data[i][0]==12) octave++; - curOctave=CLAMP(octave-1, GUI_EDIT_OCTAVE_MIN, GUI_EDIT_OCTAVE_MAX); - foundOctave=true; - } - } + doAbsorbInstrument(); break; } diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index 1a4449098..8a49f4ecf 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -1823,6 +1823,52 @@ void FurnaceGUI::doExpandSong(int multiplier) { if (e->isPlaying()) e->play(); } +void FurnaceGUI::doAbsorbInstrument() { + bool foundIns=false; + bool foundOctave=false; + auto foundAll = [&]() { return foundIns && foundOctave; }; + + // search this order and all prior until we find all the data we need + int orderIdx=curOrder; + for (; orderIdx>=0 && !foundAll(); orderIdx--) { + DivPattern* pat=e->curPat[cursor.xCoarse].getPattern(e->curOrders->ord[cursor.xCoarse][orderIdx],false); + if (!pat) continue; + + // start on current row when searching current order, but start from end when searching + // prior orders. + int searchStartRow=orderIdx==curOrder ? cursor.y : e->curSubSong->patLen-1; + for (int i=searchStartRow; i>=0 && !foundAll(); i--) { + + // absorb most recent instrument + if (!foundIns && pat->data[i][2] >= 0) { + foundIns=true; + curIns=pat->data[i][2]; + } + + // absorb most recent octave (i.e. set curOctave such that the "main row" (QWERTY) of + // notes will result in an octave number equal to the previous note). + if (!foundOctave && pat->data[i][0] != 0) { + foundOctave=true; + + // decode octave data (was signed cast to unsigned char) + int octave=pat->data[i][1]; + if (octave>128) octave-=256; + + // @NOTE the special handling when note==12, which is really an octave above what's + // stored in the octave data. without this handling, if you press Q, then + // "ABSORB_INSTRUMENT", then Q again, you'd get a different octave! + if (pat->data[i][0]==12) octave++; + curOctave=CLAMP(octave-1, GUI_EDIT_OCTAVE_MIN, GUI_EDIT_OCTAVE_MAX); + } + } + } + + // if no instrument has been set at this point, the only way to match it is to use "none" + if (!foundIns) curIns=-1; + + logD("doAbsorbInstrument -- searched %d orders", curOrder-orderIdx); +} + void FurnaceGUI::doDrag() { int len=dragEnd.xCoarse-dragStart.xCoarse+1; diff --git a/src/gui/gui.h b/src/gui/gui.h index 8108c74f0..83d412b7f 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -2922,6 +2922,7 @@ class FurnaceGUI { void doExpand(int multiplier, const SelectionPoint& sStart, const SelectionPoint& sEnd); void doCollapseSong(int divider); void doExpandSong(int multiplier); + void doAbsorbInstrument(); void doUndo(); void doRedo(); void doFind();