fix pitch bend mapping, add inertia when releasing

This commit is contained in:
Armin 2026-07-15 21:24:04 +02:00
commit 6e37f224e1
4 changed files with 46 additions and 23 deletions

View file

@ -168,8 +168,8 @@ void VuMeter::paint(juce::Graphics& g) {
clipPath.addRoundedRectangle(bounds, 9.0f); clipPath.addRoundedRectangle(bounds, 9.0f);
g.reduceClipRegion(clipPath); g.reduceClipRegion(clipPath);
juce::ColourGradient grad(juce::Colour(0xff00cc44).withAlpha(0.4f), 0.0f, bounds.getBottom(), juce::ColourGradient grad(juce::Colour(0xff00cc44).withAlpha(0.7f), 0.0f, bounds.getBottom(),
juce::Colour(0xffcc2200).withAlpha(0.4f), 0.0f, bounds.getY(), false); juce::Colour(0xffcc2200).withAlpha(0.7f), 0.0f, bounds.getY(), false);
g.setGradientFill(grad); g.setGradientFill(grad);
g.fillRoundedRectangle(innerBar, 2.0f); g.fillRoundedRectangle(innerBar, 2.0f);
} }
@ -230,8 +230,8 @@ void WaveformDisplay::paint(juce::Graphics& g) {
clipPath.addRoundedRectangle(bounds, 9.0f); clipPath.addRoundedRectangle(bounds, 9.0f);
g.reduceClipRegion(clipPath); g.reduceClipRegion(clipPath);
juce::ColourGradient waveGrad(juce::Colour(0xff00ff88).withAlpha(0.33f), 0.0f, bounds.getY(), juce::ColourGradient waveGrad(juce::Colour(0xff00ff88).withAlpha(0.5f), 0.0f, bounds.getY(),
juce::Colour(0xff005522).withAlpha(0.12f), 0.0f, bounds.getBottom(), false); juce::Colour(0xff005522).withAlpha(0.4f), 0.0f, bounds.getBottom(), false);
g.setGradientFill(waveGrad); g.setGradientFill(waveGrad);
g.fillPath(filledPath); g.fillPath(filledPath);
@ -309,7 +309,7 @@ void SpectrumAnalyzer::paint(juce::Graphics& g) {
float bx = x + 1.0f; float bx = x + 1.0f;
float by = barBottom - barH; float by = barBottom - barH;
g.setColour(juce::Colour(0xff00ff88).withAlpha(0.3f)); g.setColour(juce::Colour(0xff00ff88).withAlpha(0.4f));
g.fillRect(bx, by, bw, barH); g.fillRect(bx, by, bw, barH);
} }
@ -1126,7 +1126,7 @@ void PianoRollComponent::paint(juce::Graphics& g) {
bool pressed = processor.isNoteActive(note); bool pressed = processor.isNoteActive(note);
if (pressed) { if (pressed) {
g.setColour(juce::Colour(0xffccaa44).withAlpha(0.8f)); g.setColour(juce::Colour(0xffccaa44).withAlpha(0.7f));
} else { } else {
juce::ColourGradient grad(juce::Colour(0xffe4e4e4).withAlpha(0.7f), static_cast<float>(kx), 0.0f, juce::ColourGradient grad(juce::Colour(0xffe4e4e4).withAlpha(0.7f), static_cast<float>(kx), 0.0f,
juce::Colour(0xffc8c8c8).withAlpha(0.7f), static_cast<float>(kx), static_cast<float>(whiteKeyHeight), false); juce::Colour(0xffc8c8c8).withAlpha(0.7f), static_cast<float>(kx), static_cast<float>(whiteKeyHeight), false);
@ -1179,12 +1179,9 @@ void PianoRollComponent::paint(juce::Graphics& g) {
void PianoRollComponent::mouseDown(const juce::MouseEvent& e) { void PianoRollComponent::mouseDown(const juce::MouseEvent& e) {
auto pos = e.getPosition(); auto pos = e.getPosition();
// Pitch bend strip // Pitch bend strip: ignore plain clicks — require a vertical drag (see mouseDrag)
if (pos.x < pitchBendWidth) { if (pos.x < pitchBendWidth) {
float pbNorm = 1.0f - static_cast<float>(pos.y) / static_cast<float>(whiteKeyHeight); pitchBendDragging = false;
pbNorm = std::clamp(pbNorm, -1.0f, 1.0f);
currentPitchBend = 64 + static_cast<int>(pbNorm * 64.0f);
processor.pitchBendValue.store(pbNorm);
return; return;
} }
@ -1199,15 +1196,14 @@ void PianoRollComponent::mouseDown(const juce::MouseEvent& e) {
} }
void PianoRollComponent::mouseUp(const juce::MouseEvent& e) { void PianoRollComponent::mouseUp(const juce::MouseEvent& e) {
// Reset pitch bend to center on release // Reset pitch bend to center on release (only if it was actually dragged)
if (e.getPosition().x < pitchBendWidth || lastTriggeredNote < 0) { if (pitchBendDragging) {
if (e.getPosition().x < pitchBendWidth) { pitchBendDragging = false;
currentPitchBend = 64; pitchBendGliding = true;
processor.pitchBendValue.store(0.0f); pitchBendGlideStart = static_cast<float>(currentPitchBend - 64) / 64.0f;
pitchBendGlideStartMs = juce::Time::currentTimeMillis();
repaint(); repaint();
} }
if (lastTriggeredNote < 0) return;
}
if (lastTriggeredNote >= 0) { if (lastTriggeredNote >= 0) {
triggerNote(lastTriggeredNote, false); triggerNote(lastTriggeredNote, false);
@ -1216,12 +1212,33 @@ void PianoRollComponent::mouseUp(const juce::MouseEvent& e) {
} }
} }
void PianoRollComponent::timerCallback() {
if (pitchBendGliding) {
float t = static_cast<float>(juce::Time::currentTimeMillis() - pitchBendGlideStartMs)
/ static_cast<float>(pitchBendGlideMs);
if (t >= 1.0f) {
pitchBendGliding = false;
currentPitchBend = 64;
processor.pitchBendValue.store(0.0f);
} else {
float pbNorm = pitchBendGlideStart * (1.0f - t);
currentPitchBend = 64 + static_cast<int>(pbNorm * 64.0f);
processor.pitchBendValue.store(pbNorm);
}
repaint();
} else {
repaint();
}
}
void PianoRollComponent::mouseDrag(const juce::MouseEvent& e) { void PianoRollComponent::mouseDrag(const juce::MouseEvent& e) {
auto pos = e.getPosition(); auto pos = e.getPosition();
// Pitch bend drag // Pitch bend drag — only while touching the strip
if (pos.x < pitchBendWidth) { if (pos.x < pitchBendWidth) {
float pbNorm = 1.0f - static_cast<float>(pos.y) / static_cast<float>(whiteKeyHeight); pitchBendDragging = true;
pitchBendGliding = false;
float pbNorm = 1.0f - 2.0f * static_cast<float>(pos.y) / static_cast<float>(whiteKeyHeight);
pbNorm = std::clamp(pbNorm, -1.0f, 1.0f); pbNorm = std::clamp(pbNorm, -1.0f, 1.0f);
currentPitchBend = 64 + static_cast<int>(pbNorm * 64.0f); currentPitchBend = 64 + static_cast<int>(pbNorm * 64.0f);
processor.pitchBendValue.store(pbNorm); processor.pitchBendValue.store(pbNorm);

View file

@ -65,9 +65,9 @@ private:
class PianoRollComponent : public juce::Component, public juce::Timer { class PianoRollComponent : public juce::Component, public juce::Timer {
public: public:
explicit PianoRollComponent(ChromaFlockProcessor& p) : processor(p) { startTimerHz(30); } explicit PianoRollComponent(ChromaFlockProcessor& p) : processor(p) { startTimerHz(60); }
void paint(juce::Graphics& g) override; void paint(juce::Graphics& g) override;
void timerCallback() override { repaint(); } void timerCallback() override;
void mouseDown(const juce::MouseEvent& e) override; void mouseDown(const juce::MouseEvent& e) override;
void mouseUp(const juce::MouseEvent& e) override; void mouseUp(const juce::MouseEvent& e) override;
void mouseDrag(const juce::MouseEvent& e) override; void mouseDrag(const juce::MouseEvent& e) override;
@ -91,6 +91,12 @@ private:
int lastTriggeredNote = -1; int lastTriggeredNote = -1;
int currentPitchBend = 64; // 0..127, 64 = center int currentPitchBend = 64; // 0..127, 64 = center
bool pitchBendDragging = false;
bool pitchBendGliding = false;
float pitchBendGlideStart = 0.0f;
juce::int64 pitchBendGlideStartMs = 0;
static constexpr int pitchBendGlideMs = 50;
}; };
class MainContentComponent : public juce::Component { class MainContentComponent : public juce::Component {

BIN
bg.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 MiB

After

Width:  |  Height:  |  Size: 2.9 MiB

Before After
Before After

Binary file not shown.