Skip to content

Commit 3267f80

Browse files
committed
[Imp] Pressing Ctrl while moving loop points or clicking loop start/end spin buttons now moves the loop, keeping the loop length constant.
git-svn-id: https://source.openmpt.org/svn/openmpt/trunk/OpenMPT@22592 56274372-70c3-4bfc-bfc3-4c3a0b034d27
1 parent 18ae839 commit 3267f80

File tree

6 files changed

+267
-166
lines changed

6 files changed

+267
-166
lines changed

mptrack/Ctrl_smp.cpp

Lines changed: 36 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -2508,99 +2508,29 @@ void CCtrlSamples::OnSustainPointsChanged()
25082508
}
25092509

25102510

2511-
#define SMPLOOP_ACCURACY 7 // 5%
2512-
#define BIDILOOP_ACCURACY 2 // 5%
2513-
2514-
2515-
bool MPT_LoopCheck(int sstart0, int sstart1, int send0, int send1)
2516-
{
2517-
int dse0 = send0 - sstart0;
2518-
if ((dse0 < -SMPLOOP_ACCURACY) || (dse0 > SMPLOOP_ACCURACY)) return false;
2519-
int dse1 = send1 - sstart1;
2520-
if ((dse1 < -SMPLOOP_ACCURACY) || (dse1 > SMPLOOP_ACCURACY)) return false;
2521-
int dstart = sstart1 - sstart0;
2522-
int dend = send1 - send0;
2523-
if (!dstart) dstart = dend >> 7;
2524-
if (!dend) dend = dstart >> 7;
2525-
if ((dstart ^ dend) < 0) return false;
2526-
int delta = dend - dstart;
2527-
return ((delta > -SMPLOOP_ACCURACY) && (delta < SMPLOOP_ACCURACY));
2528-
}
2529-
2530-
2531-
bool MPT_BidiEndCheck(int spos0, int spos1, int spos2)
2532-
{
2533-
int delta0 = spos1 - spos0;
2534-
int delta1 = spos2 - spos1;
2535-
int delta2 = spos2 - spos0;
2536-
if (!delta0) delta0 = delta1 >> 7;
2537-
if (!delta1) delta1 = delta0 >> 7;
2538-
if ((delta1 ^ delta0) < 0) return false;
2539-
return ((delta0 >= -1) && (delta0 <= 0) && (delta1 >= -1) && (delta1 <= 0) && (delta2 >= -1) && (delta2 <= 0));
2540-
}
2541-
2542-
2543-
bool MPT_BidiStartCheck(int spos0, int spos1, int spos2)
2544-
{
2545-
int delta1 = spos1 - spos0;
2546-
int delta0 = spos2 - spos1;
2547-
int delta2 = spos2 - spos0;
2548-
if (!delta0) delta0 = delta1 >> 7;
2549-
if (!delta1) delta1 = delta0 >> 7;
2550-
if ((delta1 ^ delta0) < 0) return false;
2551-
return ((delta0 >= -1) && (delta0 <= 0) && (delta1 > -1) && (delta1 <= 0) && (delta2 >= -1) && (delta2 <= 0));
2552-
}
2553-
2554-
2555-
25562511
void CCtrlSamples::OnVScroll(UINT nCode, UINT, CScrollBar *scrollBar)
25572512
{
2558-
TCHAR s[256];
2513+
TCHAR s[32];
25592514
if(IsLocked()) return;
25602515
ModSample &sample = m_sndFile.GetSample(m_nSample);
2561-
const uint8 *pSample = mpt::byte_cast<const uint8 *>(sample.sampleb());
2562-
const uint32 inc = sample.GetBytesPerSample();
2563-
SmpLength i;
2564-
int pos;
2516+
const bool moveLoop = CMainFrame::GetInputHandler()->CtrlPressed();
25652517
bool redraw = false;
25662518
static CScrollBar *lastScrollbar = nullptr;
25672519

25682520
LockControls();
2569-
if ((!sample.nLength) || (!pSample)) goto NoSample;
2570-
if (sample.uFlags[CHN_16BIT])
2571-
{
2572-
pSample++;
2573-
}
25742521
// Loop Start
2575-
if ((pos = m_SpinLoopStart.GetPos32()) != 0 && sample.nLoopEnd > 0)
2522+
if(int pos = m_SpinLoopStart.GetPos32(); pos != 0 && sample.nLoopEnd > 0 && sample.HasSampleData())
25762523
{
2577-
bool bOk = false;
2578-
const uint8 *p = pSample + sample.nLoopStart * inc;
2579-
int find0 = (int)pSample[sample.nLoopEnd*inc-inc];
2580-
int find1 = (int)pSample[sample.nLoopEnd*inc];
2581-
// Find Next LoopStart Point
2582-
if (pos > 0)
2583-
{
2584-
for (i = sample.nLoopStart + 1; i + 16 < sample.nLoopEnd; i++)
2585-
{
2586-
p += inc;
2587-
bOk = sample.uFlags[CHN_PINGPONGLOOP] ? MPT_BidiStartCheck(p[0], p[inc], p[inc*2]) : MPT_LoopCheck(find0, find1, p[0], p[inc]);
2588-
if (bOk) break;
2589-
}
2590-
} else
2591-
// Find Prev LoopStart Point
2524+
if(SmpLength i = SampleEdit::FindLoopStart(sample, false, pos > 0, moveLoop); i < sample.nLength)
25922525
{
2593-
for (i = sample.nLoopStart; i; )
2526+
if(!m_startedEdit && lastScrollbar != scrollBar)
2527+
PrepareUndo(moveLoop ? "Move Loop" : "Set Loop Start");
2528+
if(moveLoop)
25942529
{
2595-
i--;
2596-
p -= inc;
2597-
bOk = sample.uFlags[CHN_PINGPONGLOOP] ? MPT_BidiStartCheck(p[0], p[inc], p[inc*2]) : MPT_LoopCheck(find0, find1, p[0], p[inc]);
2598-
if (bOk) break;
2530+
sample.nLoopEnd = i + (sample.nLoopEnd - sample.nLoopStart);
2531+
wsprintf(s, _T("%u"), sample.nLoopEnd);
2532+
m_EditLoopEnd.SetWindowText(s);
25992533
}
2600-
}
2601-
if (bOk)
2602-
{
2603-
if(!m_startedEdit && lastScrollbar != scrollBar) PrepareUndo("Set Loop Start");
26042534
sample.nLoopStart = i;
26052535
wsprintf(s, _T("%u"), sample.nLoopStart);
26062536
m_EditLoopStart.SetWindowText(s);
@@ -2610,34 +2540,18 @@ void CCtrlSamples::OnVScroll(UINT nCode, UINT, CScrollBar *scrollBar)
26102540
m_SpinLoopStart.SetPos(0);
26112541
}
26122542
// Loop End
2613-
if ((pos = m_SpinLoopEnd.GetPos32()) != 0)
2543+
if(int pos = m_SpinLoopEnd.GetPos32(); pos != 0 && sample.HasSampleData())
26142544
{
2615-
bool bOk = false;
2616-
const uint8 *p = pSample + sample.nLoopEnd * inc;
2617-
int find0 = (int)pSample[sample.nLoopStart*inc];
2618-
int find1 = (int)pSample[sample.nLoopStart*inc+inc];
2619-
// Find Next LoopEnd Point
2620-
if (pos > 0)
2621-
{
2622-
for (i = sample.nLoopEnd + 1; i <= sample.nLength; i++, p += inc)
2623-
{
2624-
bOk = sample.uFlags[CHN_PINGPONGLOOP] ? MPT_BidiEndCheck(p[0], p[inc], p[inc*2]) : MPT_LoopCheck(find0, find1, p[0], p[inc]);
2625-
if (bOk) break;
2626-
}
2627-
} else
2628-
// Find Prev LoopEnd Point
2545+
if(SmpLength i = SampleEdit::FindLoopEnd(sample, false, pos > 0, moveLoop); i > 0)
26292546
{
2630-
for (i = sample.nLoopEnd; i > sample.nLoopStart + 16; )
2547+
if(!m_startedEdit && lastScrollbar != scrollBar)
2548+
PrepareUndo(moveLoop ? "Move Loop" : "Set Loop End");
2549+
if(moveLoop)
26312550
{
2632-
i--;
2633-
p -= inc;
2634-
bOk = sample.uFlags[CHN_PINGPONGLOOP] ? MPT_BidiEndCheck(p[0], p[inc], p[inc*2]) : MPT_LoopCheck(find0, find1, p[0], p[inc]);
2635-
if (bOk) break;
2551+
sample.nLoopStart = i - (sample.nLoopEnd - sample.nLoopStart);
2552+
wsprintf(s, _T("%u"), sample.nLoopStart);
2553+
m_EditLoopStart.SetWindowText(s);
26362554
}
2637-
}
2638-
if (bOk)
2639-
{
2640-
if(!m_startedEdit && lastScrollbar != scrollBar) PrepareUndo("Set Loop End");
26412555
sample.nLoopEnd = i;
26422556
wsprintf(s, _T("%u"), sample.nLoopEnd);
26432557
m_EditLoopEnd.SetWindowText(s);
@@ -2647,35 +2561,18 @@ void CCtrlSamples::OnVScroll(UINT nCode, UINT, CScrollBar *scrollBar)
26472561
m_SpinLoopEnd.SetPos(0);
26482562
}
26492563
// Sustain Loop Start
2650-
if ((pos = m_SpinSustainStart.GetPos32()) != 0 && sample.nSustainEnd > 0)
2564+
if(int pos = m_SpinSustainStart.GetPos32(); pos != 0 && sample.nSustainEnd > 0 && sample.HasSampleData())
26512565
{
2652-
bool bOk = false;
2653-
const uint8 *p = pSample + sample.nSustainStart * inc;
2654-
int find0 = (int)pSample[sample.nSustainEnd*inc-inc];
2655-
int find1 = (int)pSample[sample.nSustainEnd*inc];
2656-
// Find Next Sustain LoopStart Point
2657-
if (pos > 0)
2658-
{
2659-
for (i = sample.nSustainStart + 1; i + 16 < sample.nSustainEnd; i++)
2660-
{
2661-
p += inc;
2662-
bOk = sample.uFlags[CHN_PINGPONGSUSTAIN] ? MPT_BidiStartCheck(p[0], p[inc], p[inc*2]) : MPT_LoopCheck(find0, find1, p[0], p[inc]);
2663-
if (bOk) break;
2664-
}
2665-
} else
2666-
// Find Prev Sustain LoopStart Point
2566+
if(SmpLength i = SampleEdit::FindLoopStart(sample, true, pos > 0, moveLoop); i < sample.nLength)
26672567
{
2668-
for (i = sample.nSustainStart; i; )
2568+
if(!m_startedEdit && lastScrollbar != scrollBar)
2569+
PrepareUndo(moveLoop ? "Move Sustain Loop" : "Set Sustain Loop Start");
2570+
if(moveLoop)
26692571
{
2670-
i--;
2671-
p -= inc;
2672-
bOk = sample.uFlags[CHN_PINGPONGSUSTAIN] ? MPT_BidiStartCheck(p[0], p[inc], p[inc*2]) : MPT_LoopCheck(find0, find1, p[0], p[inc]);
2673-
if (bOk) break;
2572+
sample.nSustainEnd = i + (sample.nSustainEnd - sample.nSustainStart);
2573+
wsprintf(s, _T("%u"), sample.nSustainEnd);
2574+
m_EditSustainEnd.SetWindowText(s);
26742575
}
2675-
}
2676-
if (bOk)
2677-
{
2678-
if(!m_startedEdit && lastScrollbar != scrollBar) PrepareUndo("Set Sustain Loop Start");
26792576
sample.nSustainStart = i;
26802577
wsprintf(s, _T("%u"), sample.nSustainStart);
26812578
m_EditSustainStart.SetWindowText(s);
@@ -2685,34 +2582,18 @@ void CCtrlSamples::OnVScroll(UINT nCode, UINT, CScrollBar *scrollBar)
26852582
m_SpinSustainStart.SetPos(0);
26862583
}
26872584
// Sustain Loop End
2688-
if ((pos = m_SpinSustainEnd.GetPos32()) != 0)
2585+
if(int pos = m_SpinSustainEnd.GetPos32(); pos != 0 && sample.HasSampleData())
26892586
{
2690-
bool bOk = false;
2691-
const uint8 *p = pSample + sample.nSustainEnd * inc;
2692-
int find0 = (int)pSample[sample.nSustainStart*inc];
2693-
int find1 = (int)pSample[sample.nSustainStart*inc+inc];
2694-
// Find Next LoopEnd Point
2695-
if (pos > 0)
2696-
{
2697-
for (i = sample.nSustainEnd + 1; i + 1 < sample.nLength; i++, p += inc)
2698-
{
2699-
bOk = sample.uFlags[CHN_PINGPONGSUSTAIN] ? MPT_BidiEndCheck(p[0], p[inc], p[inc*2]) : MPT_LoopCheck(find0, find1, p[0], p[inc]);
2700-
if (bOk) break;
2701-
}
2702-
} else
2703-
// Find Prev LoopEnd Point
2587+
if(SmpLength i = SampleEdit::FindLoopEnd(sample, true, pos > 0, moveLoop); i > 0)
27042588
{
2705-
for (i = sample.nSustainEnd; i > sample.nSustainStart + 16; )
2589+
if(!m_startedEdit && lastScrollbar != scrollBar)
2590+
PrepareUndo(moveLoop ? "Move Sustain Loop" : "Set Sustain Loop End");
2591+
if(moveLoop)
27062592
{
2707-
i--;
2708-
p -= inc;
2709-
bOk = sample.uFlags[CHN_PINGPONGSUSTAIN] ? MPT_BidiEndCheck(p[0], p[inc], p[inc*2]) : MPT_LoopCheck(find0, find1, p[0], p[inc]);
2710-
if (bOk) break;
2593+
sample.nSustainStart = i - (sample.nSustainEnd - sample.nSustainStart);
2594+
wsprintf(s, _T("%u"), sample.nSustainStart);
2595+
m_EditSustainStart.SetWindowText(s);
27112596
}
2712-
}
2713-
if (bOk)
2714-
{
2715-
if(!m_startedEdit && lastScrollbar != scrollBar) PrepareUndo("Set Sustain Loop End");
27162597
sample.nSustainEnd = i;
27172598
wsprintf(s, _T("%u"), sample.nSustainEnd);
27182599
m_EditSustainEnd.SetWindowText(s);
@@ -2721,9 +2602,8 @@ void CCtrlSamples::OnVScroll(UINT nCode, UINT, CScrollBar *scrollBar)
27212602
}
27222603
m_SpinSustainEnd.SetPos(0);
27232604
}
2724-
NoSample:
27252605
// FineTune / C-5 Speed
2726-
if ((pos = m_SpinFineTune.GetPos32()) != 0)
2606+
if(int pos = m_SpinFineTune.GetPos32(); pos != 0)
27272607
{
27282608
if(!m_startedEdit && lastScrollbar != scrollBar)
27292609
PrepareUndo("Finetune");
@@ -2930,8 +2810,7 @@ void CCtrlSamples::OnXFade()
29302810
CSampleXFadeDlg dlg(this, sample);
29312811
if(dlg.DoModal() == IDOK)
29322812
{
2933-
const SmpLength loopStart = dlg.m_useSustainLoop ? sample.nSustainStart: sample.nLoopStart;
2934-
const SmpLength loopEnd = dlg.m_useSustainLoop ? sample.nSustainEnd: sample.nLoopEnd;
2813+
const auto [loopStart, loopEnd] = dlg.m_useSustainLoop ? sample.GetSustainLoop() : sample.GetLoop();
29352814
const SmpLength maxSamples = std::min({ sample.nLength, loopStart, loopEnd / 2 });
29362815
SmpLength fadeSamples = dlg.PercentToSamples(dlg.m_fadeLength);
29372816
LimitMax(fadeSamples, maxSamples);

mptrack/View_smp.cpp

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1848,9 +1848,11 @@ void CViewSample::OnMouseMove(UINT flags, CPoint point)
18481848
m_startDragValue = ScreenToSample(point.x);
18491849
}
18501850

1851+
const bool moveLoop = (flags & MK_CONTROL);
18511852
bool update = false;
18521853
SmpLength *updateLoopPoint = nullptr;
18531854
const char *updateLoopDesc = nullptr;
1855+
SmpLength loopLength = 0;
18541856
switch(m_dragItem)
18551857
{
18561858
case HitTestItem::SelectionStart:
@@ -1863,28 +1865,50 @@ void CViewSample::OnMouseMove(UINT flags, CPoint point)
18631865
}
18641866
break;
18651867
case HitTestItem::LoopStart:
1866-
if(x < sample.nLoopEnd)
1868+
if(moveLoop)
1869+
{
1870+
updateLoopPoint = &sample.nLoopStart;
1871+
updateLoopDesc = "Move Loop";
1872+
loopLength = sample.nLoopEnd - sample.nLoopStart;
1873+
} else if(x < sample.nLoopEnd)
18671874
{
18681875
updateLoopPoint = &sample.nLoopStart;
18691876
updateLoopDesc = "Set Loop Start";
18701877
}
18711878
break;
18721879
case HitTestItem::LoopEnd:
1873-
if(x > sample.nLoopStart)
1880+
if(moveLoop)
1881+
{
1882+
updateLoopPoint = &sample.nLoopStart;
1883+
updateLoopDesc = "Move Loop";
1884+
loopLength = sample.nLoopEnd - sample.nLoopStart;
1885+
x = (x > loopLength) ? x - loopLength : 0;
1886+
} else if(x > sample.nLoopStart)
18741887
{
18751888
updateLoopPoint = &sample.nLoopEnd;
18761889
updateLoopDesc = "Set Loop End";
18771890
}
18781891
break;
18791892
case HitTestItem::SustainStart:
1880-
if(x < sample.nSustainEnd)
1893+
if(moveLoop)
1894+
{
1895+
updateLoopPoint = &sample.nSustainStart;
1896+
updateLoopDesc = "Move Sustain Loop";
1897+
loopLength = sample.nSustainEnd - sample.nSustainStart;
1898+
} else if(x < sample.nSustainEnd)
18811899
{
18821900
updateLoopPoint = &sample.nSustainStart;
18831901
updateLoopDesc = "Set Sustain Start";
18841902
}
18851903
break;
18861904
case HitTestItem::SustainEnd:
1887-
if(x > sample.nSustainStart)
1905+
if(moveLoop)
1906+
{
1907+
updateLoopPoint = &sample.nSustainStart;
1908+
updateLoopDesc = "Move Loop";
1909+
loopLength = sample.nSustainEnd - sample.nSustainStart;
1910+
x = (x > loopLength) ? x - loopLength : 0;
1911+
} else if(x > sample.nSustainStart)
18881912
{
18891913
updateLoopPoint = &sample.nSustainEnd;
18901914
updateLoopDesc = "Set Sustain End";
@@ -1900,13 +1924,20 @@ void CViewSample::OnMouseMove(UINT flags, CPoint point)
19001924
break;
19011925
}
19021926

1927+
if(loopLength)
1928+
LimitMax(x, sample.nLength - loopLength);
1929+
19031930
if(updateLoopPoint && updateLoopDesc && *updateLoopPoint != x)
19041931
{
19051932
if(!m_dragPreparedUndo)
19061933
pModDoc->GetSampleUndo().PrepareUndo(m_nSample, sundo_none, updateLoopDesc);
19071934
m_dragPreparedUndo = true;
19081935
update = true;
19091936
*updateLoopPoint = x;
1937+
if(loopLength && updateLoopPoint == &sample.nLoopStart)
1938+
sample.nLoopEnd = sample.nLoopStart + loopLength;
1939+
else if(loopLength && updateLoopPoint == &sample.nSustainStart)
1940+
sample.nSustainEnd = sample.nSustainStart + loopLength;
19101941
sample.PrecomputeLoops(sndFile, true);
19111942
SetModified(SampleHint().Info(), true, false);
19121943
}
@@ -2041,7 +2072,7 @@ void CViewSample::OnLButtonDown(UINT flags, CPoint point)
20412072
} else
20422073
{
20432074
// ctrl + click = play from cursor pos
2044-
if(flags & MK_CONTROL)
2075+
if((flags & MK_CONTROL) && point.y >= m_timelineHeight)
20452076
PlayNote(NOTE_MIDDLEC, ScreenToSample(point.x));
20462077
}
20472078
}

soundlib/ModSample.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ struct ModSample
148148
void SetLoop(SmpLength start, SmpLength end, bool enable, bool pingpong, CSoundFile &sndFile);
149149
// Set sustain loop points and update loop wrap-around buffer
150150
void SetSustainLoop(SmpLength start, SmpLength end, bool enable, bool pingpong, CSoundFile &sndFile);
151+
// Retrieve the normal loop points
152+
std::pair<SmpLength, SmpLength> GetLoop() const noexcept { return std::make_pair(nLoopStart, nLoopEnd); }
153+
// Retrieve the sustain loop points
154+
std::pair<SmpLength, SmpLength> GetSustainLoop() const noexcept { return std::make_pair(nSustainStart, nSustainEnd); }
151155
// Update loop wrap-around buffer
152156
void PrecomputeLoops(CSoundFile &sndFile, bool updateChannels = true);
153157

soundlib/modsmp_ctrl.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,7 @@ static void XFadeSampleImpl(const T *srcIn, const T *srcOut, T *output, const Sm
105105
bool XFadeSample(ModSample &smp, SmpLength fadeLength, int fadeLaw, bool afterloopFade, bool useSustainLoop, CSoundFile &sndFile)
106106
{
107107
if(!smp.HasSampleData()) return false;
108-
const SmpLength loopStart = useSustainLoop ? smp.nSustainStart : smp.nLoopStart;
109-
const SmpLength loopEnd = useSustainLoop ? smp.nSustainEnd : smp.nLoopEnd;
108+
const auto [loopStart, loopEnd] = useSustainLoop ? smp.GetSustainLoop() : smp.GetLoop();
110109

111110
if(loopEnd <= loopStart || loopEnd > smp.nLength) return false;
112111
if(loopStart < fadeLength) return false;

0 commit comments

Comments
 (0)