mirror of
https://codeberg.org/armin/justasample.git
synced 2026-09-01 04:10:48 +02:00
add ping-pong loop mode and crossfade length rotary
This commit is contained in:
parent
4bd1156835
commit
e9dc3a4d66
10 changed files with 67 additions and 17 deletions
|
|
@ -178,10 +178,10 @@ juce_add_plugin(JustASample
|
||||||
DESCRIPTION "Just a Sample is a modern, open-source audio sampler"
|
DESCRIPTION "Just a Sample is a modern, open-source audio sampler"
|
||||||
ICON_BIG "Assets/Icons/IconLogo.svg"
|
ICON_BIG "Assets/Icons/IconLogo.svg"
|
||||||
ICON_SMALL "Assets/Icons/IconLogo.svg"
|
ICON_SMALL "Assets/Icons/IconLogo.svg"
|
||||||
COMPANY_NAME "Binyamin Friedman"
|
COMPANY_NAME "Just a Sample"
|
||||||
COMPANY_COPYRIGHT "Copyright (c) 2026 Binyamin Friedman"
|
COMPANY_COPYRIGHT "(c) 2026 B. Friedman & A. Jenewein"
|
||||||
COMPANY_WEBSITE "https://github.com/BOBONA/Just-a-Sample/"
|
COMPANY_WEBSITE "https://codeberg.org/armin/justasample"
|
||||||
BUNDLE_ID com.BinyaminFriedman.JustASample
|
BUNDLE_ID org.justasample.JustASample
|
||||||
PLUGIN_MANUFACTURER_CODE Manu
|
PLUGIN_MANUFACTURER_CODE Manu
|
||||||
PLUGIN_CODE Bpf2
|
PLUGIN_CODE Bpf2
|
||||||
FORMATS AU VST3
|
FORMATS AU VST3
|
||||||
|
|
@ -268,6 +268,7 @@ juce_add_binary_data(AudioPluginData
|
||||||
Assets/Icons/IconLogo.svg
|
Assets/Icons/IconLogo.svg
|
||||||
Assets/Icons/IconLoop.svg
|
Assets/Icons/IconLoop.svg
|
||||||
Assets/Icons/IconLoopStart.svg
|
Assets/Icons/IconLoopStart.svg
|
||||||
|
Assets/Icons/IconPingPong.svg
|
||||||
Assets/Icons/IconMono.svg
|
Assets/Icons/IconMono.svg
|
||||||
Assets/Icons/IconPin.svg
|
Assets/Icons/IconPin.svg
|
||||||
Assets/Icons/IconPlay.svg
|
Assets/Icons/IconPlay.svg
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ struct Layout
|
||||||
static constexpr int attackWidth{ 204 };
|
static constexpr int attackWidth{ 204 };
|
||||||
static constexpr int releaseWidth{ 204 };
|
static constexpr int releaseWidth{ 204 };
|
||||||
static constexpr int playbackWidth{ 534 };
|
static constexpr int playbackWidth{ 534 };
|
||||||
static constexpr int loopWidth{ 217 };
|
static constexpr int loopWidth{ 310 };
|
||||||
static constexpr int masterWidth{ 295 };
|
static constexpr int masterWidth{ 295 };
|
||||||
|
|
||||||
static constexpr int standardRotarySize{ 87 }; // Not including padding
|
static constexpr int standardRotarySize{ 87 }; // Not including padding
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,12 @@ JustaSampleAudioProcessorEditor::JustaSampleAudioProcessorEditor(JustaSampleAudi
|
||||||
loopButton(true),
|
loopButton(true),
|
||||||
loopStartButton(true),
|
loopStartButton(true),
|
||||||
loopEndButton(true),
|
loopEndButton(true),
|
||||||
|
pingPongButton(true),
|
||||||
loopAttachment(p.APVTS(), PluginParameters::IS_LOOPING, loopButton),
|
loopAttachment(p.APVTS(), PluginParameters::IS_LOOPING, loopButton),
|
||||||
loopStartAttachment(p.APVTS(), PluginParameters::LOOPING_HAS_START, loopStartButton),
|
loopStartAttachment(p.APVTS(), PluginParameters::LOOPING_HAS_START, loopStartButton),
|
||||||
loopEndAttachment(p.APVTS(), PluginParameters::LOOPING_HAS_END, loopEndButton),
|
loopEndAttachment(p.APVTS(), PluginParameters::LOOPING_HAS_END, loopEndButton),
|
||||||
|
pingPongAttachment(p.APVTS(), PluginParameters::IS_PING_PONG, pingPongButton),
|
||||||
|
crossfadeAttachment(p.APVTS(), PluginParameters::CROSSFADE_SAMPLES, crossfadeRotary),
|
||||||
|
|
||||||
// Master module
|
// Master module
|
||||||
monoOutputAttachment(p.APVTS(), PluginParameters::MONO_OUTPUT, monoOutputButton),
|
monoOutputAttachment(p.APVTS(), PluginParameters::MONO_OUTPUT, monoOutputButton),
|
||||||
|
|
@ -179,6 +182,15 @@ JustaSampleAudioProcessorEditor::JustaSampleAudioProcessorEditor(JustaSampleAudi
|
||||||
loopEndButton.setHelpText("Loop with release portion");
|
loopEndButton.setHelpText("Loop with release portion");
|
||||||
addAndMakeVisible(&loopEndButton);
|
addAndMakeVisible(&loopEndButton);
|
||||||
|
|
||||||
|
pingPongButton.useShape(getOutlineFromSVG(BinaryData::IconPingPong_svg));
|
||||||
|
pingPongButton.setOwnerButton(&loopButton);
|
||||||
|
pingPongButton.setHelpText("Ping-pong loop");
|
||||||
|
addAndMakeVisible(&pingPongButton);
|
||||||
|
|
||||||
|
crossfadeRotary.getProperties().set(ComponentProps::ROTARY_UNIT, "samp");
|
||||||
|
crossfadeRotary.setHelpText("Loop crossfade length");
|
||||||
|
addAndMakeVisible(&crossfadeRotary);
|
||||||
|
|
||||||
monoOutputButton.useShape(getOutlineFromSVG(BinaryData::IconMono_svg));
|
monoOutputButton.useShape(getOutlineFromSVG(BinaryData::IconMono_svg));
|
||||||
monoOutputButton.setHelpText("Mix output to mono");
|
monoOutputButton.setHelpText("Mix output to mono");
|
||||||
addAndMakeVisible(&monoOutputButton);
|
addAndMakeVisible(&monoOutputButton);
|
||||||
|
|
@ -190,7 +202,7 @@ JustaSampleAudioProcessorEditor::JustaSampleAudioProcessorEditor(JustaSampleAudi
|
||||||
gainSlider.setHelpText("Sample gain");
|
gainSlider.setHelpText("Sample gain");
|
||||||
addAndMakeVisible(&gainSlider);
|
addAndMakeVisible(&gainSlider);
|
||||||
|
|
||||||
rotaries = { &semitoneRotary, &waveformSemitoneRotary, ¢Rotary, &waveformCentRotary, &attackTimeRotary, &releaseTimeRotary, &playbackSpeedRotary };
|
rotaries = { &semitoneRotary, &waveformSemitoneRotary, ¢Rotary, &waveformCentRotary, &attackTimeRotary, &releaseTimeRotary, &playbackSpeedRotary, &crossfadeRotary };
|
||||||
for (auto rotary : rotaries)
|
for (auto rotary : rotaries)
|
||||||
{
|
{
|
||||||
rotary->setSliderStyle(juce::Slider::RotaryVerticalDrag);
|
rotary->setSliderStyle(juce::Slider::RotaryVerticalDrag);
|
||||||
|
|
@ -651,22 +663,32 @@ void JustaSampleAudioProcessorEditor::resized()
|
||||||
loopingLabel.setBounds(loopingLabelBounds.toNearestInt());
|
loopingLabel.setBounds(loopingLabelBounds.toNearestInt());
|
||||||
|
|
||||||
loopModule.removeFromTop(scalei(Layout::moduleLabelGap));
|
loopModule.removeFromTop(scalei(Layout::moduleLabelGap));
|
||||||
loopModule.reduce(scalei(16.f), scalei(6.f));
|
loopModule.reduce(scalei(16.f) - rotaryPadding, scalei(6.f) - rotaryPadding);
|
||||||
|
|
||||||
loopStartButton.setBounds(loopModule.removeFromLeft(scalei(34.f)).toNearestInt());
|
loopStartButton.setBounds(loopModule.removeFromLeft(scalei(34.f)).toNearestInt());
|
||||||
loopStartButton.setBorder(scalef(2.5f), scalef(6.f), true, false, true, false);
|
loopStartButton.setBorder(scalef(2.5f), scalef(6.f), true, false, true, false);
|
||||||
loopStartButton.setPadding(scalef(8.f), scalef(4.f), scalef(7.5f), scalef(7.5f));
|
loopStartButton.setPadding(scalef(8.f), scalef(4.f), scalef(7.5f), scalef(7.5f));
|
||||||
|
|
||||||
loopModule.removeFromLeft(scalei(6.f));
|
loopModule.removeFromLeft(scalei(6.f));
|
||||||
loopButton.setBounds(loopModule.removeFromLeft(scalei(105.f)).toNearestInt());
|
loopButton.setBounds(loopModule.removeFromLeft(scalei(65.f)).toNearestInt());
|
||||||
loopButton.setBorder(scalef(2.5f));
|
loopButton.setBorder(scalef(2.5f));
|
||||||
loopButton.setPadding(scalef(13.f));
|
loopButton.setPadding(scalef(13.f));
|
||||||
|
|
||||||
|
loopModule.removeFromLeft(scalei(3.f));
|
||||||
|
pingPongButton.setBounds(loopModule.removeFromLeft(scalei(34.f)).toNearestInt());
|
||||||
|
pingPongButton.setBorder(scalef(2.5f), scalef(6.f));
|
||||||
|
pingPongButton.setPadding(scalef(8.f));
|
||||||
|
|
||||||
loopModule.removeFromLeft(scalei(6.f));
|
loopModule.removeFromLeft(scalei(6.f));
|
||||||
loopEndButton.setBounds(loopModule.removeFromLeft(scalei(34.f)).toNearestInt());
|
loopEndButton.setBounds(loopModule.removeFromLeft(scalei(34.f)).toNearestInt());
|
||||||
loopEndButton.setBorder(scalef(2.5f), scalef(6.f), false, true, false, true);
|
loopEndButton.setBorder(scalef(2.5f), scalef(6.f), false, true, false, true);
|
||||||
loopEndButton.setPadding(scalef(4.f), scalef(8.f), scalef(7.5f), scalef(7.5f));
|
loopEndButton.setPadding(scalef(4.f), scalef(8.f), scalef(7.5f), scalef(7.5f));
|
||||||
|
|
||||||
|
loopModule.removeFromLeft(scalei(6.f));
|
||||||
|
auto crossfadeRotaryBounds = loopModule.removeFromLeft(rotarySize + 2 * rotaryPadding);
|
||||||
|
crossfadeRotary.setBounds(crossfadeRotaryBounds.toNearestInt());
|
||||||
|
crossfadeRotary.sendLookAndFeelChange();
|
||||||
|
|
||||||
controls.removeFromLeft(scalei(Layout::moduleGap));
|
controls.removeFromLeft(scalei(Layout::moduleGap));
|
||||||
|
|
||||||
// Master module
|
// Master module
|
||||||
|
|
@ -787,6 +809,7 @@ void JustaSampleAudioProcessorEditor::lookAndFeelChanged()
|
||||||
loopButton.setColors(theme.dark, theme.loop, shadow);
|
loopButton.setColors(theme.dark, theme.loop, shadow);
|
||||||
loopStartButton.setColors(theme.dark, theme.loop, shadow);
|
loopStartButton.setColors(theme.dark, theme.loop, shadow);
|
||||||
loopEndButton.setColors(theme.dark, theme.loop, shadow);
|
loopEndButton.setColors(theme.dark, theme.loop, shadow);
|
||||||
|
pingPongButton.setColors(theme.dark, theme.loop, shadow);
|
||||||
monoOutputButton.setColors(theme.dark, theme.light, shadow);
|
monoOutputButton.setColors(theme.dark, theme.light, shadow);
|
||||||
linkSampleToggle.setColors(theme.dark, theme.slate.withAlpha(0.5f), shadow);
|
linkSampleToggle.setColors(theme.dark, theme.slate.withAlpha(0.5f), shadow);
|
||||||
waveformModeLabel.setColors(theme.foreground, theme.slate.withAlpha(0.f), shadow);
|
waveformModeLabel.setColors(theme.foreground, theme.slate.withAlpha(0.f), shadow);
|
||||||
|
|
@ -810,7 +833,7 @@ void JustaSampleAudioProcessorEditor::lookAndFeelChanged()
|
||||||
|
|
||||||
juce::Array<Component*> foregroundComponents = {
|
juce::Array<Component*> foregroundComponents = {
|
||||||
&tuningLabel, &attackLabel, &releaseLabel, &playbackLabel, &loopingLabel, &masterLabel, &semitoneRotary, &waveformSemitoneRotary, ¢Rotary, &waveformCentRotary, &tuningDetectLabel, &tuningDetectButton,
|
&tuningLabel, &attackLabel, &releaseLabel, &playbackLabel, &loopingLabel, &masterLabel, &semitoneRotary, &waveformSemitoneRotary, ¢Rotary, &waveformCentRotary, &tuningDetectLabel, &tuningDetectButton,
|
||||||
&attackTimeRotary, &attackCurve, &releaseTimeRotary, &releaseCurve, &lofiModeButton, &playbackModeButton, &playbackSpeedRotary, &loopStartButton, &loopButton, &loopEndButton,
|
&attackTimeRotary, &attackCurve, &releaseTimeRotary, &releaseCurve, &lofiModeButton, &playbackModeButton, &playbackSpeedRotary, &loopStartButton, &loopButton, &loopEndButton, &pingPongButton, &crossfadeRotary,
|
||||||
&monoOutputButton, &gainSlider, &filenameComponent, &linkSampleToggle, &playStopButton, &recordButton, &deviceSettingsButton, &fitButton, &pinButton, &sampleNavigator, &preFXButton, &showFXButton
|
&monoOutputButton, &gainSlider, &filenameComponent, &linkSampleToggle, &playStopButton, &recordButton, &deviceSettingsButton, &fitButton, &pinButton, &sampleNavigator, &preFXButton, &showFXButton
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1047,7 +1070,7 @@ void JustaSampleAudioProcessorEditor::enablementChanged()
|
||||||
&playStopButton, &fitButton, &pinButton, &sampleEditor, &sampleNavigator, &fxChain, &showFXButton
|
&playStopButton, &fitButton, &pinButton, &sampleEditor, &sampleNavigator, &fxChain, &showFXButton
|
||||||
};
|
};
|
||||||
|
|
||||||
juce::Array<Component*> notWaveformModeComponents = { &playbackModeButton, &loopStartButton, &loopButton, &loopEndButton, &tuningDetectLabel, &tuningDetectButton };
|
juce::Array<Component*> notWaveformModeComponents = { &playbackModeButton, &loopStartButton, &loopButton, &loopEndButton, &pingPongButton, &crossfadeRotary, &tuningDetectLabel, &tuningDetectButton };
|
||||||
|
|
||||||
juce::Array<Component*> notLoadingDependentComponents = { &tuningDetectButton, &tuningDetectLabel, &recordButton, &deviceSettingsButton };
|
juce::Array<Component*> notLoadingDependentComponents = { &tuningDetectButton, &tuningDetectLabel, &recordButton, &deviceSettingsButton };
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -182,8 +182,10 @@ private:
|
||||||
CustomRotaryAttachment playbackSpeedAttachment;
|
CustomRotaryAttachment playbackSpeedAttachment;
|
||||||
|
|
||||||
// Loop module
|
// Loop module
|
||||||
CustomToggleableButton loopButton, loopStartButton, loopEndButton;
|
CustomToggleableButton loopButton, loopStartButton, loopEndButton, pingPongButton;
|
||||||
APVTS::ButtonAttachment loopAttachment, loopStartAttachment, loopEndAttachment;
|
APVTS::ButtonAttachment loopAttachment, loopStartAttachment, loopEndAttachment, pingPongAttachment;
|
||||||
|
CustomRotary crossfadeRotary;
|
||||||
|
CustomRotaryAttachment crossfadeAttachment;
|
||||||
|
|
||||||
// Mixing module
|
// Mixing module
|
||||||
CustomToggleableButton monoOutputButton;
|
CustomToggleableButton monoOutputButton;
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ inline static const String PLAY_UNTIL_END{ "Play Until End" };
|
||||||
inline static const String IS_LOOPING{ "Loop" };
|
inline static const String IS_LOOPING{ "Loop" };
|
||||||
inline static const String LOOPING_HAS_START{ "Loop With Start" };
|
inline static const String LOOPING_HAS_START{ "Loop With Start" };
|
||||||
inline static const String LOOPING_HAS_END{ "Loop With End" };
|
inline static const String LOOPING_HAS_END{ "Loop With End" };
|
||||||
|
inline static const String IS_PING_PONG{ "Ping Pong" };
|
||||||
|
|
||||||
inline static const String PLAYBACK_MODE{ "Playback Mode" };
|
inline static const String PLAYBACK_MODE{ "Playback Mode" };
|
||||||
inline static const StringArray PLAYBACK_MODE_LABELS{ "Basic", "Bungee" }; // for IDs and display
|
inline static const StringArray PLAYBACK_MODE_LABELS{ "Basic", "Bungee" }; // for IDs and display
|
||||||
|
|
@ -381,6 +382,7 @@ inline juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout
|
||||||
addBool(layout, LOOPING_HAS_START, false, Version::V1);
|
addBool(layout, LOOPING_HAS_START, false, Version::V1);
|
||||||
addBool(layout, IS_LOOPING, false, Version::V1);
|
addBool(layout, IS_LOOPING, false, Version::V1);
|
||||||
addBool(layout, LOOPING_HAS_END, false, Version::V1);
|
addBool(layout, LOOPING_HAS_END, false, Version::V1);
|
||||||
|
addBool(layout, IS_PING_PONG, false, Version::V1_3_2);
|
||||||
|
|
||||||
addFloat(layout, SAMPLE_GAIN, 0.f, addSkew({ -32.f, 16.f, 0.1f }, 0.f), Version::V1, suffixF(" " + VOLUME_UNIT, 0.1f));
|
addFloat(layout, SAMPLE_GAIN, 0.f, addSkew({ -32.f, 16.f, 0.1f }, 0.f), Version::V1, suffixF(" " + VOLUME_UNIT, 0.1f));
|
||||||
addBool(layout, MONO_OUTPUT, false, Version::V1);
|
addBool(layout, MONO_OUTPUT, false, Version::V1);
|
||||||
|
|
|
||||||
|
|
@ -413,6 +413,7 @@ void JustaSampleAudioProcessor::loadSample(juce::AudioBuffer<float>& sample, int
|
||||||
// The order here is actually important, because the start and end buttons can otherwise enable the main loop button
|
// The order here is actually important, because the start and end buttons can otherwise enable the main loop button
|
||||||
pv(PluginParameters::LOOPING_HAS_START) = false;
|
pv(PluginParameters::LOOPING_HAS_START) = false;
|
||||||
pv(PluginParameters::LOOPING_HAS_END) = false;
|
pv(PluginParameters::LOOPING_HAS_END) = false;
|
||||||
|
pv(PluginParameters::IS_PING_PONG) = false;
|
||||||
pv(PluginParameters::IS_LOOPING) = false;
|
pv(PluginParameters::IS_LOOPING) = false;
|
||||||
|
|
||||||
pluginState.loopStart = 0;
|
pluginState.loopStart = 0;
|
||||||
|
|
|
||||||
|
|
@ -91,11 +91,17 @@ void CustomSamplerVoice::startNote(int midiNoteNumber, float velocity, juce::Syn
|
||||||
|
|
||||||
playUntilEnd = sampleSound.playUntilEnd->get();
|
playUntilEnd = sampleSound.playUntilEnd->get();
|
||||||
isLooping = sampleSound.isLooping->get() || wavetableMode;
|
isLooping = sampleSound.isLooping->get() || wavetableMode;
|
||||||
loopingHasStart = isLooping && sampleSound.loopingHasStart->get() && sampleSound.loopStart < sampleSound.sampleStart && !wavetableMode;
|
isPingPong = isLooping && sampleSound.isPingPong->get() && !wavetableMode;
|
||||||
|
loopingHasStart = isLooping && sampleSound.loopingHasStart->get() && sampleSound.loopStart < sampleSound.sampleStart && !wavetableMode && !isPingPong;
|
||||||
loopStart = sampleSound.loopStart;
|
loopStart = sampleSound.loopStart;
|
||||||
loopingHasEnd = isLooping && sampleSound.loopingHasEnd->get() && sampleSound.loopEnd > sampleSound.sampleEnd && !wavetableMode;
|
loopingHasEnd = isLooping && sampleSound.loopingHasEnd->get() && sampleSound.loopEnd > sampleSound.sampleEnd && !wavetableMode && !isPingPong;
|
||||||
loopEnd = sampleSound.loopEnd;
|
loopEnd = sampleSound.loopEnd;
|
||||||
|
|
||||||
|
if (isPingPong)
|
||||||
|
playbackMode = PluginParameters::BASIC; // BungeeStretcher is forward-only
|
||||||
|
|
||||||
|
pingPongDirection = 1.0f;
|
||||||
|
|
||||||
effectiveStart = loopingHasStart ? loopStart : sampleStart;
|
effectiveStart = loopingHasStart ? loopStart : sampleStart;
|
||||||
effectiveEnd = loopingHasEnd ? loopEnd : sampleEnd;
|
effectiveEnd = loopingHasEnd ? loopEnd : sampleEnd;
|
||||||
|
|
||||||
|
|
@ -264,6 +270,9 @@ void CustomSamplerVoice::renderNextBlock(juce::AudioBuffer<float>& outputBuffer,
|
||||||
|
|
||||||
updateSpeedAndPitch(getCurrentlyPlayingNote(), pitchWheel);
|
updateSpeedAndPitch(getCurrentlyPlayingNote(), pitchWheel);
|
||||||
|
|
||||||
|
if (isPingPong && isLooping)
|
||||||
|
speed *= pingPongDirection;
|
||||||
|
|
||||||
bool someFXEnabled{ false };
|
bool someFXEnabled{ false };
|
||||||
for (const auto& effect : effects)
|
for (const auto& effect : effects)
|
||||||
{
|
{
|
||||||
|
|
@ -350,7 +359,17 @@ void CustomSamplerVoice::renderNextBlock(juce::AudioBuffer<float>& outputBuffer,
|
||||||
con.speedMovedSinceRelease += 1;
|
con.speedMovedSinceRelease += 1;
|
||||||
|
|
||||||
// Handle transitions
|
// Handle transitions
|
||||||
if (con.state == PLAYING && isLooping && con.currentPosition >= sampleEnd - crossfade) // Loop crossfade
|
if (con.state == PLAYING && isLooping && isPingPong && pingPongDirection > 0 && con.currentPosition >= sampleEnd) // Ping-pong: reverse at end
|
||||||
|
{
|
||||||
|
pingPongDirection = -1.0f;
|
||||||
|
speed = std::abs(speed) * -1.0f;
|
||||||
|
}
|
||||||
|
else if (con.state == PLAYING && isLooping && isPingPong && pingPongDirection < 0 && con.currentPosition <= sampleStart) // Ping-pong: reverse at start
|
||||||
|
{
|
||||||
|
pingPongDirection = 1.0f;
|
||||||
|
speed = std::abs(speed);
|
||||||
|
}
|
||||||
|
else if (con.state == PLAYING && isLooping && !isPingPong && con.currentPosition >= sampleEnd - crossfade) // Loop crossfade
|
||||||
{
|
{
|
||||||
con.currentPosition -= (sampleEnd - sampleStart + 1) - crossfade;
|
con.currentPosition -= (sampleEnd - sampleStart + 1) - crossfade;
|
||||||
con.isCrossfadingLoop = true;
|
con.isCrossfadingLoop = true;
|
||||||
|
|
|
||||||
|
|
@ -219,8 +219,9 @@ private:
|
||||||
float noteVelocity{ 0.f };
|
float noteVelocity{ 0.f };
|
||||||
|
|
||||||
bool playUntilEnd{ false };
|
bool playUntilEnd{ false };
|
||||||
bool isLooping{ false }, loopingHasStart{ false }, loopingHasEnd{ false };
|
bool isLooping{ false }, loopingHasStart{ false }, loopingHasEnd{ false }, isPingPong{ false };
|
||||||
int sampleStart{ 0 }, sampleEnd{ 0 }, loopStart{ 0 }, loopEnd{ 0 };
|
int sampleStart{ 0 }, sampleEnd{ 0 }, loopStart{ 0 }, loopEnd{ 0 };
|
||||||
|
float pingPongDirection{ 1.0f };
|
||||||
|
|
||||||
/** We call this "smoothing" but it's a pretty normal attack/release envelope. */
|
/** We call this "smoothing" but it's a pretty normal attack/release envelope. */
|
||||||
float attackSmoothing{ 0.f }, releaseSmoothing{ 0.f };
|
float attackSmoothing{ 0.f }, releaseSmoothing{ 0.f };
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ SamplerParameters::SamplerParameters(const juce::AudioProcessorValueTreeState& a
|
||||||
isLooping(dynamic_cast<juce::AudioParameterBool*>(apvts.getParameter(PluginParameters::IS_LOOPING))),
|
isLooping(dynamic_cast<juce::AudioParameterBool*>(apvts.getParameter(PluginParameters::IS_LOOPING))),
|
||||||
loopingHasStart(dynamic_cast<juce::AudioParameterBool*>(apvts.getParameter(PluginParameters::LOOPING_HAS_START))),
|
loopingHasStart(dynamic_cast<juce::AudioParameterBool*>(apvts.getParameter(PluginParameters::LOOPING_HAS_START))),
|
||||||
loopingHasEnd(dynamic_cast<juce::AudioParameterBool*>(apvts.getParameter(PluginParameters::LOOPING_HAS_END))),
|
loopingHasEnd(dynamic_cast<juce::AudioParameterBool*>(apvts.getParameter(PluginParameters::LOOPING_HAS_END))),
|
||||||
|
isPingPong(dynamic_cast<juce::AudioParameterBool*>(apvts.getParameter(PluginParameters::IS_PING_PONG))),
|
||||||
|
|
||||||
sampleStart(pluginState.sampleStart), sampleEnd(pluginState.sampleEnd),
|
sampleStart(pluginState.sampleStart), sampleEnd(pluginState.sampleEnd),
|
||||||
loopStart(pluginState.loopStart), loopEnd(pluginState.loopEnd),
|
loopStart(pluginState.loopStart), loopEnd(pluginState.loopEnd),
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ public:
|
||||||
/** Playback details */
|
/** Playback details */
|
||||||
juce::AudioParameterFloat* gain, * speedFactor, * octaveSpeedFactor, * attack, * release, * attackShape, * releaseShape, * a4_freq, * pitchWheelRange, * wideTuningControl;
|
juce::AudioParameterFloat* gain, * speedFactor, * octaveSpeedFactor, * attack, * release, * attackShape, * releaseShape, * a4_freq, * pitchWheelRange, * wideTuningControl;
|
||||||
juce::AudioParameterInt* semitoneTuning, * centTuning, * waveformSemitoneTuning, * waveformCentTuning, * crossfadeSamples;
|
juce::AudioParameterInt* semitoneTuning, * centTuning, * waveformSemitoneTuning, * waveformCentTuning, * crossfadeSamples;
|
||||||
juce::AudioParameterBool* monoOutput, * disableVelocity, * skipAntialiasing, * applyFXPre, * playUntilEnd, * disableWavetableMode, * isLooping, * loopingHasStart, * loopingHasEnd;
|
juce::AudioParameterBool* monoOutput, * disableVelocity, * skipAntialiasing, * applyFXPre, * playUntilEnd, * disableWavetableMode, * isLooping, * loopingHasStart, * loopingHasEnd, * isPingPong;
|
||||||
ListenableAtomic<int>& sampleStart, & sampleEnd, & loopStart, & loopEnd;
|
ListenableAtomic<int>& sampleStart, & sampleEnd, & loopStart, & loopEnd;
|
||||||
|
|
||||||
juce::AudioParameterInt* midiStart, * midiEnd, * midiRoot;
|
juce::AudioParameterInt* midiStart, * midiEnd, * midiRoot;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue