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
# 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

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
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
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.
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.
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 (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)
: findColour (DirectoryContentsDisplayComponent::textColourId));
g.setFont (myFont.withHeight(height * 0.5f));
g.setFont (myFont.withHeight(height * 0.6f));
if (width > 450 && ! isDirectory)
{
@ -673,7 +674,7 @@ void CustomLookAndFeel::drawFileBrowserRow (Graphics& g, int width, int height,
x, 0, sizeX - x, height,
Justification::centredLeft, 1);
g.setFont (myFont.withHeight(height * 0.5f));
g.setFont (myFont.withHeight(height * 0.6f));
g.setColour (Colours::darkgrey);
if (! isDirectory)

View File

@ -1,28 +1,4 @@
/*
==============================================================================
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.
==============================================================================
*/
// SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
#include "../JuceLibraryCode/JuceHeader.h"

View File

@ -1,28 +1,4 @@
/*
==============================================================================
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.
==============================================================================
*/
// SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
//#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client
//extern juce::AudioProcessor* JUCE_API JUCE_CALLTYPE createPluginFilterOfType (juce::AudioProcessor::WrapperType type);
@ -271,11 +247,19 @@ public:
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);
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);
if (bus->isNumberOfChannelsSupported(1)) {
updateMinAndMax (1, minNumOutputs, maxNumOutputs);
}
}
minNumInputs = jmin (minNumInputs, maxNumInputs);
minNumOutputs = jmin (minNumOutputs, maxNumOutputs);
@ -465,9 +449,9 @@ private:
deviceSelector (deviceManagerToUse,
minAudioInputChannels, maxAudioInputChannels,
minAudioOutputChannels, maxAudioOutputChannels,
true,
true, // show midi
(pluginHolder.processor.get() != nullptr && pluginHolder.processor->producesMidi()),
true, false),
false, false),
shouldMuteLabel ("Feedback Loop:", "Feedback Loop:"),
shouldMuteButton ("Mute audio input")
{

View File

@ -1,20 +1,6 @@
/*
Copyright (C) 2006-2011 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
*/
// SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2006-2011 Nasca Octavian Paul
// Author: Nasca Octavian Paul
#pragma once

View File

@ -1,20 +1,7 @@
/*
Copyright (C) 2006-2011 Nasca Octavian Paul
Author: Nasca Octavian Paul
// SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2006-2011 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

View File

@ -1,19 +1,6 @@
/*
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
*/
// SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
// Copyright (C) 2022 Jesse Chappell
#include "StretchSource.h"

View File

@ -1,20 +1,6 @@
/*
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
*/
// SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
// Copyright (C) 2022 Jesse Chappell
#pragma once

View File

@ -1,20 +1,6 @@
/*
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
*/
// SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
// Copyright (C) 2020 Jesse Chappell
#include "PluginProcessor.h"
#include "PluginEditor.h"
@ -84,7 +70,7 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau
{
return jmap<double>(x, 0.0, 1.0, -48.0, 12.0);
};
int tabdepth = 24;
int tabdepth = 26;
#if JUCE_IOS
tabdepth = 36;
@ -209,6 +195,7 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau
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->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()) {
@ -469,7 +456,7 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau
};
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("Ratio mixer", tabbgcol, &m_ratiomixeditor, false);
@ -873,9 +860,6 @@ void PaulstretchpluginAudioProcessorEditor::resized()
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) {
@ -899,6 +883,7 @@ void PaulstretchpluginAudioProcessorEditor::resized()
int totminh = vpminh + orderminh + tabminh + topboxh + toggleh + volh + stretchH + 18;
int shortthresh = vpminh + orderminh + tabminh + topboxh + toggleh;
int veryshortthresh = tabminh + topboxh + toggleh;
if (getHeight() < totminh) {
// not enough vertical space, put the top items in the scrollable viewport
@ -916,19 +901,41 @@ void PaulstretchpluginAudioProcessorEditor::resized()
if (getHeight() < shortthresh) {
// really not much space, put group scroll in a new tab
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);
}
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());
groupsbox.items.add(FlexItem(minw, orderminh, m_spec_order_ed).withMargin(2));
useh += orderminh + 4;
m_shortMode = true;
} else {
reparentIfNecessary(&m_spec_order_ed, this);
reparentItemsIfNecessary(topbox, this);
reparentItemsIfNecessary(togglesbox, this);
if (m_wavefilter_tab.getNumTabs() > 3) {
// bring it back
@ -940,6 +947,10 @@ void PaulstretchpluginAudioProcessorEditor::resized()
addAndMakeVisible(m_groupviewport.get());
}
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_spec_order_ed, this);
reparentIfNecessary(m_stretchgroup.get(), this);
//reparentItemsIfNecessary(togglesbox, 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(6, 3));
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_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) {
m_groupcontainer->repaint();
}
@ -1317,7 +1336,8 @@ void PaulstretchpluginAudioProcessorEditor::toggleFileBrowser()
m_filechooser = std::make_unique<MyFileBrowserComponent>(processor);
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());
if (m_filechooser->isVisible())
m_import_button.setButtonText("Hide browser");
@ -1667,6 +1687,14 @@ void WaveformComponent::mouseWheelMove(const MouseEvent & e, const MouseWheelDet
double t0 = normt - newScale * 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);
t1 = jlimit(0.0,1.0, t1);
@ -2310,7 +2338,17 @@ void PerfMeterComponent::timerCallback()
void zoom_scrollbar::mouseDown(const MouseEvent &e)
{
auto ha = get_hot_area(e.x, e.y);
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&)
@ -2341,21 +2379,19 @@ void zoom_scrollbar::mouseMove(const MouseEvent &e)
void zoom_scrollbar::mouseDrag(const MouseEvent &e)
{
if (m_hot_area == ha_none)
return;
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));
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));
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 old_start = m_start;
@ -2370,6 +2406,21 @@ void zoom_scrollbar::mouseDrag(const MouseEvent &e)
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)
{
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)
{
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());
int x0 = (int)(getWidth()*m_therange.getStart());
int x1 = (int)(getWidth()*m_therange.getEnd());
if (m_hot_area != ha_none)
g.setColour(Colours::white.withAlpha(0.8f));
else g.setColour(Colours::grey);
if (m_hot_area == ha_handle)
barcolor = barcolor.brighter(0.5f); //Colours::white.withAlpha(0.8f);
g.setColour(barcolor);
//g.fillRect(x0, 0, x1 - x0, getHeight());
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)
@ -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)
{
int radius = 10;
int radius = 16;
#if JUCE_IOS
radius *= 2;
#endif

View File

@ -1,19 +1,6 @@
/*
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
*/
// SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
// Copyright (C) 2020 Jesse Chappell
#pragma once
@ -41,6 +28,7 @@ public:
void mouseEnter(const MouseEvent &event) override;
void mouseExit(const MouseEvent &event) override;
void mouseDoubleClick (const MouseEvent&) override;
void mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& wd) override;
void paint(Graphics &g) override;
std::function<void(Range<double>)> RangeChanged;
@ -52,6 +40,7 @@ private:
hot_area m_hot_area = ha_none;
hot_area get_hot_area(int x, int y);
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 "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);
}
#if JUCE_IOS
#define ALTBUS_ACTIVE true
#else
#define ALTBUS_ACTIVE false
#endif
//==============================================================================
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)
{
DBG("Attempt proc const");
m_filechoose_callback = [this](const FileChooser& chooser)
{
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({ 1.0,0.75 });
m_free_filter_envelope->set_reset_nodes(m_free_filter_envelope->get_all_nodes());
DBG("recbuffer");
m_recbuffer.setSize(2, 48000);
m_recbuffer.clear();
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)
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[1] = new AudioParameterBool("enab_specmodule1", "Enable tonal vs noise", false);
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[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->setOnsetDetection(0.0);
m_stretch_source->setLoopingEnabled(true);
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("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));
@ -216,11 +222,12 @@ m_bufferingthread("pspluginprebufferthread"), m_is_stand_alone_offline(is_stand_
if (!m_is_stand_alone_offline) {
setPreBufferAmount(2);
startTimer(1, 50);
startTimer(1, 40);
}
m_show_technical_info = m_propsfile->m_props_file->getBoolValue("showtechnicalinfo", false);
DBG("Constructed PS plugin");
}
PaulstretchpluginAudioProcessor::~PaulstretchpluginAudioProcessor()
@ -764,7 +771,7 @@ void PaulstretchpluginAudioProcessor::prepareToPlay(double sampleRate, int sampl
m_adsr.setSampleRate(sampleRate);
m_cur_sr = sampleRate;
m_curmaxblocksize = samplesPerBlock;
m_input_buffer.setSize(getMainBusNumInputChannels(), samplesPerBlock);
m_input_buffer.setSize(getTotalNumInputChannels(), samplesPerBlock);
*getBoolParameter(cpi_rewind) = false;
m_lastrewind = false;
int numoutchans = *m_outchansparam;
@ -794,6 +801,8 @@ void PaulstretchpluginAudioProcessor::prepareToPlay(double sampleRate, int sampl
{
m_buffering_source->prepareToPlay(samplesPerBlock, getSampleRateChecked());
}
m_standalone = juce::PluginHostType::getPluginLoadedAs() == AudioProcessor::wrapperType_Standalone;
}
void PaulstretchpluginAudioProcessor::releaseResources()
@ -808,10 +817,14 @@ bool PaulstretchpluginAudioProcessor::isBusesLayoutSupported (const BusesLayout&
ignoreUnused (layouts);
return true;
#else
// support anything
return true;
// This is the place where you check if the layout is supported.
// In this template code we only support mono or stereo.
if (layouts.getMainOutputChannelSet() != AudioChannelSet::mono()
&& layouts.getMainOutputChannelSet() != AudioChannelSet::stereo())
if ( /* layouts.getMainOutputChannelSet() != AudioChannelSet::mono() && */
layouts.getMainOutputChannelSet() != AudioChannelSet::stereo())
return false;
// This checks if the input layout matches the output layout
@ -825,21 +838,42 @@ bool PaulstretchpluginAudioProcessor::isBusesLayoutSupported (const BusesLayout&
}
#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)
{
int channel_to_copy = i % src.getNumChannels();
if (destbufpos + src.getNumSamples() > maxdestpos)
if (destbufpos + useNumSamples > maxdestpos)
{
int wrappos = (destbufpos + src.getNumSamples()) % maxdestpos;
int partial_len = src.getNumSamples() - 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);
int wrappos = (destbufpos + useNumSamples) % maxdestpos;
int partial_len = useNumSamples - 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
{
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);
const int totalNumInputChannels = getTotalNumInputChannels();
const int totalNumOutputChannels = getTotalNumOutputChannels();
bool passthruEnabled = getParameter(cpi_passthrough) > 0.5f;
AudioPlayHead* phead = getPlayHead();
bool seektostart = false;
if (phead != nullptr)
{
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;
}
ScopedNoDenormals noDenormals;
double srtemp = getSampleRate();
if (srtemp != m_cur_sr)
@ -870,30 +913,87 @@ void PaulstretchpluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, M
m_prebufsmoother.setSlope(0.9, srtemp / buffer.getNumSamples());
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)
m_input_buffer.copyFrom(i, 0, buffer, i, 0, buffer.getNumSamples());
for (int i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
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)
{
m_previewcomponent->processBlock(getSampleRate(), buffer);
return;
}
if (m_prebuffering_inited == false)
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;
}
int recbuflenframes = m_max_reclen * getSampleRate();
copyAudioBufferWrappingPosition(buffer, m_recbuffer, m_rec_pos, recbuflenframes);
m_thumb->addBlock(m_rec_pos, buffer, 0, buffer.getNumSamples());
copyAudioBufferWrappingPosition(m_input_buffer, buffer.getNumSamples(), m_recbuffer, m_rec_pos, recbuflenframes, recfade);
m_thumb->addBlock(m_rec_pos, m_input_buffer, 0, buffer.getNumSamples());
m_rec_pos = (m_rec_pos + buffer.getNumSamples()) % recbuflenframes;
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)
m_recorded_range = { 0, m_rec_count };
if (m_mute_while_capturing == true)
if (m_mute_while_capturing == true && passthruEnabled) {
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)
return;
@ -904,17 +1004,30 @@ void PaulstretchpluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, M
double t1 = *getFloatParameter(cpi_soundend);
sanitizeTimeRange(t0, t1);
m_stretch_source->setPlayRange({ t0,t1 });
float fadeproc = 0.0f;
if (m_last_host_playing == false && m_playposinfo.isPlaying)
{
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;
}
else if (m_last_host_playing == true && m_playposinfo.isPlaying == 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;
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_scale = *getFloatParameter(cpi_freefilter_scaley);
@ -995,13 +1108,31 @@ void PaulstretchpluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, M
{
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)
{
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;
for (int i = 0; i < buffer.getNumChannels(); ++i)
{
@ -1078,22 +1209,23 @@ void PaulstretchpluginAudioProcessor::setRecordingEnabled(bool b)
m_recbuffer.clear();
m_rec_pos = 0;
m_thumb->reset(m_recbuffer.getNumChannels(), getSampleRateChecked(), lenbufframes);
m_is_recording = true;
m_recorded_range = Range<int>();
m_rec_count = 0;
m_is_recording_pending = true;
}
else
{
if (m_is_recording == true)
{
finishRecording(lenbufframes);
if (m_is_recording == true) {
m_is_recording_finished = false; // will be marked true when the recording is truly done
m_is_recording_pending = false;
}
}
}
double PaulstretchpluginAudioProcessor::getRecordingPositionPercent()
{
if (m_is_recording==false)
if (m_is_recording_pending==false)
return 0.0;
return 1.0 / m_recbuffer.getNumSamples()*m_rec_pos;
}
@ -1117,8 +1249,13 @@ String PaulstretchpluginAudioProcessor::setAudioFile(const URL & url)
}
if (m_thumb)
m_thumb->setSource(new FileInputSource(file));
ScopedLock locker(m_cs);
// 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)
m_stretch_source->seekPercent(*getFloatParameter(cpi_soundstart));
@ -1160,16 +1297,25 @@ void PaulstretchpluginAudioProcessor::timerCallback(int id)
m_max_reclen = *getFloatParameter(cpi_max_capture_len);
//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);
return;
}
if (capture == false && m_is_recording == true)
if (capture == false && m_is_recording_pending == true)
{
setRecordingEnabled(false);
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)
{
jassert(m_curmaxblocksize > 0);
@ -1224,7 +1370,8 @@ pointer_sized_int PaulstretchpluginAudioProcessor::handleVstManufacturerSpecific
void PaulstretchpluginAudioProcessor::finishRecording(int lenrecording)
{
m_is_recording = false;
m_is_recording_finished = false;
m_is_recording_pending = false;
m_current_file = URL();
m_stretch_source->setAudioBufferAsInputSource(&m_recbuffer, getSampleRateChecked(), lenrecording);
*getFloatParameter(cpi_soundstart) = 0.0f;

View File

@ -1,19 +1,6 @@
/*
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
*/
// SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
// Copyright (C) 2020 Jesse Chappell
#pragma once
@ -198,7 +185,7 @@ public:
void setDirty();
void setRecordingEnabled(bool b);
bool isRecordingEnabled() { return m_is_recording; }
bool isRecordingEnabled() { return m_is_recording_pending; }
double getRecordingPositionPercent();
String setAudioFile(const URL& url);
URL getAudioFile() { return m_current_file; }
@ -217,6 +204,8 @@ public:
bool m_mute_processed_while_capturing = false;
bool m_use_backgroundbuffering = true;
bool m_restore_playstate = true;
bool m_lastpassthru = false;
bool m_standalone = false;
void resetParameters();
void setPreBufferAmount(int x);
@ -268,6 +257,8 @@ private:
URL m_current_file;
Time m_current_file_date;
bool m_is_recording = false;
volatile bool m_is_recording_pending = false;
volatile bool m_is_recording_finished = false;
TimeSliceThread m_bufferingthread;
std::unique_ptr<StretchAudioSource> m_stretch_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"

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
/*
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"
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"

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

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

View File

@ -1,19 +1,6 @@
/*
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
*/
// SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
// Copyright (C) 2020 Jesse Chappell
#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