Match Length button toggles with red highlight, moved controls to right side

This commit is contained in:
Armin 2026-10-06 23:27:48 +02:00
commit 16322a2bb6
3 changed files with 73 additions and 31 deletions

View file

@ -156,8 +156,11 @@ MonoslicerEditor::MonoslicerEditor(MonoslicerProcessor& p)
addAndMakeVisible(stretchButton);
stretchButton.addListener(this);
stretchButton.setClickingTogglesState(true);
stretchButton.setColour(juce::TextButton::buttonColourId, juce::Colour(0xff2a2a4a));
stretchButton.setColour(juce::TextButton::textColourOffId, juce::Colours::white);
stretchButton.setColour(juce::TextButton::buttonOnColourId, juce::Colour(0xffcc3333));
stretchButton.setColour(juce::TextButton::textColourOnId, juce::Colours::white);
// Key shift combo
addAndMakeVisible(keyShiftComboBox);
@ -328,35 +331,36 @@ void MonoslicerEditor::resized()
int comboGap = 4;
int contentW = bw - 2 * sectionGap - comboGap;
int leftW = static_cast<int>(contentW * 0.21);
int sideW = static_cast<int>(contentW * 0.21);
int comboW = static_cast<int>(contentW * 0.12);
int kw = (contentW - leftW - comboW) / 7;
int kw = (contentW - sideW - sideW - comboW - sectionGap * 2 - comboGap) / 7;
int adsrW = 4 * kw;
int filterW = 3 * kw + comboW + comboGap;
// Bottom panel: buttons + stretch | amp ADSR | filter ADSR | filter knobs
auto leftArea = bottomRow.removeFromLeft(leftW);
// Place auto-slice controls and stretch controls on the right side
int rightW = sideW;
auto rightArea = bottomRow.removeFromRight(rightW);
{
auto btnArea = leftArea.removeFromTop(28);
auto btnArea = rightArea.removeFromTop(28);
autoSliceButton.setBounds(btnArea.getX(), btnArea.getY(), btnArea.getWidth() / 2 - 2, 24);
clearSlicesButton.setBounds(btnArea.getX() + btnArea.getWidth() / 2 + 2, btnArea.getY(), btnArea.getWidth() / 2 - 2, 24);
leftArea.removeFromTop(4);
rightArea.removeFromTop(4);
// Stretch controls
int stretchW = leftArea.getWidth();
int stretchW = rightArea.getWidth();
int col1W = stretchW / 2 - 2;
int col2W = stretchW / 2 - 2;
bpmSlider.setBounds(leftArea.getX(), leftArea.getY(), col1W, 20);
stretchBeatsComboBox.setBounds(leftArea.getX() + col1W + 4, leftArea.getY(), col2W, 20);
leftArea.removeFromTop(24);
stretchButton.setBounds(leftArea.getX(), leftArea.getY(), stretchW, 22);
leftArea.removeFromTop(26);
leftArea.removeFromTop(20);
keyShiftComboBox.setBounds(leftArea.getX(), leftArea.getY(), stretchW, 20);
leftArea.removeFromTop(24);
vuMeter.setBounds(leftArea.getX(), leftArea.getY(), stretchW, 40);
bpmSlider.setBounds(rightArea.getX(), rightArea.getY(), col1W, 20);
stretchBeatsComboBox.setBounds(rightArea.getX() + col1W + 4, rightArea.getY(), col2W, 20);
rightArea.removeFromTop(24);
stretchButton.setBounds(rightArea.getX(), rightArea.getY(), stretchW, 22);
rightArea.removeFromTop(26);
rightArea.removeFromTop(20);
keyShiftComboBox.setBounds(rightArea.getX(), rightArea.getY(), stretchW, 20);
rightArea.removeFromTop(24);
vuMeter.setBounds(rightArea.getX(), rightArea.getY(), stretchW, 40);
}
bottomRow.removeFromLeft(sectionGap);
bottomRow.removeFromRight(sectionGap);
auto adsrSection = bottomRow.removeFromLeft(adsrW);
{
@ -430,6 +434,25 @@ void MonoslicerEditor::timerCallback()
waveformDisplay.setActiveSliceIndex(processorRef.currentActiveSlice.load());
waveformDisplay.setSelectedSlice(processorRef.selectedSlice.load());
// Update stretch button state
{
int beatsId = stretchBeatsComboBox.getSelectedId();
int numBeats = 4;
switch (beatsId)
{
case 1: numBeats = 1; break;
case 2: numBeats = 2; break;
case 3: numBeats = 4; break;
case 4: numBeats = 8; break;
case 5: numBeats = 16; break;
case 6: numBeats = 32; break;
default: numBeats = 4; break;
}
float bpm = static_cast<float>(bpmSlider.getValue());
bool matched = processorRef.isLengthMatchedToBeats(numBeats, bpm);
stretchButton.setToggleState(matched, juce::dontSendNotification);
}
// Release key click note when mouse is released
if (keyClickNote >= 0)
{
@ -493,6 +516,8 @@ void MonoslicerEditor::buttonClicked(juce::Button* button)
processorRef.redo();
}
else if (button == &stretchButton)
{
if (stretchButton.getToggleState())
{
int beatsId = stretchBeatsComboBox.getSelectedId();
int numBeats = 4;
@ -509,7 +534,12 @@ void MonoslicerEditor::buttonClicked(juce::Button* button)
float bpm = static_cast<float>(bpmSlider.getValue());
processorRef.stretchToBeats(numBeats, bpm);
waveformDisplay.setSampleBuffer(&processorRef.getSampleBuffer(), processorRef.getSampleRateLoaded());
}
else
{
processorRef.undo();
waveformDisplay.setSampleBuffer(&processorRef.getSampleBuffer(), processorRef.getSampleRateLoaded());
}
}
else if (button == &zoomInButton)
{

View file

@ -768,6 +768,17 @@ juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter()
return new MonoslicerProcessor();
}
bool MonoslicerProcessor::isLengthMatchedToBeats(int numBeats, float bpm) const
{
if (sampleBuffer.getNumSamples() == 0 || bpm <= 0.0f || numBeats <= 0)
return false;
double sr = loadedSampleRate;
if (sr <= 0.0) return false;
double currentDuration = static_cast<double>(sampleBuffer.getNumSamples()) / sr;
double targetDuration = static_cast<double>(numBeats) * 60.0 / static_cast<double>(bpm);
return std::abs(currentDuration - targetDuration) < 0.005;
}
void MonoslicerProcessor::stretchToBeats(int numBeats, float bpm)
{
if (sampleBuffer.getNumSamples() == 0 || bpm <= 0.0f || numBeats <= 0) return;

View file

@ -43,6 +43,7 @@ public:
void stretchToBeats(int numBeats, float bpm);
void psolaStretch(int targetLength);
float getHostBpm() const;
bool isLengthMatchedToBeats(int numBeats, float bpm) const;
void undo();
void redo();