diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp index 9f0db70..b449e3a 100644 --- a/Source/PluginEditor.cpp +++ b/Source/PluginEditor.cpp @@ -98,9 +98,19 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau m_render_button.onClick = [this]() { showRenderDialog(); }; } - addAndMakeVisible(m_rewind_button); - m_rewind_button.setButtonText("<<"); - m_rewind_button.onClick = [this]() + // jlc + m_rewind_button = std::make_unique("rewind", DrawableButton::ButtonStyle::ImageFitted); + std::unique_ptr rewimg(Drawable::createFromImageData(BinaryData::skipback_icon_svg, BinaryData::skipback_icon_svgSize)); + m_rewind_button->setImages(rewimg.get()); + m_rewind_button->setColour(TextButton::buttonColourId, Colours::transparentBlack); + m_rewind_button->setColour(TextButton::buttonOnColourId, Colours::transparentBlack); + m_rewind_button->setColour(DrawableButton::backgroundColourId, Colours::transparentBlack); + m_rewind_button->setColour(DrawableButton::backgroundOnColourId, Colours::transparentBlack); + + addAndMakeVisible(m_rewind_button.get()); + m_rewind_button->setTitle("Return to start"); + m_rewind_button->setTooltip("Return to start"); + m_rewind_button->onClick = [this]() { *processor.getBoolParameter(cpi_rewind) = true; //processor.getStretchSource()->seekPercent(processor.getStretchSource()->getPlayRange().getStart()); @@ -108,6 +118,7 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau addAndMakeVisible(&m_info_label); m_info_label.setJustificationType(Justification::centredRight); + m_info_label.setFont(14.0f); m_wavecomponent.GetFileCallback = [this]() { return processor.getAudioFile(); }; @@ -120,7 +131,13 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau if (parid->paramID.startsWith("fftsize") || parid->paramID.startsWith("numoutchans") || parid->paramID.startsWith("numinchans")) notifyonlyonrelease = true; - int group_id = -1; + + bool usedrawable = false; + if (i == cpi_pause_enabled || i == cpi_looping_enabled || i == cpi_capture_trigger || i == cpi_freeze || i == cpi_passthrough) + usedrawable = true; + + + int group_id = -1; if (i == cpi_harmonicsbw || i == cpi_harmonicsfreq || i == cpi_harmonicsgauss || i == cpi_numharmonics) group_id = HarmonicsGroup; if (i == cpi_octavesm2 || i == cpi_octavesm1 || i == cpi_octaves0 || i == cpi_octaves1 || i == cpi_octaves15 || @@ -148,7 +165,7 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau group_id = -2; if (group_id >= -1) { - m_parcomps.emplace_back(std::make_unique(pars[i], notifyonlyonrelease)); + m_parcomps.emplace_back(std::make_unique(pars[i], notifyonlyonrelease, usedrawable)); m_parcomps.back()->m_group_id = group_id; if (group_id == -1) // only add ones that aren't in groups @@ -166,6 +183,42 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau m_parcomps[cpi_num_outchans]->getSlider()->setSliderStyle(Slider::SliderStyle::IncDecButtons); m_parcomps[cpi_num_outchans]->getSlider()->setTextBoxStyle(Slider::TextEntryBoxPosition::TextBoxLeft, false, 30, 34); + removeChildComponent(m_parcomps[cpi_bypass_stretch].get()); + + + if (auto * pausebut = m_parcomps[cpi_pause_enabled]->getDrawableButton()) { + std::unique_ptr playimg(Drawable::createFromImageData(BinaryData::play_icon_svg, BinaryData::play_icon_svgSize)); + std::unique_ptr pauseimg(Drawable::createFromImageData(BinaryData::pause_icon_svg, BinaryData::pause_icon_svgSize)); + pausebut->setImages(pauseimg.get(), nullptr, nullptr, nullptr, playimg.get()); + pausebut->setColour(DrawableButton::backgroundColourId, Colour::fromFloatRGBA(0.1f, 0.5f, 0.1f, 0.55f)); + } + + if (auto * loopbut = m_parcomps[cpi_looping_enabled]->getDrawableButton()) { + std::unique_ptr loopimg(Drawable::createFromImageData(BinaryData::loop_icon_svg, BinaryData::loop_icon_svgSize)); + loopbut->setImages(loopimg.get()); + loopbut->setColour(DrawableButton::backgroundOnColourId, Colour::fromFloatRGBA(0.6, 0.4, 0.6, 0.4)); + } + + if (auto * recbut = m_parcomps[cpi_capture_trigger]->getDrawableButton()) { + std::unique_ptr reconimg(Drawable::createFromImageData(BinaryData::record_active_svg, BinaryData::record_active_svgSize)); + std::unique_ptr recoffimg(Drawable::createFromImageData(BinaryData::record_svg, BinaryData::record_svgSize)); + recbut->setImages(recoffimg.get(), nullptr, nullptr, nullptr, reconimg.get()); + recbut->setColour(DrawableButton::backgroundOnColourId, Colour::fromFloatRGBA(0.6, 0.3, 0.3, 0.5)); + } + + if (auto * freezebut = m_parcomps[cpi_freeze]->getDrawableButton()) { + std::unique_ptr img(Drawable::createFromImageData(BinaryData::freeze_svg, BinaryData::freeze_svgSize)); + freezebut->setImages(img.get()); + freezebut->setColour(DrawableButton::backgroundOnColourId, Colour::fromFloatRGBA(0.2, 0.5, 0.7, 0.55)); + } + + if (auto * thrubut = m_parcomps[cpi_passthrough]->getDrawableButton()) { + std::unique_ptr img(Drawable::createFromImageData(BinaryData::passthru_svg, BinaryData::passthru_svgSize)); + std::unique_ptr imgon(Drawable::createFromImageData(BinaryData::passthru_enabled_svg, BinaryData::passthru_enabled_svgSize)); + thrubut->setImages(img.get(), nullptr, nullptr, nullptr, imgon.get()); + thrubut->setColour(DrawableButton::backgroundOnColourId, Colour::fromFloatRGBA(0.5, 0.3, 0.0, 0.55)); + } + #if JUCE_IOS // just don't include chan counts on ios for now @@ -180,8 +233,9 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau addAndMakeVisible(m_groupviewport.get()); - m_stretchgroup = std::make_unique("", -1, &processor, false); + m_stretchgroup = std::make_unique("", -1, &processor, true); m_stretchgroup->setBackgroundColor(Colour(0xff332244)); + m_stretchgroup->setToggleEnabled( ! *processor.getBoolParameter(cpi_bypass_stretch)); if (*processor.getBoolParameter(cpi_bypass_stretch)) { m_stretchgroup->addParameterComponent(m_parcomps[cpi_dryplayrate].get()); removeChildComponent(m_parcomps[cpi_stretchamount].get()); @@ -190,6 +244,11 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau removeChildComponent(m_parcomps[cpi_dryplayrate].get()); } m_stretchgroup->addParameterComponent(m_parcomps[cpi_fftsize].get()); + m_stretchgroup->EnabledChangedCallback = [this]() { + toggleBool(processor.getBoolParameter(cpi_bypass_stretch)); + m_stretchgroup->setToggleEnabled( ! *processor.getBoolParameter(cpi_bypass_stretch)); + // jlc + }; addAndMakeVisible(m_stretchgroup.get()); @@ -451,7 +510,7 @@ void PaulstretchpluginAudioProcessorEditor::showRenderDialog() { auto contentraw = new RenderSettingsComponent(&processor); - int prefw = jmin(contentraw->getPreferredWidth(), getWidth() - 10); + int prefw = jmin(contentraw->getPreferredWidth(), getWidth() - 20); int prefh = jmin(contentraw->getPreferredHeight(), getHeight() - 10); contentraw->setSize(prefw, prefh); std::unique_ptr content(contentraw); @@ -577,7 +636,6 @@ void PaulstretchpluginAudioProcessorEditor::resized() { topbox.items.add(FlexItem(buttw, buttonrowheight, m_render_button).withMargin(1).withFlex(1).withMaxWidth(130)); } - topbox.items.add(FlexItem(buttminw, buttonrowheight, m_rewind_button).withMargin(1)); topbox.items.add(FlexItem(4, 4)); topbox.items.add(FlexItem(80, buttonrowheight, m_perfmeter).withMargin(1).withFlex(1).withMaxWidth(110).withMaxHeight(24).withAlignSelf(FlexItem::AlignSelf::center)); topbox.items.add(FlexItem(140, 26, m_info_label).withMargin(1).withFlex(2)); @@ -591,13 +649,23 @@ void PaulstretchpluginAudioProcessorEditor::resized() togglesbox.flexWrap = FlexBox::Wrap::wrap; togglesbox.alignContent = FlexBox::AlignContent::flexStart; - togglesbox.items.add(FlexItem(toggleminw, togglerowheight, *m_parcomps[cpi_capture_trigger]).withMargin(margin).withFlex(1).withMaxWidth(200)); - togglesbox.items.add(FlexItem(toggleminw, togglerowheight, *m_parcomps[cpi_passthrough]).withMargin(margin).withFlex(1.5).withMaxWidth(200)); + togglesbox.items.add(FlexItem(buttminw, buttonrowheight, *m_parcomps[cpi_capture_trigger]).withMargin(margin).withFlex(1).withMaxWidth(65)); + togglesbox.items.add(FlexItem(buttminw, buttonrowheight).withFlex(0.1)); - togglesbox.items.add(FlexItem(toggleminw, togglerowheight, *m_parcomps[cpi_pause_enabled]).withMargin(margin).withFlex(1).withMaxWidth(200)); - togglesbox.items.add(FlexItem(toggleminw, togglerowheight, *m_parcomps[cpi_freeze]).withMargin(margin).withFlex(1).withMaxWidth(200)); - togglesbox.items.add(FlexItem(toggleminw, togglerowheight, *m_parcomps[cpi_bypass_stretch]).withMargin(margin).withFlex(1).withMaxWidth(200)); - togglesbox.items.add(FlexItem(toggleminw, togglerowheight, *m_parcomps[cpi_looping_enabled]).withMargin(margin).withFlex(1).withMaxWidth(200)); + togglesbox.items.add(FlexItem(buttminw, buttonrowheight, *m_rewind_button).withMargin(1).withFlex(1).withMaxWidth(65)); + togglesbox.items.add(FlexItem(0, buttonrowheight).withFlex(0.1).withMaxWidth(10)); + togglesbox.items.add(FlexItem(buttminw, buttonrowheight, *m_parcomps[cpi_pause_enabled]).withMargin(margin).withFlex(1).withMaxWidth(65)); + togglesbox.items.add(FlexItem(0, buttonrowheight).withFlex(0.1).withMaxWidth(10)); + togglesbox.items.add(FlexItem(buttminw, buttonrowheight, *m_parcomps[cpi_looping_enabled]).withMargin(margin).withFlex(1).withMaxWidth(65)); + togglesbox.items.add(FlexItem(0, buttonrowheight).withFlex(0.1).withMaxWidth(10)); + togglesbox.items.add(FlexItem(buttminw, buttonrowheight, *m_parcomps[cpi_freeze]).withMargin(margin).withFlex(1).withMaxWidth(65)); + + togglesbox.items.add(FlexItem(buttminw, buttonrowheight).withFlex(0.1)); + + //togglesbox.items.add(FlexItem(toggleminw, togglerowheight, *m_parcomps[cpi_bypass_stretch]).withMargin(margin).withFlex(1).withMaxWidth(150)); + togglesbox.items.add(FlexItem(buttminw + 15, buttonrowheight, *m_parcomps[cpi_passthrough]).withMargin(margin).withFlex(1.5).withMaxWidth(85)); + + togglesbox.items.add(FlexItem(2, buttonrowheight)); togglesbox.performLayout(Rectangle(0,0,w - 2*margin,400)); // test run to calculate actual used height int toggleh = togglesbox.items.getLast().currentBounds.getBottom() + togglesbox.items.getLast().margin.bottom; @@ -625,7 +693,7 @@ void PaulstretchpluginAudioProcessorEditor::resized() volbox.performLayout(Rectangle(0,0,w - 2*margin,400)); // test run to calculate actual used height int volh = volbox.items.getLast().currentBounds.getBottom() + volbox.items.getLast().margin.bottom; int stretchH = m_stretchgroup->getMinimumHeight(w - 2*margin); - + stretchH = jmax(stretchH, (int) (minh*1.1f)); FlexBox groupsbox; @@ -719,6 +787,7 @@ void PaulstretchpluginAudioProcessorEditor::resized() mainbox.items.add(FlexItem(minw, topboxh, topbox).withMargin(margin).withFlex(0)); + mainbox.items.add(FlexItem(minw, toggleh, togglesbox).withMargin(margin).withFlex(0)); auto reparentIfNecessary = [] (Component * comp, Component *newparent) { @@ -747,14 +816,14 @@ void PaulstretchpluginAudioProcessorEditor::resized() // not enough vertical space, put the top items in the scrollable viewport // may have to reparent them reparentIfNecessary(m_stretchgroup.get(), m_groupcontainer.get()); - reparentItemsIfNecessary(togglesbox, m_groupcontainer.get()); + //reparentItemsIfNecessary(togglesbox, m_groupcontainer.get()); reparentItemsIfNecessary(volbox, m_groupcontainer.get()); groupsbox.items.insert(0, FlexItem(minw, stretchH, *m_stretchgroup).withMargin(groupmargin).withFlex(0)); groupsbox.items.insert(0, FlexItem(minw, volh, volbox).withMargin(groupmargin).withFlex(0)); - groupsbox.items.insert(0, FlexItem(minw, toggleh, togglesbox).withMargin(groupmargin).withFlex(0)); + //groupsbox.items.insert(0, FlexItem(minw, toggleh, togglesbox).withMargin(groupmargin).withFlex(0)); - useh += toggleh + volh + stretchH + 6*groupmargin; + useh += /*toggleh + */ volh + stretchH + 6*groupmargin; if (getHeight() < shortthresh) { // really not much space, put group scroll in a new tab @@ -797,11 +866,11 @@ void PaulstretchpluginAudioProcessorEditor::resized() reparentIfNecessary(m_groupviewport.get(), this); reparentIfNecessary(&m_spec_order_ed, this); reparentIfNecessary(m_stretchgroup.get(), this); - reparentItemsIfNecessary(togglesbox, this); + //reparentItemsIfNecessary(togglesbox, this); reparentItemsIfNecessary(volbox, this); - mainbox.items.add(FlexItem(minw, toggleh, togglesbox).withMargin(margin).withFlex(0)); + //mainbox.items.add(FlexItem(minw, toggleh, togglesbox).withMargin(margin).withFlex(0)); mainbox.items.add(FlexItem(minw, volh, volbox).withMargin(margin).withFlex(0)); mainbox.items.add(FlexItem(minw, stretchH, *m_stretchgroup).withMargin(margin).withFlex(0)); } @@ -862,6 +931,13 @@ void PaulstretchpluginAudioProcessorEditor::timerCallback(int id) { if (id == 1) { + if (!tooltipWindow && getParentComponent()) { + Component* dw = this; + if (dw) { + tooltipWindow = std::make_unique(this, dw); + } + } + for (int i = 0; i < m_parcomps.size(); ++i) { if (m_parcomps[i]!=nullptr) @@ -911,7 +987,8 @@ void PaulstretchpluginAudioProcessorEditor::timerCallback(int id) group.second->updateParameterComponents(); } - ; + m_stretchgroup->setToggleEnabled(!*processor.getBoolParameter(cpi_bypass_stretch)); + if (AudioParameterBool* enablepar = dynamic_cast(processor.getBoolParameter(cpi_pause_enabled))) { m_perfmeter.enabled = !enablepar->get(); } @@ -1060,9 +1137,10 @@ void PaulstretchpluginAudioProcessorEditor::showAbout() #if !JUCE_IOS text += juceversiontxt + String(" used under the GPL license.\n\n"); - text += String("GPL licensed source code for this plugin at : https://bitbucket.org/xenakios/paulstretchplugin/overview\n"); #endif + // text += String("GPL licensed source code for this plugin at : https://bitbucket.org/xenakios/paulstretchplugin/overview\n"); + if (host.type != juce::PluginHostType::UnknownHost) { text += String("Running in : ") + host.getHostDescription()+ String("\n"); } @@ -1770,7 +1848,8 @@ void SpectralChainEditor::drawBox(Graphics & g, int index, int x, int y, int w, g.setColour(Colours::white.withAlpha(0.8f)); } -ParameterComponent::ParameterComponent(AudioProcessorParameter * par, bool notifyOnlyOnRelease) : m_par(par) +ParameterComponent::ParameterComponent(AudioProcessorParameter * par, bool notifyOnlyOnRelease, bool useDrawableToggle) +: m_par(par) { addAndMakeVisible(&m_label); m_labeldefcolor = m_label.findColour(Label::textColourId); @@ -1789,6 +1868,8 @@ ParameterComponent::ParameterComponent(AudioProcessorParameter * par, bool notif m_slider->setDoubleClickReturnValue(true, floatpar->range.convertFrom0to1(par->getDefaultValue())); m_slider->setViewportIgnoreDragFlag(true); m_slider->setScrollWheelEnabled(false); + m_slider->setTitle(floatpar->getName(50)); + } AudioParameterInt* intpar = dynamic_cast(par); if (intpar) @@ -1800,7 +1881,9 @@ ParameterComponent::ParameterComponent(AudioProcessorParameter * par, bool notif m_slider->setTextBoxStyle(Slider::TextBoxLeft, false, 60, 34); m_slider->addListener(this); m_slider->setViewportIgnoreDragFlag(true); - m_slider->setScrollWheelEnabled(false); + m_slider->setScrollWheelEnabled(false + ); + m_slider->setTitle(intpar->getName(50)); } AudioParameterChoice* choicepar = dynamic_cast(par); if (choicepar) @@ -1810,11 +1893,27 @@ ParameterComponent::ParameterComponent(AudioProcessorParameter * par, bool notif AudioParameterBool* boolpar = dynamic_cast(par); if (boolpar) { - m_togglebut = std::make_unique(); - m_togglebut->setToggleState(*boolpar, dontSendNotification); - m_togglebut->addListener(this); - m_togglebut->setButtonText(par->getName(50)); - addAndMakeVisible(m_togglebut.get()); + if (useDrawableToggle) { + m_drawtogglebut = std::make_unique("but", DrawableButton::ImageFitted); + m_drawtogglebut->setToggleState(*boolpar, dontSendNotification); + m_drawtogglebut->addListener(this); + m_drawtogglebut->setTitle(par->getName(50)); + m_drawtogglebut->setTooltip(par->getName(50)); + m_drawtogglebut->setClickingTogglesState(true); + m_drawtogglebut->setColour(TextButton::buttonColourId, Colours::transparentBlack); + m_drawtogglebut->setColour(TextButton::buttonOnColourId, Colours::transparentBlack); + m_drawtogglebut->setColour(DrawableButton::backgroundColourId, Colours::transparentBlack); + m_drawtogglebut->setColour(DrawableButton::backgroundOnColourId, Colours::transparentBlack); + + addAndMakeVisible(m_drawtogglebut.get()); + } + else { + m_togglebut = std::make_unique(); + m_togglebut->setToggleState(*boolpar, dontSendNotification); + m_togglebut->addListener(this); + m_togglebut->setButtonText(par->getName(50)); + addAndMakeVisible(m_togglebut.get()); + } } } @@ -1830,8 +1929,13 @@ void ParameterComponent::resized() m_label.setBounds(0, 0, labw, h); m_slider->setBounds(m_label.getRight() + 1, 0, getWidth() - 2 - m_label.getWidth(), h); } - if (m_togglebut) + else if (m_togglebut) { m_togglebut->setBounds(1, 0, getWidth() - 1, h); + } + else if (m_drawtogglebut) { + m_drawtogglebut->setBounds(1, 0, getWidth() - 1, h); + } + } void ParameterComponent::sliderValueChanged(Slider * slid) @@ -1872,6 +1976,11 @@ void ParameterComponent::buttonClicked(Button * but) if (m_togglebut->getToggleState()!=*boolpar) *boolpar = m_togglebut->getToggleState(); } + else if (m_drawtogglebut != nullptr) + { + if (m_drawtogglebut->getToggleState() != *boolpar) + *boolpar = m_drawtogglebut->getToggleState(); + } } void ParameterComponent::updateComponent() @@ -1887,11 +1996,18 @@ void ParameterComponent::updateComponent() m_slider->setValue(*intpar, dontSendNotification); } AudioParameterBool* boolpar = dynamic_cast(m_par); - if (boolpar!=nullptr && m_togglebut != nullptr) - { - if (m_togglebut->getToggleState() != *boolpar) - m_togglebut->setToggleState(*boolpar, dontSendNotification); - } + if (boolpar!=nullptr) { + if ( m_togglebut != nullptr) + { + if (m_togglebut->getToggleState() != *boolpar) + m_togglebut->setToggleState(*boolpar, dontSendNotification); + } + else if ( m_drawtogglebut != nullptr) + { + if (m_drawtogglebut->getToggleState() != *boolpar) + m_drawtogglebut->setToggleState(*boolpar, dontSendNotification); + } + } } void ParameterComponent::setHighLighted(bool b) @@ -1901,12 +2017,16 @@ void ParameterComponent::setHighLighted(bool b) m_label.setColour(Label::textColourId, m_labeldefcolor); if (m_togglebut) m_togglebut->setColour(ToggleButton::textColourId, m_labeldefcolor); + //else if (m_drawtogglebut) + // m_drawtogglebut->setColour(ToggleButton::textColourId, m_labeldefcolor); } else { m_label.setColour(Label::textColourId, Colours::yellow); if (m_togglebut) m_togglebut->setColour(ToggleButton::textColourId, Colours::yellow); + //else if (m_drawtogglebut) + // m_drawtogglebut->setColour(ToggleButton::textColourId, Colours::yellow); } } @@ -2179,22 +2299,26 @@ void RatioMixerEditor::paint(Graphics & g) FreeFilterComponent::FreeFilterComponent(PaulstretchpluginAudioProcessor* proc) : m_env(proc->getStretchSource()->getMutex()), m_cs(proc->getStretchSource()->getMutex()), m_proc(proc) { + m_viewport = std::make_unique(); + m_viewport->setViewedComponent(&m_container, false); + addAndMakeVisible(m_viewport.get()); + addAndMakeVisible(m_env); const auto& pars = m_proc->getParameters(); m_parcomps.emplace_back(std::make_unique(pars[cpi_freefilter_shiftx],false)); - addAndMakeVisible(m_parcomps.back().get()); + m_container.addAndMakeVisible(m_parcomps.back().get()); m_parcomps.emplace_back(std::make_unique(pars[cpi_freefilter_shifty], false)); - addAndMakeVisible(m_parcomps.back().get()); + m_container.addAndMakeVisible(m_parcomps.back().get()); m_parcomps.emplace_back(std::make_unique(pars[cpi_freefilter_scaley], false)); - addAndMakeVisible(m_parcomps.back().get()); + m_container.addAndMakeVisible(m_parcomps.back().get()); m_parcomps.emplace_back(std::make_unique(pars[cpi_freefilter_tilty], false)); - addAndMakeVisible(m_parcomps.back().get()); + m_container.addAndMakeVisible(m_parcomps.back().get()); m_parcomps.emplace_back(std::make_unique(pars[cpi_freefilter_randomy_numbands], false)); - addAndMakeVisible(m_parcomps.back().get()); + m_container.addAndMakeVisible(m_parcomps.back().get()); m_parcomps.emplace_back(std::make_unique(pars[cpi_freefilter_randomy_rate], false)); - addAndMakeVisible(m_parcomps.back().get()); + m_container.addAndMakeVisible(m_parcomps.back().get()); m_parcomps.emplace_back(std::make_unique(pars[cpi_freefilter_randomy_amount], false)); - addAndMakeVisible(m_parcomps.back().get()); + m_container.addAndMakeVisible(m_parcomps.back().get()); } void FreeFilterComponent::resized() @@ -2208,30 +2332,65 @@ void FreeFilterComponent::resized() #endif FlexBox mainbox; - mainbox.flexDirection = FlexBox::Direction::row; - - - m_env.setBounds(m_slidwidth, 0, getWidth() - m_slidwidth, getHeight()); FlexBox slidbox; slidbox.flexDirection = FlexBox::Direction::column; + slidbox.items.add(FlexItem(3, 2).withMargin(0)); + + for (int i = 0; i < m_parcomps.size(); ++i) - { - //m_parcomps[i]->setBounds(1, 1+25*i, m_slidwidth - 2, 24); + { + //m_parcomps[i]->setBounds(1, 1+25*i, m_slidwidth - 2, 24); slidbox.items.add(FlexItem(minslidwidth, slidh, *m_parcomps[i]).withMargin(margin).withFlex(0)); } - mainbox.items.add(FlexItem(minslidwidth, 50, slidbox).withMargin(0).withFlex(1).withMaxWidth(m_slidwidth)); - mainbox.items.add(FlexItem(100, 50, m_env).withMargin(0).withFlex(3)); + int minh = 0; + for (auto & item : slidbox.items ) { + minh += item.minHeight + item.margin.top + item.margin.bottom; + } + + int vpminh = 3*slidh + 3*margin; + + if (minslidwidth < getWidth() * 0.4) { + + mainbox.flexDirection = FlexBox::Direction::row; + + //m_env.setBounds(m_slidwidth, 0, getWidth() - m_slidwidth, getHeight()); + + + + mainbox.items.add(FlexItem(minslidwidth, vpminh, *m_viewport).withMargin(0).withFlex(1).withMaxWidth(m_slidwidth)); + mainbox.items.add(FlexItem(100, 50, m_env).withMargin(0).withFlex(3)); + } + else { + mainbox.flexDirection = FlexBox::Direction::column; + + //m_env.setBounds(m_slidwidth, 0, getWidth() - m_slidwidth, getHeight()); + + slidbox.flexDirection = FlexBox::Direction::column; + slidbox.flexWrap = FlexBox::Wrap::wrap; + + + mainbox.items.add(FlexItem(minslidwidth, vpminh, *m_viewport).withMargin(0).withFlex(0)); + mainbox.items.add(FlexItem(100, 3).withMargin(0)); + mainbox.items.add(FlexItem(100, 50, m_env).withMargin(0).withFlex(3)); + } + mainbox.performLayout(getLocalBounds()); + + auto contw = m_viewport->getWidth() - (minh > m_viewport->getHeight() ? m_viewport->getScrollBarThickness() : 0); + auto contbounds = Rectangle(0, 0, contw, minh); + m_container.setBounds(contbounds); + slidbox.performLayout(contbounds); + } void FreeFilterComponent::paint(Graphics & g) { g.setColour(Colour(0xff222222)); - g.fillRect(0, 0, m_slidwidth, getHeight()); + g.fillRect(0, 0, getWidth(), getHeight()); } void FreeFilterComponent::updateParameterComponents() @@ -2263,14 +2422,20 @@ ParameterGroupComponent::ParameterGroupComponent(const String & name_, int group m_enableButton->setColour(DrawableButton::backgroundOnColourId, Colours::transparentBlack); m_enableButton->onClick = [this]() { - auto order = m_proc->getStretchSource()->getSpectrumProcessOrder(); - for (int i=0; i < order.size(); ++i) { - if (order[i].m_index == groupId) { - toggleBool(order[i].m_enabled); - m_enableButton->setToggleState(order[i].m_enabled->get(), dontSendNotification); - if (EnabledChangedCallback) - EnabledChangedCallback(); - break; + if (groupId < 0) { + if (EnabledChangedCallback) + EnabledChangedCallback(); + } + else { + auto order = m_proc->getStretchSource()->getSpectrumProcessOrder(); + for (int i=0; i < order.size(); ++i) { + if (order[i].m_index == groupId) { + toggleBool(order[i].m_enabled); + m_enableButton->setToggleState(order[i].m_enabled->get(), dontSendNotification); + if (EnabledChangedCallback) + EnabledChangedCallback(); + break; + } } } }; @@ -2291,7 +2456,6 @@ int ParameterGroupComponent::getMinimumHeight(int forWidth) return m_minHeight; } - void ParameterGroupComponent::addParameterComponent(ParameterComponent * pcomp) { if (pcomp) { @@ -2381,7 +2545,7 @@ void ParameterGroupComponent::resized() void ParameterGroupComponent::paint(Graphics & g) { - if (m_enableButton && m_enableButton->getToggleState()) { + if (m_enableButton && groupId >= 0 && m_enableButton->getToggleState()) { g.setColour(m_selbgcolor); } else { g.setColour(m_bgcolor); @@ -2394,7 +2558,7 @@ void ParameterGroupComponent::updateParameterComponents() { bool enabled = true; - if (m_enableButton) { + if (m_enableButton && groupId >= 0) { auto order = m_proc->getStretchSource()->getSpectrumProcessOrder(); for (int i=0; i < order.size(); ++i) { if (order[i].m_index == groupId) { diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h index e177a76..9bfaa7c 100644 --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -85,7 +85,7 @@ class ParameterComponent : public Component, public Slider::Listener, public Button::Listener { public: - ParameterComponent(AudioProcessorParameter* par, bool notifyOnlyOnRelease); + ParameterComponent(AudioProcessorParameter* par, bool notifyOnlyOnRelease, bool useDrawableToggle=false); void resized() override; void sliderValueChanged(Slider* slid) override; void sliderDragStarted(Slider* slid) override; @@ -94,14 +94,18 @@ public: void updateComponent(); void setHighLighted(bool b); int m_group_id = -1; - Slider* getSlider() { return m_slider.get(); } - + Slider* getSlider() const { return m_slider.get(); } + + DrawableButton* getDrawableButton() const { return m_drawtogglebut.get(); } + ToggleButton* getToggleButton() const { return m_togglebut.get(); } + private: Label m_label; AudioProcessorParameter* m_par = nullptr; std::unique_ptr m_slider; std::unique_ptr m_combobox; std::unique_ptr m_togglebut; + std::unique_ptr m_drawtogglebut; bool m_notify_only_on_release = false; bool m_dragging = false; Colour m_labeldefcolor; @@ -124,6 +128,9 @@ public: void setBackgroundColor(Colour col) { m_bgcolor = col; } Colour getBackgroundColor() const { return m_bgcolor; } + void setToggleEnabled(bool flag){ if (m_enableButton) m_enableButton->setToggleState(flag, dontSendNotification); } + bool getToggleEnabled() const { if (m_enableButton) return m_enableButton->getToggleState(); return false; } + String name; int groupId = -1; @@ -305,7 +312,9 @@ public: private: EnvelopeComponent m_env; uptrvec m_parcomps; - CriticalSection* m_cs = nullptr; + std::unique_ptr m_viewport; + Component m_container; + CriticalSection* m_cs = nullptr; PaulstretchpluginAudioProcessor* m_proc = nullptr; int m_slidwidth = 350; }; @@ -563,7 +572,7 @@ private: TextButton m_import_button; TextButton m_settings_button; TextButton m_render_button; - TextButton m_rewind_button; + std::unique_ptr m_rewind_button; Label m_info_label; SpectralChainEditor m_spec_order_ed; double m_lastspec_select_time = 0.0; @@ -586,7 +595,33 @@ private: std::unique_ptr m_filechooser; std::unique_ptr fileChooser; WildcardFileFilter m_filefilter; - + + class CustomTooltipWindow : public TooltipWindow + { + public: + CustomTooltipWindow(PaulstretchpluginAudioProcessorEditor * parent_, Component * viewparent) : TooltipWindow(viewparent), parent(parent_) {} + virtual ~CustomTooltipWindow() { + if (parent) { + // reset our smart pointer without a delete! someone else is deleting it + parent->tooltipWindow.release(); + } + } + + /* + String getTipFor (Component& c) override + { + if (parent->popTip && parent->popTip->isShowing()) { + return {}; + } + return TooltipWindow::getTipFor(c); + } + */ + + PaulstretchpluginAudioProcessorEditor * parent; + }; + + std::unique_ptr tooltipWindow; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PaulstretchpluginAudioProcessorEditor) }; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 6de8e64..84bb099 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -227,7 +227,7 @@ PaulstretchpluginAudioProcessor::~PaulstretchpluginAudioProcessor() if (m_thumb) m_thumb->removeAllChangeListeners(); m_thumb = nullptr; - m_bufferingthread.stopThread(1000); + m_bufferingthread.stopThread(3000); } void PaulstretchpluginAudioProcessor::resetParameters() @@ -489,8 +489,10 @@ void PaulstretchpluginAudioProcessor::startplay(Range playrange, int num m_bufferingthread, false, bufamt, numoutchans, false); m_recreate_buffering_source = false; } - if (m_bufferingthread.isThreadRunning() == false) - m_bufferingthread.startThread(); + if (m_bufferingthread.isThreadRunning() == false) { + m_bufferingthread.setPriority(8); + m_bufferingthread.startThread(); + } m_stretch_source->setNumOutChannels(numoutchans); m_stretch_source->setFFTSize(m_fft_size_to_use); m_stretch_source->setProcessParameters(&m_ppar); diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index fcbf6da..e2b9e1a 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -277,7 +277,7 @@ private: std::vector m_bufamounts{ 4096,8192,16384,32768,65536,262144 }; ProcessParameters m_ppar; int mPluginWindowWidth = 820; - int mPluginWindowHeight = 700; + int mPluginWindowHeight = 710; void setFFTSize(double size); void startplay(Range playrange, int numoutchans, int maxBlockSize, String& err); diff --git a/Source/envelope_component.cpp b/Source/envelope_component.cpp index eb250dc..7c68b31 100644 --- a/Source/envelope_component.cpp +++ b/Source/envelope_component.cpp @@ -25,6 +25,14 @@ EnvelopeComponent::EnvelopeComponent(CriticalSection* cs) : m_cs(cs) XFromNormalized = [](double x) { return x; }; addChildComponent(&m_bubble); setOpaque(true); + +//#if JUCE_IOS + m_menubutton.setButtonText("..."); + m_menubutton.onClick = [this]() { + showPopupMenu(); + }; + addAndMakeVisible(&m_menubutton); +//#endif } EnvelopeComponent::~EnvelopeComponent() @@ -50,6 +58,16 @@ void EnvelopeComponent::show_bubble(int x, int y, const envelope_point& node) m_bubble.showAt({ x,y,100,20 }, temp , 5000); } +void EnvelopeComponent::resized() +{ +//#if JUCE_IOS + int butw = 38; + int buth = 38; + m_menubutton.setBounds(getWidth() - butw - 1, 1, butw, buth); +//#endif +} + + void EnvelopeComponent::paint(Graphics& g) { float targsize = 8.0; @@ -223,51 +241,57 @@ void EnvelopeComponent::mouseMove(const MouseEvent & ev) } } +void EnvelopeComponent::showPopupMenu() +{ + PopupMenu menu; + PopupMenu::Options opts; + menu.addItem(1, "Reset"); + menu.addItem(2, "Invert"); + menu.addItem(3, "Wrap envelope X transform", true, m_envelope->m_transform_wrap_x); + menu.addItem(4, "Envelope Y random linear interpolation", true, m_envelope->m_transform_y_random_linear_interpolation); +#if JUCE_IOS + opts = opts.withStandardItemHeight(34); +#endif + auto callback = [this] (int r) { + if (r == 1) + { + ScopedLock locker(*m_cs); + m_envelope->ResetEnvelope(); + } + if (r == 2) + { + for (int i = 0; i < m_envelope->GetNumPoints(); ++i) + { + double val = 1.0 - m_envelope->GetNodeAtIndex(i).pt_y; + m_envelope->GetNodeAtIndex(i).pt_y = val; + } + } + if (r == 3) + { + toggleBool(m_envelope->m_transform_wrap_x); + } + if (r == 4) + { + toggleBool(m_envelope->m_transform_y_random_linear_interpolation); + } + repaint(); + }; + + if (!JUCEApplicationBase::isStandaloneApp()) { + opts = opts.withParentComponent(this); + } + + + menu.showMenuAsync(opts, callback); +} + void EnvelopeComponent::mouseDown(const MouseEvent & ev) { if (m_envelope == nullptr) return; if (ev.mods.isRightButtonDown() == true) { - PopupMenu menu; - PopupMenu::Options opts; - menu.addItem(1, "Reset"); - menu.addItem(2, "Invert"); - menu.addItem(3, "Wrap envelope X transform", true, m_envelope->m_transform_wrap_x); - menu.addItem(4, "Envelope Y random linear interpolation", true, m_envelope->m_transform_y_random_linear_interpolation); - - auto callback = [this] (int r) { - if (r == 1) - { - ScopedLock locker(*m_cs); - m_envelope->ResetEnvelope(); - } - if (r == 2) - { - for (int i = 0; i < m_envelope->GetNumPoints(); ++i) - { - double val = 1.0 - m_envelope->GetNodeAtIndex(i).pt_y; - m_envelope->GetNodeAtIndex(i).pt_y = val; - } - } - if (r == 3) - { - toggleBool(m_envelope->m_transform_wrap_x); - } - if (r == 4) - { - toggleBool(m_envelope->m_transform_y_random_linear_interpolation); - } - repaint(); - }; - - if (!JUCEApplicationBase::isStandaloneApp()) { - opts = opts.withParentComponent(this); - } - - - menu.showMenuAsync(opts, callback); - + showPopupMenu(); return; } m_node_to_drag = find_hot_envelope_point(ev.x, ev.y); @@ -312,7 +336,9 @@ void EnvelopeComponent::mouseDown(const MouseEvent & ev) m_envelope->SortNodes(); m_cs->exit(); m_envelope->updateMinMaxValues(); - m_mouse_down = false; + + m_node_to_drag = find_hot_envelope_point(ev.x, ev.y); + //m_mouse_down = false; OnEnvelopeEdited(m_envelope.get()); repaint(); } @@ -413,7 +439,7 @@ int EnvelopeComponent::find_hot_envelope_point(double xcor, double ycor) double ptycor = (double)getHeight() - jmap(pt.pt_y, m_view_start_value, m_view_end_value, 0.0, (double)getHeight()); float targsize = 8.0; #if JUCE_IOS - targsize = 16.0; + targsize = 20; #endif juce::Rectangle target(ptxcor - targsize*0.5f, ptycor - targsize*0.5, targsize, targsize); if (target.contains(xcor, ycor) == true) @@ -428,7 +454,7 @@ int EnvelopeComponent::findHotEnvelopeSegment(double xcor, double ycor, bool det { float targsize = 8.0; #if JUCE_IOS - targsize = 16.0; + targsize = 20.0; #endif if (m_envelope == nullptr) diff --git a/Source/envelope_component.h b/Source/envelope_component.h index 54f712f..a00dbfa 100644 --- a/Source/envelope_component.h +++ b/Source/envelope_component.h @@ -32,6 +32,7 @@ public: EnvelopeComponent(CriticalSection* cs); ~EnvelopeComponent(); void paint(Graphics& g) override; + void resized() override; void set_envelope(std::shared_ptr env, String name = String()); std::shared_ptr get_envelope() { return m_envelope; } String get_name() { return m_name; } @@ -53,6 +54,8 @@ public: void timerCallback(int id) override; //String getTooltip() override; private: + void showPopupMenu(); + std::shared_ptr m_envelope; String m_name; Colour m_env_color{ Colours::yellow }; @@ -68,6 +71,7 @@ private: int m_node_that_was_dragged = -1; String m_last_tip; BubbleMessageComponent m_bubble; + TextButton m_menubutton; void show_bubble(int x, int y, const envelope_point &node); CriticalSection* m_cs = nullptr; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(EnvelopeComponent) diff --git a/images/freeze.svg b/images/freeze.svg new file mode 100644 index 0000000..ad898e9 --- /dev/null +++ b/images/freeze.svg @@ -0,0 +1,119 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/images/loop_icon.svg b/images/loop_icon.svg new file mode 100644 index 0000000..785faf3 --- /dev/null +++ b/images/loop_icon.svg @@ -0,0 +1,137 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/passthru.svg b/images/passthru.svg new file mode 100644 index 0000000..f54bd1b --- /dev/null +++ b/images/passthru.svg @@ -0,0 +1,74 @@ + +Benjamin J Sperryimage/svg+xml diff --git a/images/passthru_enabled.svg b/images/passthru_enabled.svg new file mode 100644 index 0000000..c373f35 --- /dev/null +++ b/images/passthru_enabled.svg @@ -0,0 +1,75 @@ + +Benjamin J Sperryimage/svg+xml diff --git a/images/paulxstretch_icon.svg b/images/paulxstretch_icon.svg new file mode 100644 index 0000000..1742133 --- /dev/null +++ b/images/paulxstretch_icon.svg @@ -0,0 +1,224 @@ + +Benjamin J Sperryimage/svg+xmlPS diff --git a/images/pause_icon.svg b/images/pause_icon.svg new file mode 100644 index 0000000..5510c71 --- /dev/null +++ b/images/pause_icon.svg @@ -0,0 +1,129 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/play_icon.svg b/images/play_icon.svg new file mode 100644 index 0000000..a93b7e3 --- /dev/null +++ b/images/play_icon.svg @@ -0,0 +1,120 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/record.svg b/images/record.svg new file mode 100644 index 0000000..89d4dde --- /dev/null +++ b/images/record.svg @@ -0,0 +1,122 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/record_active.svg b/images/record_active.svg new file mode 100644 index 0000000..8d8788d --- /dev/null +++ b/images/record_active.svg @@ -0,0 +1,122 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/skipback_icon.svg b/images/skipback_icon.svg new file mode 100644 index 0000000..6050c6b --- /dev/null +++ b/images/skipback_icon.svg @@ -0,0 +1,71 @@ + + + + + + image/svg+xml + + ionicons-v5-c + + + + + + ionicons-v5-c + + + + diff --git a/paulstretchplugin.jucer b/paulstretchplugin.jucer index 2aeb2a3..582697f 100644 --- a/paulstretchplugin.jucer +++ b/paulstretchplugin.jucer @@ -2,24 +2,36 @@ + + + + + + + + + @@ -76,7 +88,7 @@ microphonePermissionsText="This application requires audio input to capture live audio for processing" hardenedRuntime="1" hardenedRuntimeOptions="com.apple.security.device.audio-input" xcodeValidArchs="arm64,x86_64" buildNumber="100" applicationCategory="public.app-category.music" - smallIcon="Yny1oQ" bigIcon="hG1CYd"> + smallIcon="Yny1oQ" bigIcon="hG1CYd" iosDevelopmentTeamID="XCS435894D"> + + + + + + + + + @@ -76,7 +88,7 @@