Fix GCC build (Clang-only flag), add note mapping + drag/drop overlay, UI tweaks

This commit is contained in:
Armin 2026-10-03 21:49:27 +02:00
commit ca6f1ff0ee
7 changed files with 97 additions and 7 deletions

View file

@ -216,6 +216,10 @@ MonoslicerEditor::MonoslicerEditor(MonoslicerProcessor& p)
processorRef.triggerSlice(sliceIdx, 0.8f);
});
addChildComponent(dropOverlay);
dropOverlay.setInterceptsMouseClicks(false, false);
dropOverlay.setVisible(false);
startTimerHz(30);
}
@ -286,6 +290,7 @@ void MonoslicerEditor::resized()
statusBarArea.getWidth() / 2 - 5, statusBarArea.getHeight());
buildInfoLabel.setBounds(statusBarArea.getCentreX(), statusBarArea.getY(),
statusBarArea.getWidth() / 2 - 5, statusBarArea.getHeight());
dropOverlay.setBounds(getLocalBounds());
int tx = 120;
@ -547,17 +552,58 @@ void MonoslicerEditor::comboBoxChanged(juce::ComboBox* comboBoxThatHasChanged)
}
}
// [EDITOR DIAG] temporary
static void ediag(const char* what, const juce::StringArray& files, int accept)
{
FILE* f = fopen("/tmp/monoslicer_drag.log", "a");
if (f == nullptr) return;
fprintf(f, "[editor] %s accept=%d files=%d", what, accept, (int)files.size());
for (const auto& x : files) fprintf(f, " \"%s\"", x.toUTF8().getAddress());
fprintf(f, "\n");
fclose(f);
}
bool MonoslicerEditor::isInterestedInFileDrag(const juce::StringArray& files)
{
for (const auto& f : files)
if (f.endsWithIgnoreCase(".wav") || f.endsWithIgnoreCase(".aiff") ||
f.endsWithIgnoreCase(".flac") || f.endsWithIgnoreCase(".ogg"))
{
ediag("isInterested", files, 1);
return true;
}
ediag("isInterested", files, 0);
return false;
}
void MonoslicerEditor::fileDragEnter(const juce::StringArray& files, int, int)
{
ediag("enter", files, isInterestedInFileDrag(files) ? 1 : 0);
if (isInterestedInFileDrag(files))
{
dropOverlay.setVisible(true);
dropOverlay.toFront(false);
dropOverlay.repaint();
}
}
void MonoslicerEditor::fileDragMove(const juce::StringArray& files, int, int)
{
if (isInterestedInFileDrag(files))
dropOverlay.setVisible(true);
}
void MonoslicerEditor::fileDragExit(const juce::StringArray&)
{
ediag("exit", juce::StringArray(), 0);
dropOverlay.setVisible(false);
}
void MonoslicerEditor::filesDropped(const juce::StringArray& files, int, int)
{
ediag("drop", files, 1);
dropOverlay.setVisible(false);
for (const auto& f : files)
{
juce::File file(f);

View file

@ -65,8 +65,8 @@ public:
auto drawBar = [&](float y, float level, float peak, const juce::String& legend)
{
float frac = juce::jlimit(0.0f, 1.0f, level);
float peakFrac = juce::jlimit(0.0f, 1.0f, peak);
float frac = juce::jlimit(0.0f, 1.0f, level) * 0.95f;
float peakFrac = juce::jlimit(0.0f, 1.0f, peak) * 0.95f;
// Legend text
g.setColour(juce::Colour(0xff888888));
@ -114,12 +114,29 @@ public:
void resized() override;
bool isInterestedInFileDrag(const juce::StringArray& files) override;
void fileDragEnter(const juce::StringArray& files, int x, int y) override;
void fileDragMove(const juce::StringArray& files, int x, int y) override;
void fileDragExit(const juce::StringArray& files) override;
void filesDropped(const juce::StringArray& files, int x, int y) override;
void buttonClicked(juce::Button* button) override;
void comboBoxChanged(juce::ComboBox* comboBoxThatHasChanged) override;
void timerCallback() override;
private:
class DropOverlay : public juce::Component
{
public:
void paint(juce::Graphics& g) override
{
auto b = getLocalBounds().toFloat();
g.setColour(juce::Colour(0x66003a8c));
g.fillRoundedRectangle(b.reduced(3.0f), 8.0f);
g.setColour(juce::Colour(0xcc88ccff));
g.drawRoundedRectangle(b.reduced(3.0f), 8.0f, 2.0f);
g.setFont(juce::Font(18.0f, juce::Font::bold));
g.drawText(TRANS("Drop audio file to load"), b, juce::Justification::centred, true);
}
};
MonoslicerLookAndFeel lnf;
MonoslicerProcessor& processorRef;
@ -199,6 +216,7 @@ private:
const juce::String& paramId, std::unique_ptr<SliderAttachment>& attachment);
int keyClickNote = -1;
DropOverlay dropOverlay;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MonoslicerEditor)
};

View file

@ -470,8 +470,12 @@ void MonoslicerProcessor::processBlock(juce::AudioBuffer<float>& buffer, juce::M
void MonoslicerProcessor::handleNoteOn(int noteNumber, float velocity)
{
int offset = static_cast<int>(apvts.getRawParameterValue("octaveOffset")->load()) * 12;
int sliceIdx = noteNumber - 60 + offset;
int offset = 0;
if (auto* p = dynamic_cast<juce::AudioParameterInt*>(apvts.getParameter("octaveOffset")))
offset = p->get();
int note = noteNumber + offset * 12;
int sliceIdx = sliceManager.findSliceIndexForNote(note);
sliceIdx = juce::jlimit(0, juce::jmax(0, sliceManager.getNumSlices() - 1), sliceIdx);
if (apvts.getRawParameterValue("selectViaMidi")->load() > 0.5f)

View file

@ -282,6 +282,24 @@ int SliceManager::findSliceIndexForSample(int samplePos) const
return -1;
}
int SliceManager::findSliceIndexForNote(int midiNote) const
{
const juce::CriticalSection::ScopedLockType lock(mutex);
if (slices.empty())
return -1;
for (size_t i = 0; i < slices.size(); ++i)
if (slices[i].midiNote == midiNote)
return static_cast<int>(i);
int pitchClass = midiNote % 12;
for (size_t i = 0; i < slices.size(); ++i)
if (slices[i].midiNote % 12 == pitchClass)
return static_cast<int>(i);
return -1;
}
void SliceManager::sortSlices()
{
std::sort(slices.begin(), slices.end(),

View file

@ -41,6 +41,7 @@ public:
void setBeforeChangeCallback(std::function<void()> cb) { beforeChangeCallback = std::move(cb); }
int findSliceIndexForSample(int samplePos) const;
int findSliceIndexForNote(int midiNote) const;
juce::AudioBuffer<float>* getMutableBuffer() { return sampleBuffer; }

View file

@ -403,8 +403,8 @@ void WaveformDisplay::drawWaveform(juce::Graphics& g, juce::Rectangle<float> bou
filledPath.closeSubPath();
juce::ColourGradient gradient(juce::Colour(0xff4488ff), bounds.getX(), bounds.getY(),
juce::Colour(0xff2244aa), bounds.getX(), bounds.getBottom(), false);
juce::ColourGradient gradient(juce::Colour(0xff5599ff), bounds.getX(), bounds.getY(),
juce::Colour(0xff002255), bounds.getX(), bounds.getBottom(), false);
g.setGradientFill(gradient);
g.fillPath(filledPath);