Various items before 1.5.1

- fixed passthrough when capturing
 - added declicking fades when bypassing input passthrough, playback, and recording
 - layout tweaks for extra small windows
 - waveform scrollbar improvements, visible edge drag handles, and allows dragging from anywhere
 - minor visual tweaks
 - license header mods, and LICENSE file consolidation
This commit is contained in:
essej 2022-04-21 23:04:30 -04:00
parent 26bd7513b7
commit c89c1558e3
22 changed files with 402 additions and 371 deletions

View File

@ -36,9 +36,9 @@ endif()
# `project()` command. `project()` sets up some helpful variables that describe source/binary # `project()` command. `project()` sets up some helpful variables that describe source/binary
# directories, and the current project version. This is a standard CMake command. # directories, and the current project version. This is a standard CMake command.
project(PaulXStretch VERSION 1.5.0) project(PaulXStretch VERSION 1.5.1)
set(BUILDVERSION 107) set(BUILDVERSION 108)
# If you've installed JUCE somehow (via a package manager, or directly using the CMake install # If you've installed JUCE somehow (via a package manager, or directly using the CMake install

15
LICENSE
View File

@ -1,3 +1,18 @@
GPL Section 7 Exception
As a special exception to the terms and conditions of the
GNU General Public License Version 3 (the "GPL") shown below:
As additional permission under section 7, you are allowed to distribute
the software through an app store, even if that store has restrictive
terms and conditions that are incompatible with the GPL, provided that
the source is also available under the GPL with or without this permission
through a channel without those restrictive terms and conditions.
Paul Nasca, Xenakios and Jesse Chappell all explicitly permitted this
license exception clause.
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007 Version 3, 29 June 2007

View File

@ -1,11 +0,0 @@
GPL Section 7 Exception
As a special exception to the terms and conditions of the
GNU General Public License Version 3 (the "GPL"):
As additional permission under section 7, you are allowed to distribute
the software through an app store, even if that store has restrictive
terms and conditions that are incompatible with the GPL, provided that
the source is also available under the GPL with or without this permission
through a channel without those restrictive terms and conditions.

View File

@ -80,7 +80,8 @@ Copyright (C) 2006-2011 Nasca Octavian Paul, Tg. Mures, Romania
# License and 3rd Party Software # License and 3rd Party Software
Released under GNU General Public License v.3 license with App Store license Released under GNU General Public License v.3 license with App Store license
exception. The full license text is in the LICENSE and LICENSE_EXCEPTION files. exception. The full license text is in the LICENSE and LICENSE_EXCEPTION files. Paul Nasca, Xenakios and Jesse Chappell all explicitly permitted the license exception clause.
It is built using JUCE 6 (slightly modified on a public fork), I'm using the very handy tool `git-subrepo` to include the source code for my forks of those software libraries in this repository. It is built using JUCE 6 (slightly modified on a public fork), I'm using the very handy tool `git-subrepo` to include the source code for my forks of those software libraries in this repository.
FFTW is required, but statically built libraries are included in `deps` for easier building on Mac and Windows. FFTW is required, but statically built libraries are included in `deps` for easier building on Mac and Windows.
@ -89,6 +90,7 @@ My github forks of these that are referenced via `git-subrepo` in this repositor
> https://github.com/essej/JUCE in the sono6good branch. > https://github.com/essej/JUCE in the sono6good branch.
The version distributed on the iOS App Store by Sonosaurus is not built with FFTW, and the JUCE commercial license applies there.

View File

@ -63,6 +63,7 @@ CustomLookAndFeel::CustomLookAndFeel()
setColour (Slider::rotarySliderFillColourId, Colour::fromFloatRGBA(0.5, 0.4, 0.6, 0.9)); setColour (Slider::rotarySliderFillColourId, Colour::fromFloatRGBA(0.5, 0.4, 0.6, 0.9));
setColour (TabbedButtonBar::tabOutlineColourId, Colour::fromFloatRGBA(0.3, 0.3, 0.3, 0.6)); setColour (TabbedButtonBar::tabOutlineColourId, Colour::fromFloatRGBA(0.3, 0.3, 0.3, 0.6));
setColour (TabbedComponent::outlineColourId, Colour::fromFloatRGBA(0.2, 0.2, 0.2, 0.5));
@ -662,7 +663,7 @@ void CustomLookAndFeel::drawFileBrowserRow (Graphics& g, int width, int height,
g.setColour (fileListComp != nullptr ? fileListComp->findColour (DirectoryContentsDisplayComponent::textColourId) g.setColour (fileListComp != nullptr ? fileListComp->findColour (DirectoryContentsDisplayComponent::textColourId)
: findColour (DirectoryContentsDisplayComponent::textColourId)); : findColour (DirectoryContentsDisplayComponent::textColourId));
g.setFont (myFont.withHeight(height * 0.5f)); g.setFont (myFont.withHeight(height * 0.6f));
if (width > 450 && ! isDirectory) if (width > 450 && ! isDirectory)
{ {
@ -673,7 +674,7 @@ void CustomLookAndFeel::drawFileBrowserRow (Graphics& g, int width, int height,
x, 0, sizeX - x, height, x, 0, sizeX - x, height,
Justification::centredLeft, 1); Justification::centredLeft, 1);
g.setFont (myFont.withHeight(height * 0.5f)); g.setFont (myFont.withHeight(height * 0.6f));
g.setColour (Colours::darkgrey); g.setColour (Colours::darkgrey);
if (! isDirectory) if (! isDirectory)

View File

@ -1,28 +1,4 @@
/* // SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#include "../JuceLibraryCode/JuceHeader.h" #include "../JuceLibraryCode/JuceHeader.h"

View File

@ -1,28 +1,4 @@
/* // SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
//#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client //#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client
//extern juce::AudioProcessor* JUCE_API JUCE_CALLTYPE createPluginFilterOfType (juce::AudioProcessor::WrapperType type); //extern juce::AudioProcessor* JUCE_API JUCE_CALLTYPE createPluginFilterOfType (juce::AudioProcessor::WrapperType type);
@ -271,11 +247,19 @@ public:
updateMinAndMax ((int) defaultConfig.numOuts, minNumOutputs, maxNumOutputs); updateMinAndMax ((int) defaultConfig.numOuts, minNumOutputs, maxNumOutputs);
} }
if (auto* bus = processor->getBus (true, 0)) if (auto* bus = processor->getBus (true, 0)) {
updateMinAndMax (bus->getDefaultLayout().size(), minNumInputs, maxNumInputs); updateMinAndMax (bus->getDefaultLayout().size(), minNumInputs, maxNumInputs);
if (bus->isNumberOfChannelsSupported(1)) {
updateMinAndMax (1, minNumInputs, maxNumInputs);
}
}
if (auto* bus = processor->getBus (false, 0)) if (auto* bus = processor->getBus (false, 0)) {
updateMinAndMax (bus->getDefaultLayout().size(), minNumOutputs, maxNumOutputs); updateMinAndMax (bus->getDefaultLayout().size(), minNumOutputs, maxNumOutputs);
if (bus->isNumberOfChannelsSupported(1)) {
updateMinAndMax (1, minNumOutputs, maxNumOutputs);
}
}
minNumInputs = jmin (minNumInputs, maxNumInputs); minNumInputs = jmin (minNumInputs, maxNumInputs);
minNumOutputs = jmin (minNumOutputs, maxNumOutputs); minNumOutputs = jmin (minNumOutputs, maxNumOutputs);
@ -465,9 +449,9 @@ private:
deviceSelector (deviceManagerToUse, deviceSelector (deviceManagerToUse,
minAudioInputChannels, maxAudioInputChannels, minAudioInputChannels, maxAudioInputChannels,
minAudioOutputChannels, maxAudioOutputChannels, minAudioOutputChannels, maxAudioOutputChannels,
true, true, // show midi
(pluginHolder.processor.get() != nullptr && pluginHolder.processor->producesMidi()), (pluginHolder.processor.get() != nullptr && pluginHolder.processor->producesMidi()),
true, false), false, false),
shouldMuteLabel ("Feedback Loop:", "Feedback Loop:"), shouldMuteLabel ("Feedback Loop:", "Feedback Loop:"),
shouldMuteButton ("Mute audio input") shouldMuteButton ("Mute audio input")
{ {

View File

@ -1,20 +1,6 @@
/* // SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
Copyright (C) 2006-2011 Nasca Octavian Paul // Copyright (C) 2006-2011 Nasca Octavian Paul
Author: Nasca Octavian Paul // Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#pragma once #pragma once

View File

@ -1,20 +1,7 @@
/* // SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
Copyright (C) 2006-2011 Nasca Octavian Paul // Copyright (C) 2006-2011 Nasca Octavian Paul
Author: Nasca Octavian Paul // Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#pragma once #pragma once

View File

@ -1,19 +1,6 @@
/* // SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
Copyright (C) 2017 Xenakios // Copyright (C) 2022 Jesse Chappell
This program is free software; you can redistribute it and/or modify
it under the terms of version 3 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 3) for more details.
www.gnu.org/licenses
*/
#include "StretchSource.h" #include "StretchSource.h"

View File

@ -1,20 +1,6 @@
/* // SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
Copyright (C) 2017 Xenakios // Copyright (C) 2022 Jesse Chappell
This program is free software; you can redistribute it and/or modify
it under the terms of version 3 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 3) for more details.
www.gnu.org/licenses
*/
#pragma once #pragma once

View File

@ -1,20 +1,6 @@
/* // SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
Copyright (C) 2017 Xenakios // Copyright (C) 2020 Jesse Chappell
This program is free software; you can redistribute it and/or modify
it under the terms of version 3 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 3) for more details.
www.gnu.org/licenses
*/
#include "PluginProcessor.h" #include "PluginProcessor.h"
#include "PluginEditor.h" #include "PluginEditor.h"
@ -84,7 +70,7 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau
{ {
return jmap<double>(x, 0.0, 1.0, -48.0, 12.0); return jmap<double>(x, 0.0, 1.0, -48.0, 12.0);
}; };
int tabdepth = 24; int tabdepth = 26;
#if JUCE_IOS #if JUCE_IOS
tabdepth = 36; tabdepth = 36;
@ -209,6 +195,7 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau
std::unique_ptr<Drawable> pauseimg(Drawable::createFromImageData(BinaryData::pause_icon_svg, BinaryData::pause_icon_svgSize)); std::unique_ptr<Drawable> pauseimg(Drawable::createFromImageData(BinaryData::pause_icon_svg, BinaryData::pause_icon_svgSize));
pausebut->setImages(pauseimg.get(), nullptr, nullptr, nullptr, playimg.get()); pausebut->setImages(pauseimg.get(), nullptr, nullptr, nullptr, playimg.get());
pausebut->setColour(DrawableButton::backgroundColourId, Colour::fromFloatRGBA(0.1f, 0.5f, 0.1f, 0.55f)); pausebut->setColour(DrawableButton::backgroundColourId, Colour::fromFloatRGBA(0.1f, 0.5f, 0.1f, 0.55f));
pausebut->setTooltip("Play / Pause");
} }
if (auto * loopbut = m_parcomps[cpi_looping_enabled]->getDrawableButton()) { if (auto * loopbut = m_parcomps[cpi_looping_enabled]->getDrawableButton()) {
@ -469,7 +456,7 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau
}; };
m_wave_container->addAndMakeVisible(&m_wavecomponent); m_wave_container->addAndMakeVisible(&m_wavecomponent);
auto tabbgcol = Colour(0xff444444); auto tabbgcol = Colour(0xff303030);
m_wavefilter_tab.addTab("Waveform", tabbgcol, m_wave_container, true); m_wavefilter_tab.addTab("Waveform", tabbgcol, m_wave_container, true);
m_wavefilter_tab.addTab("Ratio mixer", tabbgcol, &m_ratiomixeditor, false); m_wavefilter_tab.addTab("Ratio mixer", tabbgcol, &m_ratiomixeditor, false);
@ -873,9 +860,6 @@ void PaulstretchpluginAudioProcessorEditor::resized()
mainbox.items.add(FlexItem(6, 2)); mainbox.items.add(FlexItem(6, 2));
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) { auto reparentIfNecessary = [] (Component * comp, Component *newparent) {
@ -899,6 +883,7 @@ void PaulstretchpluginAudioProcessorEditor::resized()
int totminh = vpminh + orderminh + tabminh + topboxh + toggleh + volh + stretchH + 18; int totminh = vpminh + orderminh + tabminh + topboxh + toggleh + volh + stretchH + 18;
int shortthresh = vpminh + orderminh + tabminh + topboxh + toggleh; int shortthresh = vpminh + orderminh + tabminh + topboxh + toggleh;
int veryshortthresh = tabminh + topboxh + toggleh;
if (getHeight() < totminh) { if (getHeight() < totminh) {
// not enough vertical space, put the top items in the scrollable viewport // not enough vertical space, put the top items in the scrollable viewport
@ -916,19 +901,41 @@ void PaulstretchpluginAudioProcessorEditor::resized()
if (getHeight() < shortthresh) { if (getHeight() < shortthresh) {
// really not much space, put group scroll in a new tab // really not much space, put group scroll in a new tab
if (m_wavefilter_tab.getNumTabs() <= 3) { if (m_wavefilter_tab.getNumTabs() <= 3) {
m_wavefilter_tab.addTab("Controls", Colour(0xff555555), m_groupviewport.get(), false); m_wavefilter_tab.addTab("Controls", Colour(0xff333333), m_groupviewport.get(), false);
m_wavefilter_tab.setCurrentTabIndex(3); m_wavefilter_tab.setCurrentTabIndex(3);
} }
if (getHeight() < veryshortthresh) {
reparentItemsIfNecessary(topbox, m_groupcontainer.get());
reparentItemsIfNecessary(togglesbox, m_groupcontainer.get());
groupsbox.items.insert(0, FlexItem(minw, toggleh, togglesbox).withMargin(groupmargin).withFlex(0));
groupsbox.items.insert(0, FlexItem(minw, topboxh, topbox).withMargin(groupmargin).withFlex(0));
useh += toggleh + topboxh + groupmargin*4;
}
else {
reparentItemsIfNecessary(topbox, this);
reparentItemsIfNecessary(togglesbox, this);
mainbox.items.add(FlexItem(minw, topboxh, topbox).withMargin(margin).withFlex(0));
mainbox.items.add(FlexItem(minw, toggleh, togglesbox).withMargin(margin).withFlex(0));
}
reparentIfNecessary(&m_spec_order_ed, m_groupcontainer.get()); reparentIfNecessary(&m_spec_order_ed, m_groupcontainer.get());
groupsbox.items.add(FlexItem(minw, orderminh, m_spec_order_ed).withMargin(2)); groupsbox.items.add(FlexItem(minw, orderminh, m_spec_order_ed).withMargin(2));
useh += orderminh + 4; useh += orderminh + 4;
m_shortMode = true; m_shortMode = true;
} else { } else {
reparentIfNecessary(&m_spec_order_ed, this); reparentIfNecessary(&m_spec_order_ed, this);
reparentItemsIfNecessary(topbox, this);
reparentItemsIfNecessary(togglesbox, this);
if (m_wavefilter_tab.getNumTabs() > 3) { if (m_wavefilter_tab.getNumTabs() > 3) {
// bring it back // bring it back
@ -940,6 +947,10 @@ void PaulstretchpluginAudioProcessorEditor::resized()
addAndMakeVisible(m_groupviewport.get()); addAndMakeVisible(m_groupviewport.get());
} }
m_shortMode = false; m_shortMode = false;
mainbox.items.add(FlexItem(minw, topboxh, topbox).withMargin(margin).withFlex(0));
mainbox.items.add(FlexItem(minw, toggleh, togglesbox).withMargin(margin).withFlex(0));
} }
@ -960,11 +971,13 @@ void PaulstretchpluginAudioProcessorEditor::resized()
reparentIfNecessary(m_groupviewport.get(), this); reparentIfNecessary(m_groupviewport.get(), this);
reparentIfNecessary(&m_spec_order_ed, this); reparentIfNecessary(&m_spec_order_ed, this);
reparentIfNecessary(m_stretchgroup.get(), this); reparentIfNecessary(m_stretchgroup.get(), this);
//reparentItemsIfNecessary(togglesbox, this);
reparentItemsIfNecessary(volbox, this); reparentItemsIfNecessary(volbox, this);
reparentItemsIfNecessary(topbox, this);
reparentItemsIfNecessary(togglesbox, this);
mainbox.items.add(FlexItem(minw, topboxh, topbox).withMargin(margin).withFlex(0));
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, volh, volbox).withMargin(margin).withFlex(0));
mainbox.items.add(FlexItem(6, 3)); mainbox.items.add(FlexItem(6, 3));
mainbox.items.add(FlexItem(minw, stretchH, *m_stretchgroup).withMargin(margin).withFlex(0)); mainbox.items.add(FlexItem(minw, stretchH, *m_stretchgroup).withMargin(margin).withFlex(0));
@ -1016,6 +1029,12 @@ void PaulstretchpluginAudioProcessorEditor::resized()
m_zs.setBounds(m_wave_container->getX(), m_wavecomponent.getBottom(), m_wave_container->getWidth(), zscrollh); m_zs.setBounds(m_wave_container->getX(), m_wavecomponent.getBottom(), m_wave_container->getWidth(), zscrollh);
//m_wavecomponent.setBounds(1, m_spec_order_ed.getBottom()+1, getWidth()-2, remain_h/5*4); //m_wavecomponent.setBounds(1, m_spec_order_ed.getBottom()+1, getWidth()-2, remain_h/5*4);
if (m_filechooser && m_filechooser->isVisible()) {
auto importbounds = getLocalArea(nullptr, m_import_button.getScreenBounds());
m_filechooser->setBounds(0, importbounds.getBottom(), getWidth()/2, getHeight() - 75);
m_filechooser->toFront(false);
}
if (m_shortMode) { if (m_shortMode) {
m_groupcontainer->repaint(); m_groupcontainer->repaint();
} }
@ -1317,7 +1336,8 @@ void PaulstretchpluginAudioProcessorEditor::toggleFileBrowser()
m_filechooser = std::make_unique<MyFileBrowserComponent>(processor); m_filechooser = std::make_unique<MyFileBrowserComponent>(processor);
addChildComponent(m_filechooser.get()); addChildComponent(m_filechooser.get());
} }
m_filechooser->setBounds(0, m_import_button.getBottom(), getWidth()/2, getHeight() - 75); auto bounds = getLocalArea(nullptr, m_import_button.getScreenBounds());
m_filechooser->setBounds(0, bounds.getBottom(), getWidth()/2, getHeight() - 75);
m_filechooser->setVisible(!m_filechooser->isVisible()); m_filechooser->setVisible(!m_filechooser->isVisible());
if (m_filechooser->isVisible()) if (m_filechooser->isVisible())
m_import_button.setButtonText("Hide browser"); m_import_button.setButtonText("Hide browser");
@ -1667,6 +1687,14 @@ void WaveformComponent::mouseWheelMove(const MouseEvent & e, const MouseWheelDet
double t0 = normt - newScale * xratio; double t0 = normt - newScale * xratio;
double t1 = normt + newScale * (1.0 - xratio); double t1 = normt + newScale * (1.0 - xratio);
if (abs(wd.deltaX) > 0.0) {
auto deltax = 0.15f * wd.deltaX;
double old_len = t1 - t0;
t0 = (jlimit(0.0, 1.0 - old_len, t0 + deltax));
t1 = (jlimit(old_len, t0 + old_len, t1 + deltax));
}
t0 = jlimit(0.0,1.0, t0); t0 = jlimit(0.0,1.0, t0);
t1 = jlimit(0.0,1.0, t1); t1 = jlimit(0.0,1.0, t1);
@ -2310,7 +2338,17 @@ void PerfMeterComponent::timerCallback()
void zoom_scrollbar::mouseDown(const MouseEvent &e) void zoom_scrollbar::mouseDown(const MouseEvent &e)
{ {
auto ha = get_hot_area(e.x, e.y);
m_drag_start_x = e.x; m_drag_start_x = e.x;
m_handle_off_x = 0;
if (ha == ha_left_edge) {
m_handle_off_x = e.x - m_therange.getStart() * getWidth();
}
else if (ha == ha_right_edge) {
m_handle_off_x = e.x - m_therange.getEnd() * getWidth();
}
} }
void zoom_scrollbar::mouseDoubleClick (const MouseEvent&) void zoom_scrollbar::mouseDoubleClick (const MouseEvent&)
@ -2341,21 +2379,19 @@ void zoom_scrollbar::mouseMove(const MouseEvent &e)
void zoom_scrollbar::mouseDrag(const MouseEvent &e) void zoom_scrollbar::mouseDrag(const MouseEvent &e)
{ {
if (m_hot_area == ha_none)
return;
if (m_hot_area == ha_left_edge) if (m_hot_area == ha_left_edge)
{ {
double new_left_edge = 1.0 / getWidth()*e.x; double new_left_edge = 1.0 / getWidth()*(e.x - m_handle_off_x);
m_therange.setStart(jlimit(0.0, m_therange.getEnd() - 0.01, new_left_edge)); m_therange.setStart(jlimit(0.0, m_therange.getEnd() - 0.01, new_left_edge));
repaint(); repaint();
} }
if (m_hot_area == ha_right_edge) else if (m_hot_area == ha_right_edge)
{ {
double new_right_edge = 1.0 / getWidth()*e.x; double new_right_edge = 1.0 / getWidth()*(e.x - m_handle_off_x);
m_therange.setEnd(jlimit(m_therange.getStart() + 0.01, 1.0, new_right_edge)); m_therange.setEnd(jlimit(m_therange.getStart() + 0.01, 1.0, new_right_edge));
repaint(); repaint();
} }
if (m_hot_area == ha_handle) else if (m_hot_area == ha_handle || m_hot_area == ha_none)
{ {
double delta = 1.0 / getWidth()*(e.x - m_drag_start_x); double delta = 1.0 / getWidth()*(e.x - m_drag_start_x);
//double old_start = m_start; //double old_start = m_start;
@ -2370,6 +2406,21 @@ void zoom_scrollbar::mouseDrag(const MouseEvent &e)
RangeChanged(m_therange); RangeChanged(m_therange);
} }
void zoom_scrollbar::mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& wd)
{
float delta = -0.1f * wd.deltaY;
double old_len = m_therange.getLength();
m_therange.setStart(jlimit(0.0, 1.0 - old_len, m_therange.getStart() + delta));
m_therange.setEnd(jlimit(old_len, m_therange.getStart() + old_len, m_therange.getEnd() + delta));
repaint();
if (RangeChanged)
RangeChanged(m_therange);
}
void zoom_scrollbar::mouseEnter(const MouseEvent & event) void zoom_scrollbar::mouseEnter(const MouseEvent & event)
{ {
m_hot_area = get_hot_area(event.x, event.y); m_hot_area = get_hot_area(event.x, event.y);
@ -2384,16 +2435,42 @@ void zoom_scrollbar::mouseExit(const MouseEvent &)
void zoom_scrollbar::paint(Graphics &g) void zoom_scrollbar::paint(Graphics &g)
{ {
g.setColour(Colours::darkgrey); int radius = 16;
#if JUCE_IOS
radius *= 2;
#endif
Colour basecolor = Colours::darkgrey;
g.setColour(basecolor);
Colour barcolor = Colours::grey;
g.fillRect(0, 0, getWidth(), getHeight()); g.fillRect(0, 0, getWidth(), getHeight());
int x0 = (int)(getWidth()*m_therange.getStart()); int x0 = (int)(getWidth()*m_therange.getStart());
int x1 = (int)(getWidth()*m_therange.getEnd()); int x1 = (int)(getWidth()*m_therange.getEnd());
if (m_hot_area != ha_none) if (m_hot_area == ha_handle)
g.setColour(Colours::white.withAlpha(0.8f)); barcolor = barcolor.brighter(0.5f); //Colours::white.withAlpha(0.8f);
else g.setColour(Colours::grey);
//g.fillRect(x0, 0, x1 - x0, getHeight()); g.setColour(barcolor);
//g.fillRect(x0, 0, x1 - x0, getHeight());
g.fillRoundedRectangle(x0, 0, x1 - x0, getHeight(), 8.0f); g.fillRoundedRectangle(x0, 0, x1 - x0, getHeight(), 8.0f);
// edge handles
Colour handlecol = barcolor.brighter();
if (m_hot_area == ha_left_edge)
g.setColour(handlecol.brighter());
else g.setColour(handlecol);
g.fillRoundedRectangle(x0, 0, radius, getHeight(), 8.0f);
if (m_hot_area == ha_right_edge)
g.setColour(handlecol.brighter());
else g.setColour(handlecol);
g.fillRoundedRectangle(x1 - radius, 0, radius, getHeight(), 8.0f);
} }
void zoom_scrollbar::setRange(Range<double> rng, bool docallback) void zoom_scrollbar::setRange(Range<double> rng, bool docallback)
@ -2408,7 +2485,7 @@ void zoom_scrollbar::setRange(Range<double> rng, bool docallback)
zoom_scrollbar::hot_area zoom_scrollbar::get_hot_area(int x, int) zoom_scrollbar::hot_area zoom_scrollbar::get_hot_area(int x, int)
{ {
int radius = 10; int radius = 16;
#if JUCE_IOS #if JUCE_IOS
radius *= 2; radius *= 2;
#endif #endif

View File

@ -1,19 +1,6 @@
/* // SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
Copyright (C) 2017 Xenakios // Copyright (C) 2020 Jesse Chappell
This program is free software; you can redistribute it and/or modify
it under the terms of version 3 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 3) for more details.
www.gnu.org/licenses
*/
#pragma once #pragma once
@ -41,6 +28,7 @@ public:
void mouseEnter(const MouseEvent &event) override; void mouseEnter(const MouseEvent &event) override;
void mouseExit(const MouseEvent &event) override; void mouseExit(const MouseEvent &event) override;
void mouseDoubleClick (const MouseEvent&) override; void mouseDoubleClick (const MouseEvent&) override;
void mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& wd) override;
void paint(Graphics &g) override; void paint(Graphics &g) override;
std::function<void(Range<double>)> RangeChanged; std::function<void(Range<double>)> RangeChanged;
@ -52,6 +40,7 @@ private:
hot_area m_hot_area = ha_none; hot_area m_hot_area = ha_none;
hot_area get_hot_area(int x, int y); hot_area get_hot_area(int x, int y);
int m_drag_start_x = 0; int m_drag_start_x = 0;
int m_handle_off_x = 0;
}; };

View File

@ -1,19 +1,7 @@
/* // SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
// Copyright (C) 2020 Jesse Chappell
Copyright (C) 2017 Xenakios
This program is free software; you can redistribute it and/or modify
it under the terms of version 3 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 3) for more details.
www.gnu.org/licenses
*/
#include "PluginProcessor.h" #include "PluginProcessor.h"
#include "PluginEditor.h" #include "PluginEditor.h"
@ -61,11 +49,19 @@ inline AudioParameterFloat* make_floatpar(String id, String name, float minv, fl
return new AudioParameterFloat(id, name, NormalisableRange<float>(minv, maxv, step, skew), defv); return new AudioParameterFloat(id, name, NormalisableRange<float>(minv, maxv, step, skew), defv);
} }
#if JUCE_IOS
#define ALTBUS_ACTIVE true
#else
#define ALTBUS_ACTIVE false
#endif
//============================================================================== //==============================================================================
PaulstretchpluginAudioProcessor::PaulstretchpluginAudioProcessor(bool is_stand_alone_offline) PaulstretchpluginAudioProcessor::PaulstretchpluginAudioProcessor(bool is_stand_alone_offline)
: AudioProcessor(PaulstretchpluginAudioProcessor::BusesProperties().withInput("Main In", AudioChannelSet::stereo(), true).withOutput ("Main Out", AudioChannelSet::stereo(), true)), : AudioProcessor(PaulstretchpluginAudioProcessor::BusesProperties().withInput("Main In", AudioChannelSet::stereo(), true).withOutput ("Main Out", AudioChannelSet::stereo(), true).withInput ("Aux 1 In", AudioChannelSet::stereo(), ALTBUS_ACTIVE).withInput ("Aux 2 In", AudioChannelSet::stereo(), ALTBUS_ACTIVE).withInput ("Aux 3 In", AudioChannelSet::stereo(), ALTBUS_ACTIVE).withOutput ("Aux 1 Out", AudioChannelSet::stereo(), ALTBUS_ACTIVE).withOutput ("Aux 2 Out", AudioChannelSet::stereo(), ALTBUS_ACTIVE).withOutput ("Aux 3 Out", AudioChannelSet::stereo(), ALTBUS_ACTIVE)),
m_bufferingthread("pspluginprebufferthread"), m_is_stand_alone_offline(is_stand_alone_offline) m_bufferingthread("pspluginprebufferthread"), m_is_stand_alone_offline(is_stand_alone_offline)
{ {
DBG("Attempt proc const");
m_filechoose_callback = [this](const FileChooser& chooser) m_filechoose_callback = [this](const FileChooser& chooser)
{ {
URL resu = chooser.getURLResult(); URL resu = chooser.getURLResult();
@ -91,6 +87,9 @@ m_bufferingthread("pspluginprebufferthread"), m_is_stand_alone_offline(is_stand_
m_free_filter_envelope->AddNode({ 0.0,0.75 }); m_free_filter_envelope->AddNode({ 0.0,0.75 });
m_free_filter_envelope->AddNode({ 1.0,0.75 }); m_free_filter_envelope->AddNode({ 1.0,0.75 });
m_free_filter_envelope->set_reset_nodes(m_free_filter_envelope->get_all_nodes()); m_free_filter_envelope->set_reset_nodes(m_free_filter_envelope->get_all_nodes());
DBG("recbuffer");
m_recbuffer.setSize(2, 48000); m_recbuffer.setSize(2, 48000);
m_recbuffer.clear(); m_recbuffer.clear();
if (m_afm->getNumKnownFormats()==0) if (m_afm->getNumKnownFormats()==0)
@ -98,6 +97,8 @@ m_bufferingthread("pspluginprebufferthread"), m_is_stand_alone_offline(is_stand_
if (m_is_stand_alone_offline == false) if (m_is_stand_alone_offline == false)
m_thumb = std::make_unique<AudioThumbnail>(512, *m_afm, *m_thumbcache); m_thumb = std::make_unique<AudioThumbnail>(512, *m_afm, *m_thumbcache);
DBG("making bool pars");
m_sm_enab_pars[0] = new AudioParameterBool("enab_specmodule0", "Enable harmonics", false); m_sm_enab_pars[0] = new AudioParameterBool("enab_specmodule0", "Enable harmonics", false);
m_sm_enab_pars[1] = new AudioParameterBool("enab_specmodule1", "Enable tonal vs noise", false); m_sm_enab_pars[1] = new AudioParameterBool("enab_specmodule1", "Enable tonal vs noise", false);
m_sm_enab_pars[2] = new AudioParameterBool("enab_specmodule2", "Enable frequency shift", true); m_sm_enab_pars[2] = new AudioParameterBool("enab_specmodule2", "Enable frequency shift", true);
@ -108,12 +109,17 @@ m_bufferingthread("pspluginprebufferthread"), m_is_stand_alone_offline(is_stand_
m_sm_enab_pars[7] = new AudioParameterBool("enab_specmodule7", "Enable free filter", true); m_sm_enab_pars[7] = new AudioParameterBool("enab_specmodule7", "Enable free filter", true);
m_sm_enab_pars[8] = new AudioParameterBool("enab_specmodule8", "Enable compressor", false); m_sm_enab_pars[8] = new AudioParameterBool("enab_specmodule8", "Enable compressor", false);
DBG("making stretch source");
m_stretch_source = std::make_unique<StretchAudioSource>(2, m_afm,m_sm_enab_pars); m_stretch_source = std::make_unique<StretchAudioSource>(2, m_afm,m_sm_enab_pars);
m_stretch_source->setOnsetDetection(0.0); m_stretch_source->setOnsetDetection(0.0);
m_stretch_source->setLoopingEnabled(true); m_stretch_source->setLoopingEnabled(true);
m_stretch_source->setFFTWindowingType(1); m_stretch_source->setFFTWindowingType(1);
DBG("About to add parameters");
addParameter(make_floatpar("mainvolume0", "Main volume", -24.0, 12.0, -3.0, 0.1, 1.0)); addParameter(make_floatpar("mainvolume0", "Main volume", -24.0, 12.0, -3.0, 0.1, 1.0));
addParameter(make_floatpar("stretchamount0", "Stretch amount", 0.1, 1024.0, 2.0, 0.1, 0.25)); addParameter(make_floatpar("stretchamount0", "Stretch amount", 0.1, 1024.0, 2.0, 0.1, 0.25));
addParameter(make_floatpar("fftsize0", "FFT size", 0.0, 1.0, 0.7, 0.01, 1.0)); addParameter(make_floatpar("fftsize0", "FFT size", 0.0, 1.0, 0.7, 0.01, 1.0));
@ -216,11 +222,12 @@ m_bufferingthread("pspluginprebufferthread"), m_is_stand_alone_offline(is_stand_
if (!m_is_stand_alone_offline) { if (!m_is_stand_alone_offline) {
setPreBufferAmount(2); setPreBufferAmount(2);
startTimer(1, 50); startTimer(1, 40);
} }
m_show_technical_info = m_propsfile->m_props_file->getBoolValue("showtechnicalinfo", false); m_show_technical_info = m_propsfile->m_props_file->getBoolValue("showtechnicalinfo", false);
DBG("Constructed PS plugin");
} }
PaulstretchpluginAudioProcessor::~PaulstretchpluginAudioProcessor() PaulstretchpluginAudioProcessor::~PaulstretchpluginAudioProcessor()
@ -764,7 +771,7 @@ void PaulstretchpluginAudioProcessor::prepareToPlay(double sampleRate, int sampl
m_adsr.setSampleRate(sampleRate); m_adsr.setSampleRate(sampleRate);
m_cur_sr = sampleRate; m_cur_sr = sampleRate;
m_curmaxblocksize = samplesPerBlock; m_curmaxblocksize = samplesPerBlock;
m_input_buffer.setSize(getMainBusNumInputChannels(), samplesPerBlock); m_input_buffer.setSize(getTotalNumInputChannels(), samplesPerBlock);
*getBoolParameter(cpi_rewind) = false; *getBoolParameter(cpi_rewind) = false;
m_lastrewind = false; m_lastrewind = false;
int numoutchans = *m_outchansparam; int numoutchans = *m_outchansparam;
@ -794,6 +801,8 @@ void PaulstretchpluginAudioProcessor::prepareToPlay(double sampleRate, int sampl
{ {
m_buffering_source->prepareToPlay(samplesPerBlock, getSampleRateChecked()); m_buffering_source->prepareToPlay(samplesPerBlock, getSampleRateChecked());
} }
m_standalone = juce::PluginHostType::getPluginLoadedAs() == AudioProcessor::wrapperType_Standalone;
} }
void PaulstretchpluginAudioProcessor::releaseResources() void PaulstretchpluginAudioProcessor::releaseResources()
@ -808,10 +817,14 @@ bool PaulstretchpluginAudioProcessor::isBusesLayoutSupported (const BusesLayout&
ignoreUnused (layouts); ignoreUnused (layouts);
return true; return true;
#else #else
// support anything
return true;
// This is the place where you check if the layout is supported. // This is the place where you check if the layout is supported.
// In this template code we only support mono or stereo. // In this template code we only support mono or stereo.
if (layouts.getMainOutputChannelSet() != AudioChannelSet::mono() if ( /* layouts.getMainOutputChannelSet() != AudioChannelSet::mono() && */
&& layouts.getMainOutputChannelSet() != AudioChannelSet::stereo()) layouts.getMainOutputChannelSet() != AudioChannelSet::stereo())
return false; return false;
// This checks if the input layout matches the output layout // This checks if the input layout matches the output layout
@ -825,21 +838,42 @@ bool PaulstretchpluginAudioProcessor::isBusesLayoutSupported (const BusesLayout&
} }
#endif #endif
void copyAudioBufferWrappingPosition(const AudioBuffer<float>& src, AudioBuffer<float>& dest, int destbufpos, int maxdestpos) static void copyAudioBufferWrappingPosition(const AudioBuffer<float>& src, int numSamples, AudioBuffer<float>& dest, int destbufpos, int maxdestpos, float fademode)
{ {
int useNumSamples = jmin(numSamples, src.getNumSamples());
for (int i = 0; i < dest.getNumChannels(); ++i) for (int i = 0; i < dest.getNumChannels(); ++i)
{ {
int channel_to_copy = i % src.getNumChannels(); int channel_to_copy = i % src.getNumChannels();
if (destbufpos + src.getNumSamples() > maxdestpos) if (destbufpos + useNumSamples > maxdestpos)
{ {
int wrappos = (destbufpos + src.getNumSamples()) % maxdestpos; int wrappos = (destbufpos + useNumSamples) % maxdestpos;
int partial_len = src.getNumSamples() - wrappos; int partial_len = useNumSamples - wrappos;
dest.copyFrom(channel_to_copy, destbufpos, src, channel_to_copy, 0, partial_len);
dest.copyFrom(channel_to_copy, partial_len, src, channel_to_copy, 0, wrappos); if (fademode == 0.0f) {
dest.copyFrom(i, destbufpos, src, channel_to_copy, 0, partial_len);
dest.copyFrom(i, partial_len, src, channel_to_copy, 0, wrappos);
} else {
//DBG("recfade wrap: " << fademode);
if (fademode > 0.0f) {
// fade in
dest.copyFromWithRamp(i, destbufpos, src.getReadPointer(channel_to_copy), partial_len, fademode > 0.0f ? 0.0f : 1.0f, fademode > 0.0f ? 1.0f : 0.0f);
dest.copyFrom(i, partial_len, src, channel_to_copy, 0, wrappos);
} else {
// fade out
dest.copyFrom(i, destbufpos, src, channel_to_copy, 0, partial_len);
dest.copyFromWithRamp(i, partial_len, src.getReadPointer(channel_to_copy), wrappos, fademode > 0.0f ? 0.0f : 1.0f, fademode > 0.0f ? 1.0f : 0.0f);
}
}
} }
else else
{ {
dest.copyFrom(channel_to_copy, destbufpos, src, channel_to_copy, 0, src.getNumSamples()); if (fademode == 0.0f) {
dest.copyFrom(i, destbufpos, src, channel_to_copy, 0, useNumSamples);
} else {
//DBG("recfade: " << fademode);
dest.copyFromWithRamp(i, destbufpos, src.getReadPointer(channel_to_copy), useNumSamples, fademode > 0.0f ? 0.0f : 1.0f, fademode > 0.0f ? 1.0f : 0.0f);
}
} }
} }
} }
@ -856,13 +890,22 @@ void PaulstretchpluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, M
ScopedLock locker(m_cs); ScopedLock locker(m_cs);
const int totalNumInputChannels = getTotalNumInputChannels(); const int totalNumInputChannels = getTotalNumInputChannels();
const int totalNumOutputChannels = getTotalNumOutputChannels(); const int totalNumOutputChannels = getTotalNumOutputChannels();
AudioPlayHead* phead = getPlayHead(); bool passthruEnabled = getParameter(cpi_passthrough) > 0.5f;
AudioPlayHead* phead = getPlayHead();
bool seektostart = false;
if (phead != nullptr) if (phead != nullptr)
{ {
phead->getCurrentPosition(m_playposinfo); phead->getCurrentPosition(m_playposinfo);
if (m_playposinfo.isPlaying && m_playposinfo.ppqPosition == 0.0 || m_playposinfo.timeInSamples == 0) {
seektostart = true;
}
} }
else else {
m_playposinfo.isPlaying = false; m_playposinfo.isPlaying = false;
}
ScopedNoDenormals noDenormals; ScopedNoDenormals noDenormals;
double srtemp = getSampleRate(); double srtemp = getSampleRate();
if (srtemp != m_cur_sr) if (srtemp != m_cur_sr)
@ -870,30 +913,87 @@ void PaulstretchpluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, M
m_prebufsmoother.setSlope(0.9, srtemp / buffer.getNumSamples()); m_prebufsmoother.setSlope(0.9, srtemp / buffer.getNumSamples());
m_smoothed_prebuffer_ready = m_prebufsmoother.process(m_buffering_source->getPercentReady()); m_smoothed_prebuffer_ready = m_prebufsmoother.process(m_buffering_source->getPercentReady());
if (buffer.getNumSamples() > m_input_buffer.getNumSamples()) {
// just in case
m_input_buffer.setSize(totalNumInputChannels, buffer.getNumSamples(), false, false, true);
}
for (int i = 0; i < totalNumInputChannels; ++i) for (int i = 0; i < totalNumInputChannels; ++i)
m_input_buffer.copyFrom(i, 0, buffer, i, 0, buffer.getNumSamples()); m_input_buffer.copyFrom(i, 0, buffer, i, 0, buffer.getNumSamples());
for (int i = totalNumInputChannels; i < totalNumOutputChannels; ++i) for (int i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
buffer.clear (i, 0, buffer.getNumSamples()); buffer.clear (i, 0, buffer.getNumSamples());
float fadepassthru = 0.0f;
if (!passthruEnabled) {
if (m_lastpassthru != passthruEnabled) {
// ramp it down
fadepassthru = -1.0f;
for (int i = 0; i < totalNumInputChannels; ++i)
buffer.applyGainRamp(i, 0, buffer.getNumSamples(), 1.0f, 0.0f);
}
else {
for (int i = 0; i < totalNumInputChannels; ++i)
buffer.clear (i, 0, buffer.getNumSamples());
}
}
else if (passthruEnabled != m_lastpassthru) {
// ramp it up
fadepassthru = 1.0f;
for (int i = 0; i < totalNumInputChannels; ++i)
buffer.applyGainRamp(i, 0, buffer.getNumSamples(), 0.0f, 1.0f);
}
m_lastpassthru = passthruEnabled;
float recfade = 0.0f;
if (m_is_recording != m_is_recording_pending) {
recfade = m_is_recording_pending ? 1.0f : -1.0f;
m_is_recording = m_is_recording_pending;
}
if (m_previewcomponent != nullptr) if (m_previewcomponent != nullptr)
{ {
m_previewcomponent->processBlock(getSampleRate(), buffer); m_previewcomponent->processBlock(getSampleRate(), buffer);
return; return;
} }
if (m_prebuffering_inited == false)
if (m_prebuffering_inited == false)
return; return;
if (m_is_recording == true)
if (m_is_recording == true || recfade != 0.0f)
{ {
if (m_playposinfo.isPlaying == false && m_capture_when_host_plays == true) if (m_playposinfo.isPlaying == false && m_capture_when_host_plays == true && !m_standalone) {
if (!m_is_recording)
m_is_recording_finished = true;
return; return;
}
int recbuflenframes = m_max_reclen * getSampleRate(); int recbuflenframes = m_max_reclen * getSampleRate();
copyAudioBufferWrappingPosition(buffer, m_recbuffer, m_rec_pos, recbuflenframes); copyAudioBufferWrappingPosition(m_input_buffer, buffer.getNumSamples(), m_recbuffer, m_rec_pos, recbuflenframes, recfade);
m_thumb->addBlock(m_rec_pos, buffer, 0, buffer.getNumSamples()); m_thumb->addBlock(m_rec_pos, m_input_buffer, 0, buffer.getNumSamples());
m_rec_pos = (m_rec_pos + buffer.getNumSamples()) % recbuflenframes; m_rec_pos = (m_rec_pos + buffer.getNumSamples()) % recbuflenframes;
m_rec_count += buffer.getNumSamples(); m_rec_count += buffer.getNumSamples();
if (!m_is_recording) {
// to signal that it may be written, etc
m_is_recording_finished = true;
}
if (m_rec_count<recbuflenframes) if (m_rec_count<recbuflenframes)
m_recorded_range = { 0, m_rec_count }; m_recorded_range = { 0, m_rec_count };
if (m_mute_while_capturing == true) if (m_mute_while_capturing == true && passthruEnabled) {
buffer.clear(); if (recfade < 0.0f) {
buffer.applyGainRamp(0, buffer.getNumSamples(), 1.0f, 0.0f);
}
else if (recfade > 0.0f) {
buffer.applyGainRamp(0, buffer.getNumSamples(), 0.0f, 1.0f);
}
else {
buffer.clear();
}
}
if (m_mute_processed_while_capturing == true) if (m_mute_processed_while_capturing == true)
return; return;
@ -904,17 +1004,30 @@ void PaulstretchpluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, M
double t1 = *getFloatParameter(cpi_soundend); double t1 = *getFloatParameter(cpi_soundend);
sanitizeTimeRange(t0, t1); sanitizeTimeRange(t0, t1);
m_stretch_source->setPlayRange({ t0,t1 }); m_stretch_source->setPlayRange({ t0,t1 });
float fadeproc = 0.0f;
if (m_last_host_playing == false && m_playposinfo.isPlaying) if (m_last_host_playing == false && m_playposinfo.isPlaying)
{ {
m_stretch_source->seekPercent(*getFloatParameter(cpi_soundstart)); if (m_play_when_host_plays) {
// should we even do this ever?
if (seektostart)
m_stretch_source->seekPercent(*getFloatParameter(cpi_soundstart));
fadeproc = 1.0f; // fadein
}
m_last_host_playing = true; m_last_host_playing = true;
} }
else if (m_last_host_playing == true && m_playposinfo.isPlaying == false) else if (m_last_host_playing == true && m_playposinfo.isPlaying == false)
{ {
m_last_host_playing = false; m_last_host_playing = false;
if (m_play_when_host_plays) {
fadeproc = -1.0f; // fadeout
}
} }
if (m_play_when_host_plays == true && m_playposinfo.isPlaying == false)
if (m_play_when_host_plays == true && m_playposinfo.isPlaying == false && !m_standalone && fadeproc == 0.0f)
return; return;
m_free_filter_envelope->m_transform_x_shift = *getFloatParameter(cpi_freefilter_shiftx); m_free_filter_envelope->m_transform_x_shift = *getFloatParameter(cpi_freefilter_shiftx);
m_free_filter_envelope->m_transform_y_shift = *getFloatParameter(cpi_freefilter_shifty); m_free_filter_envelope->m_transform_y_shift = *getFloatParameter(cpi_freefilter_shifty);
m_free_filter_envelope->m_transform_y_scale = *getFloatParameter(cpi_freefilter_scaley); m_free_filter_envelope->m_transform_y_scale = *getFloatParameter(cpi_freefilter_scaley);
@ -995,13 +1108,31 @@ void PaulstretchpluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, M
{ {
m_buffering_source->getNextAudioBlock(aif); m_buffering_source->getNextAudioBlock(aif);
} }
if ( getParameter(cpi_passthrough) > 0.5f)
// fade processing if necessary
if (fadeproc != 0.0f) {
buffer.applyGainRamp(0, buffer.getNumSamples(), fadeproc > 0.0f ? 0.0f : 1.0f, fadeproc > 0.0f ? 1.0f : 0.0f);
}
if (fadepassthru != 0.0f
|| (passthruEnabled && (!m_is_recording || !m_mute_while_capturing))
|| (recfade != 0.0f && m_mute_while_capturing))
{ {
if (recfade != 0.0f && m_mute_while_capturing) {
// DBG("Invert recfade");
fadepassthru = -recfade;
}
for (int i = 0; i < totalNumInputChannels; ++i) for (int i = 0; i < totalNumInputChannels; ++i)
{ {
buffer.addFrom(i, 0, m_input_buffer, i, 0, buffer.getNumSamples()); if (fadepassthru != 0.0f) {
buffer.addFromWithRamp(i, 0, m_input_buffer.getReadPointer(i), buffer.getNumSamples(), fadepassthru > 0.0f ? 0.0f : 1.0f, fadepassthru > 0.0f ? 1.0f : 0.0f);
}
else
buffer.addFrom(i, 0, m_input_buffer, i, 0, buffer.getNumSamples());
} }
} }
bool abnordetected = false; bool abnordetected = false;
for (int i = 0; i < buffer.getNumChannels(); ++i) for (int i = 0; i < buffer.getNumChannels(); ++i)
{ {
@ -1078,22 +1209,23 @@ void PaulstretchpluginAudioProcessor::setRecordingEnabled(bool b)
m_recbuffer.clear(); m_recbuffer.clear();
m_rec_pos = 0; m_rec_pos = 0;
m_thumb->reset(m_recbuffer.getNumChannels(), getSampleRateChecked(), lenbufframes); m_thumb->reset(m_recbuffer.getNumChannels(), getSampleRateChecked(), lenbufframes);
m_is_recording = true;
m_recorded_range = Range<int>(); m_recorded_range = Range<int>();
m_rec_count = 0; m_rec_count = 0;
m_is_recording_pending = true;
} }
else else
{ {
if (m_is_recording == true) if (m_is_recording == true) {
{
finishRecording(lenbufframes); m_is_recording_finished = false; // will be marked true when the recording is truly done
} m_is_recording_pending = false;
}
} }
} }
double PaulstretchpluginAudioProcessor::getRecordingPositionPercent() double PaulstretchpluginAudioProcessor::getRecordingPositionPercent()
{ {
if (m_is_recording==false) if (m_is_recording_pending==false)
return 0.0; return 0.0;
return 1.0 / m_recbuffer.getNumSamples()*m_rec_pos; return 1.0 / m_recbuffer.getNumSamples()*m_rec_pos;
} }
@ -1117,9 +1249,14 @@ String PaulstretchpluginAudioProcessor::setAudioFile(const URL & url)
} }
if (m_thumb) if (m_thumb)
m_thumb->setSource(new FileInputSource(file)); m_thumb->setSource(new FileInputSource(file));
ScopedLock locker(m_cs);
m_stretch_source->setAudioFile(url);
//Range<double> currange{ *getFloatParameter(cpi_soundstart),*getFloatParameter(cpi_soundend) }; // lets not lock
//ScopedLock locker(m_cs);
m_stretch_source->setAudioFile(url);
//Range<double> currange{ *getFloatParameter(cpi_soundstart),*getFloatParameter(cpi_soundend) };
//if (currange.contains(m_stretch_source->getInfilePositionPercent())==false) //if (currange.contains(m_stretch_source->getInfilePositionPercent())==false)
m_stretch_source->seekPercent(*getFloatParameter(cpi_soundstart)); m_stretch_source->seekPercent(*getFloatParameter(cpi_soundstart));
m_current_file = url; m_current_file = url;
@ -1160,16 +1297,25 @@ void PaulstretchpluginAudioProcessor::timerCallback(int id)
m_max_reclen = *getFloatParameter(cpi_max_capture_len); m_max_reclen = *getFloatParameter(cpi_max_capture_len);
//Logger::writeToLog("Changing max capture len to " + String(m_max_reclen)); //Logger::writeToLog("Changing max capture len to " + String(m_max_reclen));
} }
if (capture == true && m_is_recording == false) if (capture == true && m_is_recording_pending == false)
{ {
setRecordingEnabled(true); setRecordingEnabled(true);
return; return;
} }
if (capture == false && m_is_recording == true) if (capture == false && m_is_recording_pending == true)
{ {
setRecordingEnabled(false); setRecordingEnabled(false);
return; return;
} }
if (m_is_recording_finished) {
DBG("Recording is actually done, commit the finish");
int lenbufframes = getSampleRateChecked()*m_max_reclen;
finishRecording(lenbufframes);
m_is_recording_finished = false;
}
if (m_cur_num_out_chans != *m_outchansparam) if (m_cur_num_out_chans != *m_outchansparam)
{ {
jassert(m_curmaxblocksize > 0); jassert(m_curmaxblocksize > 0);
@ -1224,7 +1370,8 @@ pointer_sized_int PaulstretchpluginAudioProcessor::handleVstManufacturerSpecific
void PaulstretchpluginAudioProcessor::finishRecording(int lenrecording) void PaulstretchpluginAudioProcessor::finishRecording(int lenrecording)
{ {
m_is_recording = false; m_is_recording_finished = false;
m_is_recording_pending = false;
m_current_file = URL(); m_current_file = URL();
m_stretch_source->setAudioBufferAsInputSource(&m_recbuffer, getSampleRateChecked(), lenrecording); m_stretch_source->setAudioBufferAsInputSource(&m_recbuffer, getSampleRateChecked(), lenrecording);
*getFloatParameter(cpi_soundstart) = 0.0f; *getFloatParameter(cpi_soundstart) = 0.0f;

View File

@ -1,19 +1,6 @@
/* // SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
Copyright (C) 2017 Xenakios // Copyright (C) 2020 Jesse Chappell
This program is free software; you can redistribute it and/or modify
it under the terms of version 3 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 3) for more details.
www.gnu.org/licenses
*/
#pragma once #pragma once
@ -198,7 +185,7 @@ public:
void setDirty(); void setDirty();
void setRecordingEnabled(bool b); void setRecordingEnabled(bool b);
bool isRecordingEnabled() { return m_is_recording; } bool isRecordingEnabled() { return m_is_recording_pending; }
double getRecordingPositionPercent(); double getRecordingPositionPercent();
String setAudioFile(const URL& url); String setAudioFile(const URL& url);
URL getAudioFile() { return m_current_file; } URL getAudioFile() { return m_current_file; }
@ -217,6 +204,8 @@ public:
bool m_mute_processed_while_capturing = false; bool m_mute_processed_while_capturing = false;
bool m_use_backgroundbuffering = true; bool m_use_backgroundbuffering = true;
bool m_restore_playstate = true; bool m_restore_playstate = true;
bool m_lastpassthru = false;
bool m_standalone = false;
void resetParameters(); void resetParameters();
void setPreBufferAmount(int x); void setPreBufferAmount(int x);
@ -268,6 +257,8 @@ private:
URL m_current_file; URL m_current_file;
Time m_current_file_date; Time m_current_file_date;
bool m_is_recording = false; bool m_is_recording = false;
volatile bool m_is_recording_pending = false;
volatile bool m_is_recording_finished = false;
TimeSliceThread m_bufferingthread; TimeSliceThread m_bufferingthread;
std::unique_ptr<StretchAudioSource> m_stretch_source; std::unique_ptr<StretchAudioSource> m_stretch_source;
std::unique_ptr<MyBufferingAudioSource> m_buffering_source; std::unique_ptr<MyBufferingAudioSource> m_buffering_source;

View File

@ -1,19 +1,7 @@
/* // SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
// Copyright (C) 2020 Jesse Chappell
Copyright (C) 2017 Xenakios
This program is free software; you can redistribute it and/or modify
it under the terms of version 3 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 3) for more details.
www.gnu.org/licenses
*/
#include "PluginProcessor.h" #include "PluginProcessor.h"

View File

@ -1,22 +1,9 @@
// SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
// Copyright (C) 2020 Jesse Chappell
#pragma once #pragma once
/*
Copyright (C) 2017 Xenakios
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../JuceLibraryCode/JuceHeader.h" #include "../JuceLibraryCode/JuceHeader.h"
class PaulstretchpluginAudioProcessor; class PaulstretchpluginAudioProcessor;

View File

@ -1,19 +1,7 @@
/* // SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
// Copyright (C) 2020 Jesse Chappell
Copyright (C) 2017 Xenakios
This program is free software; you can redistribute it and/or modify
it under the terms of version 3 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 3) for more details.
www.gnu.org/licenses
*/
#include "envelope_component.h" #include "envelope_component.h"

View File

@ -1,19 +1,7 @@
/* // SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
// Copyright (C) 2020 Jesse Chappell
Copyright (C) 2017 Xenakios
This program is free software; you can redistribute it and/or modify
it under the terms of version 3 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 3) for more details.
www.gnu.org/licenses
*/
#pragma once #pragma once

View File

@ -1,19 +1,7 @@
/* // SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
// Copyright (C) 2020 Jesse Chappell
Copyright (C) 2017 Xenakios
This program is free software; you can redistribute it and/or modify
it under the terms of version 3 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 3) for more details.
www.gnu.org/licenses
*/
#pragma once #pragma once

View File

@ -1,19 +1,6 @@
/* // SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
Copyright (C) 2017 Xenakios // Copyright (C) 2020 Jesse Chappell
This program is free software; you can redistribute it and/or modify
it under the terms of version 3 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 3) for more details.
www.gnu.org/licenses
*/
#include "ps3_BufferingAudioSource.h" #include "ps3_BufferingAudioSource.h"

View File

@ -1,19 +1,7 @@
/* // SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
// Copyright (C) 2020 Jesse Chappell
Copyright (C) 2017 Xenakios
This program is free software; you can redistribute it and/or modify
it under the terms of version 3 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 3) for more details.
www.gnu.org/licenses
*/
#pragma once #pragma once