update to support juce 6.1. added mute audio while processing capture option. added a mac specific priority fix. use async popup menus and browsers where needed.

This commit is contained in:
essej 2022-04-02 12:45:02 -04:00
parent 86f1a8c594
commit 8c4a20ecd6
10 changed files with 188 additions and 81 deletions

View File

@ -0,0 +1,14 @@
// SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2020 Jesse Chappell
#pragma once
void getSafeAreaInsets(void * component, float & top, float & bottom, float & left, float & right);
#if JUCE_MAC
void disableAppNap();
#endif

View File

@ -0,0 +1,46 @@
// SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2020 Jesse Chappell
#include "CrossPlatformUtils.h"
//#include "../JuceLibraryCode/JuceHeader.h"
#define JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED 1
#include <juce_core/system/juce_TargetPlatform.h>
#if JUCE_MAC
//#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
void getSafeAreaInsets(void * component, float & top, float & bottom, float & left, float & right)
{
top = bottom = left = right = 0;
}
void disableAppNap() {
// Does the App Nap API even exist on this Mac?
if ([[NSProcessInfo processInfo] respondsToSelector:@selector(beginActivityWithOptions:reason:)]) {
// If the API exists, then disable App Nap...
// From NSProcessInfo.h:
// NSActivityIdleSystemSleepDisabled = (1ULL << 20),
// NSActivityUserInitiated = (0x00FFFFFFULL | NSActivityIdleSystemSleepDisabled),
// NSActivityLatencyCritical = 0xFF00000000ULL
uint64_t options = (0x00FFFFFFULL | (1ULL << 20)) | 0xFF00000000ULL;
// NSActivityLatencyCritical | NSActivityUserInitiated
[[NSProcessInfo processInfo] beginActivityWithOptions:options
reason:@"avoiding audio hiccups and reducing latency"];
}
}
#endif

View File

@ -157,7 +157,7 @@ void StretchAudioSource::setAudioBufferAsInputSource(AudioBuffer<float>* buf, in
ScopedLock locker(m_cs); ScopedLock locker(m_cs);
m_inputfile->setAudioBuffer(buf, sr, len); m_inputfile->setAudioBuffer(buf, sr, len);
m_seekpos = 0.0; m_seekpos = 0.0;
m_audiobuffer_is_source = true;
m_curfile = File(); m_curfile = File();
if (m_playrange.isEmpty()) if (m_playrange.isEmpty())
setPlayRange({ 0.0,1.0 }); setPlayRange({ 0.0,1.0 });
@ -512,6 +512,7 @@ String StretchAudioSource::setAudioFile(File file)
{ {
m_curfile = file; m_curfile = file;
m_firstbuffer = true; m_firstbuffer = true;
m_audiobuffer_is_source = false;
return String(); return String();
} }
return "Could not open file"; return "Could not open file";

View File

@ -99,6 +99,7 @@ public:
void setLoopingEnabled(bool b); void setLoopingEnabled(bool b);
void setMaxLoops(int64_t numloops) { m_maxloops = numloops; } void setMaxLoops(int64_t numloops) { m_maxloops = numloops; }
void setAudioBufferAsInputSource(AudioBuffer<float>* buf, int sr, int len); void setAudioBufferAsInputSource(AudioBuffer<float>* buf, int sr, int len);
bool isAudioBufferInputSource() const { return m_audiobuffer_is_source; }
void setMainVolume(double decibels); void setMainVolume(double decibels);
double getMainVolume() const { return m_main_volume; } double getMainVolume() const { return m_main_volume; }
//void setSpectralModulesEnabled(const std::array<AudioParameterBool*, 9>& params); //void setSpectralModulesEnabled(const std::array<AudioParameterBool*, 9>& params);
@ -148,6 +149,7 @@ private:
bool m_stream_end_reached = false; bool m_stream_end_reached = false;
int64_t m_output_silence_counter = 0; int64_t m_output_silence_counter = 0;
File m_curfile; File m_curfile;
bool m_audiobuffer_is_source = false;
int64_t m_maxloops = 0; int64_t m_maxloops = 0;
std::unique_ptr<WDL_Resampler> m_resampler; std::unique_ptr<WDL_Resampler> m_resampler;
std::vector<double> m_resampler_outbuf; std::vector<double> m_resampler_outbuf;

View File

@ -21,6 +21,8 @@ www.gnu.org/licenses
#include <array> #include <array>
#include "RenderSettingsComponent.h" #include "RenderSettingsComponent.h"
#include "CrossPlatformUtils.h"
static void handleSettingsMenuModalCallback(int choice, PaulstretchpluginAudioProcessorEditor* ed) static void handleSettingsMenuModalCallback(int choice, PaulstretchpluginAudioProcessorEditor* ed)
{ {
ed->executeModalMenuAction(0,choice); ed->executeModalMenuAction(0,choice);
@ -243,6 +245,14 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau
startTimer(3, 200); startTimer(3, 200);
m_wavecomponent.startTimer(100); m_wavecomponent.startTimer(100);
setResizeLimits(320, 14*25 + 120, 40000, 4000);
setResizable(true, !JUCEApplicationBase::isStandaloneApp());
#if JUCE_MAC
disableAppNap();
#endif
} }
PaulstretchpluginAudioProcessorEditor::~PaulstretchpluginAudioProcessorEditor() PaulstretchpluginAudioProcessorEditor::~PaulstretchpluginAudioProcessorEditor()
@ -277,6 +287,10 @@ void PaulstretchpluginAudioProcessorEditor::executeModalMenuAction(int menuid, i
{ {
toggleBool(processor.m_mute_while_capturing); toggleBool(processor.m_mute_while_capturing);
} }
if (r == 10)
{
toggleBool(processor.m_mute_processed_while_capturing);
}
if (r == 4) if (r == 4)
{ {
processor.resetParameters(); processor.resetParameters();
@ -537,7 +551,8 @@ void PaulstretchpluginAudioProcessorEditor::showSettingsMenu()
m_settings_menu.addItem(5, "Load file with plugin state", true, processor.m_load_file_with_state); m_settings_menu.addItem(5, "Load file with plugin state", true, processor.m_load_file_with_state);
m_settings_menu.addItem(1, "Play when host transport running", true, processor.m_play_when_host_plays); m_settings_menu.addItem(1, "Play when host transport running", true, processor.m_play_when_host_plays);
m_settings_menu.addItem(2, "Capture when host transport running", true, processor.m_capture_when_host_plays); m_settings_menu.addItem(2, "Capture when host transport running", true, processor.m_capture_when_host_plays);
m_settings_menu.addItem(8, "Mute audio while capturing", true, processor.m_mute_while_capturing); m_settings_menu.addItem(8, "Mute passthrough while capturing", true, processor.m_mute_while_capturing);
m_settings_menu.addItem(10, "Mute processed audio output while capturing", true, processor.m_mute_processed_while_capturing);
m_settings_menu.addItem(9, "Save captured audio to disk", true, processor.m_save_captured_audio); m_settings_menu.addItem(9, "Save captured audio to disk", true, processor.m_save_captured_audio);
int capturelen = *processor.getFloatParameter(cpi_max_capture_len); int capturelen = *processor.getFloatParameter(cpi_max_capture_len);
PopupMenu capturelenmenu; PopupMenu capturelenmenu;
@ -1362,7 +1377,10 @@ void PerfMeterComponent::mouseDown(const MouseEvent & ev)
bufferingmenu.addItem(103, "Large", true, curbufamount == 3); bufferingmenu.addItem(103, "Large", true, curbufamount == 3);
bufferingmenu.addItem(104, "Very large", true, curbufamount == 4); bufferingmenu.addItem(104, "Very large", true, curbufamount == 4);
bufferingmenu.addItem(105, "Huge", true, curbufamount == 5); bufferingmenu.addItem(105, "Huge", true, curbufamount == 5);
int r = bufferingmenu.show();
auto opts = PopupMenu::Options();
bufferingmenu.showMenuAsync(opts, [this](int r) {
if (r >= 100 && r < 200) if (r >= 100 && r < 200)
{ {
if (r == 100) if (r == 100)
@ -1370,6 +1388,7 @@ void PerfMeterComponent::mouseDown(const MouseEvent & ev)
if (r > 100) if (r > 100)
m_proc->setPreBufferAmount(r - 100); m_proc->setPreBufferAmount(r - 100);
} }
});
} }
void PerfMeterComponent::timerCallback() void PerfMeterComponent::timerCallback()

View File

@ -58,7 +58,8 @@ inline AudioParameterFloat* make_floatpar(String id, String name, float minv, fl
//============================================================================== //==============================================================================
PaulstretchpluginAudioProcessor::PaulstretchpluginAudioProcessor(bool is_stand_alone_offline) PaulstretchpluginAudioProcessor::PaulstretchpluginAudioProcessor(bool is_stand_alone_offline)
: m_is_stand_alone_offline(is_stand_alone_offline), m_bufferingthread("pspluginprebufferthread") : AudioProcessor(PaulstretchpluginAudioProcessor::BusesProperties().withInput("Main In", AudioChannelSet::stereo(), true).withOutput ("Main Out", AudioChannelSet::stereo(), true)),
m_is_stand_alone_offline(is_stand_alone_offline), m_bufferingthread("pspluginprebufferthread")
{ {
m_filechoose_callback = [this](const FileChooser& chooser) m_filechoose_callback = [this](const FileChooser& chooser)
{ {
@ -214,6 +215,8 @@ PaulstretchpluginAudioProcessor::PaulstretchpluginAudioProcessor(bool is_stand_a
PaulstretchpluginAudioProcessor::~PaulstretchpluginAudioProcessor() PaulstretchpluginAudioProcessor::~PaulstretchpluginAudioProcessor()
{ {
stopTimer(1);
//Logger::writeToLog("PaulX AudioProcessor destroyed"); //Logger::writeToLog("PaulX AudioProcessor destroyed");
if (m_thumb) if (m_thumb)
m_thumb->removeAllChangeListeners(); m_thumb->removeAllChangeListeners();
@ -281,7 +284,7 @@ ValueTree PaulstretchpluginAudioProcessor::getStateTree(bool ignoreoptions, bool
paramtree.setProperty("loadfilewithstate", m_load_file_with_state, nullptr); paramtree.setProperty("loadfilewithstate", m_load_file_with_state, nullptr);
storeToTreeProperties(paramtree, nullptr, "playwhenhostrunning", m_play_when_host_plays, storeToTreeProperties(paramtree, nullptr, "playwhenhostrunning", m_play_when_host_plays,
"capturewhenhostrunning", m_capture_when_host_plays,"savecapturedaudio",m_save_captured_audio, "capturewhenhostrunning", m_capture_when_host_plays,"savecapturedaudio",m_save_captured_audio,
"mutewhilecapturing",m_mute_while_capturing); "mutewhilecapturing",m_mute_while_capturing, "muteprocwhilecapturing",m_mute_processed_while_capturing);
} }
storeToTreeProperties(paramtree, nullptr, "tabaindex", m_cur_tab_index); storeToTreeProperties(paramtree, nullptr, "tabaindex", m_cur_tab_index);
storeToTreeProperties(paramtree, nullptr, "waveviewrange", m_wave_view_range); storeToTreeProperties(paramtree, nullptr, "waveviewrange", m_wave_view_range);
@ -301,7 +304,7 @@ void PaulstretchpluginAudioProcessor::setStateFromTree(ValueTree tree)
m_load_file_with_state = tree.getProperty("loadfilewithstate", true); m_load_file_with_state = tree.getProperty("loadfilewithstate", true);
getFromTreeProperties(tree, "playwhenhostrunning", m_play_when_host_plays, getFromTreeProperties(tree, "playwhenhostrunning", m_play_when_host_plays,
"capturewhenhostrunning", m_capture_when_host_plays,"mutewhilecapturing",m_mute_while_capturing, "capturewhenhostrunning", m_capture_when_host_plays,"mutewhilecapturing",m_mute_while_capturing,
"savecapturedaudio",m_save_captured_audio); "savecapturedaudio",m_save_captured_audio, "muteprocwhilecapturing",m_mute_processed_while_capturing);
getFromTreeProperties(tree, "tabaindex", m_cur_tab_index); getFromTreeProperties(tree, "tabaindex", m_cur_tab_index);
if (tree.hasProperty("numspectralstagesb")) if (tree.hasProperty("numspectralstagesb"))
{ {
@ -526,6 +529,8 @@ void PaulstretchpluginAudioProcessor::saveCaptureBuffer()
inchans, 32, {}, 0)); inchans, 32, {}, 0));
if (writer != nullptr) if (writer != nullptr)
{ {
outstream.release(); // the writer takes ownership
auto sourcebuffer = getStretchSource()->getSourceAudioBuffer(); auto sourcebuffer = getStretchSource()->getSourceAudioBuffer();
jassert(sourcebuffer->getNumChannels() == inchans); jassert(sourcebuffer->getNumChannels() == inchans);
jassert(sourcebuffer->getNumSamples() > 0); jassert(sourcebuffer->getNumSamples() > 0);
@ -596,7 +601,13 @@ String PaulstretchpluginAudioProcessor::offlineRender(OfflineRenderParams render
{ {
//delete outstream; //delete outstream;
jassert(false); jassert(false);
}
m_offline_render_state = 200;
Logger::writeToLog("Render failed, could not open file!");
return;
} else {
outstream.release(); // the writer takes ownership
AudioBuffer<float> renderbuffer{ numoutchans, blocksize }; AudioBuffer<float> renderbuffer{ numoutchans, blocksize };
MidiBuffer dummymidi; MidiBuffer dummymidi;
double outlensecs = sc->getOutputDurationSecondsForRange(sc->getPlayRange(),sc->getFFTSize()); double outlensecs = sc->getOutputDurationSecondsForRange(sc->getPlayRange(),sc->getFFTSize());
@ -617,7 +628,7 @@ String PaulstretchpluginAudioProcessor::offlineRender(OfflineRenderParams render
} }
m_offline_render_state = 200; m_offline_render_state = 200;
Logger::writeToLog("Rendered ok!"); Logger::writeToLog("Rendered ok!");
}
}; };
std::thread th(rendertask); std::thread th(rendertask);
th.detach(); th.detach();
@ -768,6 +779,8 @@ void PaulstretchpluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, M
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)
buffer.clear(); buffer.clear();
if (m_mute_processed_while_capturing == true)
return; return;
} }
jassert(m_buffering_source != nullptr); jassert(m_buffering_source != nullptr);

View File

@ -207,6 +207,7 @@ public:
bool m_play_when_host_plays = false; bool m_play_when_host_plays = false;
bool m_capture_when_host_plays = false; bool m_capture_when_host_plays = false;
bool m_mute_while_capturing = false; bool m_mute_while_capturing = false;
bool m_mute_processed_while_capturing = false;
bool m_use_backgroundbuffering = true; bool m_use_backgroundbuffering = true;
void resetParameters(); void resetParameters();
void setPreBufferAmount(int x); void setPreBufferAmount(int x);

View File

@ -186,10 +186,9 @@ void RenderSettingsComponent::buttonClicked (Button* buttonThatWasClicked)
FileChooser myChooser("Please select audio file to render...", FileChooser myChooser("Please select audio file to render...",
lastexportfolder, lastexportfolder,
"*.wav"); "*.wav");
if (myChooser.browseForFileToSave(true)) myChooser.launchAsync(FileBrowserComponent::saveMode, [this](const FileChooser &chooser) {
{ outfileNameEditor.setText(chooser.getResult().getFullPathName(), dontSendNotification);
outfileNameEditor.setText(myChooser.getResult().getFullPathName(), dontSendNotification); });
}
} }
} }

View File

@ -225,11 +225,13 @@ void EnvelopeComponent::mouseDown(const MouseEvent & ev)
if (ev.mods.isRightButtonDown() == true) if (ev.mods.isRightButtonDown() == true)
{ {
PopupMenu menu; PopupMenu menu;
PopupMenu::Options opts;
menu.addItem(1, "Reset"); menu.addItem(1, "Reset");
menu.addItem(2, "Invert"); menu.addItem(2, "Invert");
menu.addItem(3, "Wrap envelope X transform", true, m_envelope->m_transform_wrap_x); menu.addItem(3, "Wrap envelope X transform", true, m_envelope->m_transform_wrap_x);
menu.addItem(4, "Envelope Y random linear interpolation", true, m_envelope->m_transform_y_random_linear_interpolation); menu.addItem(4, "Envelope Y random linear interpolation", true, m_envelope->m_transform_y_random_linear_interpolation);
int r = menu.show();
auto callback = [this] (int r) {
if (r == 1) if (r == 1)
{ {
ScopedLock locker(*m_cs); ScopedLock locker(*m_cs);
@ -252,6 +254,10 @@ void EnvelopeComponent::mouseDown(const MouseEvent & ev)
toggleBool(m_envelope->m_transform_y_random_linear_interpolation); toggleBool(m_envelope->m_transform_y_random_linear_interpolation);
} }
repaint(); repaint();
};
menu.showMenuAsync(opts, callback);
return; return;
} }
m_node_to_drag = find_hot_envelope_point(ev.x, ev.y); m_node_to_drag = find_hot_envelope_point(ev.x, ev.y);

View File

@ -1,20 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<JUCERPROJECT id="fn1Rg8" name="PaulXStretch" displaySplashScreen="0" reportAppUsage="0" <JUCERPROJECT id="fn1Rg8" name="PaulXStretch" displaySplashScreen="0" reportAppUsage="0"
splashScreenColour="Dark" projectType="audioplug" version="1.0.0" splashScreenColour="Dark" projectType="audioplug" version="1.2.5"
bundleIdentifier="com.xenakios.paulxstretch" includeBinaryInAppConfig="1" bundleIdentifier="com.xenakios.paulxstretch" includeBinaryInAppConfig="1"
cppLanguageStandard="latest" companyCopyright="" buildVST="1" cppLanguageStandard="latest" companyCopyright="" buildVST="0"
buildVST3="1" buildAU="1" buildAUv3="0" buildRTAS="0" buildAAX="0" buildVST3="1" buildAU="1" buildAUv3="0" buildRTAS="0" buildAAX="0"
buildStandalone="1" enableIAA="0" pluginName="PaulXStretch" pluginDesc="PaulXStretch" buildStandalone="1" enableIAA="0" pluginName="PaulXStretch" pluginDesc="PaulXStretch"
pluginManufacturer="Xenakios" pluginManufacturerCode="XenS" pluginCode="Fn1r" pluginManufacturer="Xenakios" pluginManufacturerCode="XenS" pluginCode="Fn1r"
pluginChannelConfigs="{2,2},{2,4}, {2,8}, {8,8} " pluginIsSynth="0" pluginIsSynth="0" pluginWantsMidiIn="0" pluginProducesMidiOut="0"
pluginWantsMidiIn="0" pluginProducesMidiOut="0" pluginIsMidiEffectPlugin="0" pluginIsMidiEffectPlugin="0" pluginEditorRequiresKeys="0" pluginAUExportPrefix="paulxstretchAU"
pluginEditorRequiresKeys="0" pluginAUExportPrefix="paulxstretchAU"
aaxIdentifier="com.yourcompany.paulstretchplugin" pluginAAXCategory="2" aaxIdentifier="com.yourcompany.paulstretchplugin" pluginAAXCategory="2"
headerPath="&#10;&#10;" pluginFormats="buildVST,buildVST3,buildAU,buildStandalone" headerPath="&#10;&#10;" pluginFormats="buildAU,buildStandalone,buildVST3"
jucerFormatVersion="1"> jucerFormatVersion="1">
<MAINGROUP id="nozXHl" name="PaulXStretch"> <MAINGROUP id="nozXHl" name="PaulXStretch">
<GROUP id="{03DA6B32-F666-FF60-F168-4385D0847058}" name="Source"> <GROUP id="{03DA6B32-F666-FF60-F168-4385D0847058}" name="Source">
<FILE id="zvau5B" name="CrossPlatformUtils.h" compile="0" resource="0"
file="Source/CrossPlatformUtils.h"/>
<FILE id="fjYsFD" name="CrossPlatformUtilsMac.mm" compile="1" resource="0"
file="Source/CrossPlatformUtilsMac.mm"/>
<FILE id="RanaVV" name="RenderSettingsComponent.cpp" compile="1" resource="0" <FILE id="RanaVV" name="RenderSettingsComponent.cpp" compile="1" resource="0"
file="Source/RenderSettingsComponent.cpp"/> file="Source/RenderSettingsComponent.cpp"/>
<FILE id="Mz5aVb" name="envelope_component.cpp" compile="1" resource="0" <FILE id="Mz5aVb" name="envelope_component.cpp" compile="1" resource="0"
@ -51,19 +54,22 @@
</GROUP> </GROUP>
</MAINGROUP> </MAINGROUP>
<EXPORTFORMATS> <EXPORTFORMATS>
<XCODE_MAC targetFolder="Builds/MacOSX" extraLinkerFlags="/usr/local/Cellar/fftw/3.3.8/lib/libfftw3f.a&#10;"> <XCODE_MAC targetFolder="Builds/MacOSX" externalLibraries="fftw3f" microphonePermissionNeeded="1"
microphonePermissionsText="This application requires audio input to capture live audio for processing"
hardenedRuntime="1" hardenedRuntimeOptions="com.apple.security.device.audio-input"
xcodeValidArchs="arm64,x86_64" buildNumber="100">
<CONFIGURATIONS> <CONFIGURATIONS>
<CONFIGURATION name="Debug" enablePluginBinaryCopyStep="1" isDebug="1" optimisation="1" <CONFIGURATION name="Debug" enablePluginBinaryCopyStep="1" isDebug="1" optimisation="1"
linkTimeOptimisation="0" targetName="PaulXStretch" headerPath="Source/PS_Source&#10;Source/WDL&#10;/Users/teemu/codeprojects/JUCE/modules/vst2.x&#10;" linkTimeOptimisation="0" targetName="PaulXStretch" headerPath="Source/PS_Source&#10;Source/WDL&#10;${HOME}/devstatic/include&#10;"
libraryPath="/usr/local/Cellar/fftw/3.3.8/lib" cppLibType="libc++" libraryPath="${HOME}/devstatic/lib&#10;" cppLibType="libc++"
osxArchitecture="64BitIntel" osxCompatibility="10.9 SDK" defines="JUCE_NO_DEPRECATION_WARNINGS" osxArchitecture="64BitIntel" osxCompatibility="10.10 SDK" defines="JUCE_NO_DEPRECATION_WARNINGS"
macOSDeploymentTarget="10.9"/> macOSDeploymentTarget="10.10"/>
<CONFIGURATION name="Release" enablePluginBinaryCopyStep="1" isDebug="0" optimisation="3" <CONFIGURATION name="Release" enablePluginBinaryCopyStep="0" isDebug="0" optimisation="3"
linkTimeOptimisation="0" targetName="PaulXStretch" headerPath="Source/PS_Source&#10;Source/WDL&#10;/Users/teemu/codeprojects/JUCE/modules/vst2.x&#10;" linkTimeOptimisation="0" targetName="PaulXStretch" headerPath="Source/PS_Source&#10;Source/WDL&#10;${HOME}/devstatic/include&#10;"
osxCompatibility="10.9 SDK" osxArchitecture="64BitIntel" cppLibType="libc++" osxCompatibility="10.10 SDK" osxArchitecture="64BitIntel" cppLibType="libc++"
libraryPath="/usr/local/Cellar/fftw/3.3.8/lib" defines="JUCE_NO_DEPRECATION_WARNINGS" libraryPath="${HOME}/devstatic/lib&#10;" defines="JUCE_NO_DEPRECATION_WARNINGS"
auBinaryLocation="$(HOME)/Library/Audio/Plug-Ins/Components" auBinaryLocation="$(HOME)/Library/Audio/Plug-Ins/Components"
macOSDeploymentTarget="10.9"/> macOSDeploymentTarget="10.10"/>
</CONFIGURATIONS> </CONFIGURATIONS>
<MODULEPATHS> <MODULEPATHS>
<MODULEPATH id="juce_core" path="../JUCE/modules"/> <MODULEPATH id="juce_core" path="../JUCE/modules"/>