diff --git a/CHANGES.md b/CHANGES.md index 04db04b..afd8968 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,17 +1,27 @@ ## PaulXStretch Change History -**v1.5.3** (04-25-2022) +**v1.6.0** (2022-06-15) + - Added live output recording feature + - Added selection of directory for recording/capture audio files, and some format options, now defaulting to FLAC + - Added offline render feature to plugin version + - Added Binaural Beats feature (from original paulstretch) + - Added CLAP plugin support (https://github.com/free-audio/clap for info) + - Fixed an initialization bug + - Compile fix for gcc12 + + +**v1.5.3** (2022-04-25) - Fixed Mac AudioUnit validation error and potentional crash risk when using more than 8 channels. -**v1.5.2** (04-24-2022) +**v1.5.2** (2022-04-24) - Increased maximum number of channels to 32 - Optimized FFTW build to use available hardware - Fixed crash issue some people were seeing on older windows systems - Added option (now default) to end recording automatically when chosen buffer size is reached. - More extremely small window size tweaks -**v1.5.1** (04-22-2022) +**v1.5.1** (2022-04-22) - fixed passthrough when capturing - added declicking fades when bypassing input passthrough, playback, and recording - layout tweaks for extra small windows @@ -22,7 +32,7 @@ - fixed VST3 installation issue on windows (be sure to uninstall first, you may need to manually remove the C:\Program Files\Common Files\VST3\PaulXStretch.vst3) -**v1.5.0** (04-14-2022) +**v1.5.0** (2022-04-14) - UI layout redesign to adapt to different window sizes and changed look and feel. - Added iOS support for standalone and AUv3 diff --git a/README.md b/README.md index 6fdd633..4442a60 100644 --- a/README.md +++ b/README.md @@ -80,19 +80,16 @@ 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 file. Paul Nasca, Xenakios and Jesse Chappell all explicitly permitted the license exception clause. +exception. The full license text is in the LICENSE file. Paul Nasca, Xenakios and Jesse Chappell all explicitly permitted the license exception clause. The AAX plugin and the version distributed on the iOS App Store by Sonosaurus is not built with FFTW, and the JUCE commercial license applies there. 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. -My github forks of these that are referenced via `git-subrepo` in this repository are: - -> 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. - - - +Dependencies that are referenced via `git-subrepo` in this repository are: + - ```(deps/juce) https://github.com/essej/JUCE in the sono6good branch. ``` + - ```(deps/clap-juce-extensions) https://github.com/free-audio/clap-juce-extensions in the main branch.``` + - ```(deps/clap-juce-extensions/clap-libs/clap) https://github.com/free-audio/clap in the main branch.``` + - ```(deps/clap-juce-extensions/clap-libs/clap-helpers) https://github.com/free-audio/clap-helpers in the main branch.``` diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp index 99e22bf..a741b4c 100644 --- a/Source/PluginEditor.cpp +++ b/Source/PluginEditor.cpp @@ -76,12 +76,9 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau showSettings(true); }; - if (JUCEApplicationBase::isStandaloneApp()) - { - addAndMakeVisible(&m_render_button); - m_render_button.setButtonText("Render..."); - m_render_button.onClick = [this]() { showRenderDialog(); }; - } + addAndMakeVisible(&m_render_button); + m_render_button.setButtonText("Render..."); + m_render_button.onClick = [this]() { showRenderDialog(); }; m_rewind_button = std::make_unique("rewind", DrawableButton::ButtonStyle::ImageFitted); @@ -730,10 +727,8 @@ void PaulstretchpluginAudioProcessorEditor::resized() topbox.items.add(FlexItem(buttw, buttonrowheight, m_import_button).withMargin(1).withFlex(1).withMaxWidth(130)); topbox.items.add(FlexItem(buttw, buttonrowheight, m_settings_button).withMargin(1).withFlex(1).withMaxWidth(130)); - if (JUCEApplicationBase::isStandaloneApp()) - { - topbox.items.add(FlexItem(buttw, buttonrowheight, m_render_button).withMargin(1).withFlex(1).withMaxWidth(130)); - } + topbox.items.add(FlexItem(buttw, buttonrowheight, m_render_button).withMargin(1).withFlex(1).withMaxWidth(130)); + topbox.items.add(FlexItem(4, 4)); topbox.items.add(FlexItem(80, buttonrowheight, m_perfmeter).withMargin(1).withFlex(1).withMaxWidth(110).withMaxHeight(24).withAlignSelf(FlexItem::AlignSelf::center)); topbox.items.add(FlexItem(140, 26, m_info_label).withMargin(1).withFlex(2)); @@ -1298,6 +1293,37 @@ void PaulstretchpluginAudioProcessorEditor::toggleFileBrowser() } +void PaulstretchpluginAudioProcessorEditor::showPopTip(const String & message, int timeoutMs, Component * target, int maxwidth) +{ + popTip.reset(new BubbleMessageComponent()); + popTip->setAllowedPlacement(BubbleComponent::above); + + if (target) { + if (auto * parent = target->findParentComponentOfClass()) { + parent->addChildComponent (popTip.get()); + } else { + addChildComponent(popTip.get()); + } + } + else { + addChildComponent(popTip.get()); + } + + AttributedString text(message); + text.setJustification (Justification::centred); + text.setColour (findColour (TextButton::textColourOffId)); + text.setFont(Font(12)); + if (target) { + popTip->showAt(target, text, timeoutMs); + } + else { + Rectangle topbox(getWidth()/2 - maxwidth/2, 0, maxwidth, 2); + popTip->showAt(topbox, text, timeoutMs); + } + popTip->toFront(false); + //AccessibilityHandler::postAnnouncement(message, AccessibilityHandler::AnnouncementPriority::high); +} + void PaulstretchpluginAudioProcessorEditor::toggleOutputRecording() { if (processor.isRecordingToFile()) { @@ -1309,10 +1335,10 @@ void PaulstretchpluginAudioProcessorEditor::toggleOutputRecording() String filepath; #if (JUCE_IOS || JUCE_ANDROID) filepath = m_lastRecordedFile.getRelativePathFrom(File::getSpecialLocation (File::userDocumentsDirectory)); - //showPopTip(TRANS("Finished recording to ") + filepath, 4000, mRecordingButton.get(), 130); #else filepath = m_lastRecordedFile.getRelativePathFrom(File::getSpecialLocation (File::userHomeDirectory)); #endif + showPopTip(TRANS("Finished recording to ") + filepath, 4000, m_recordingButton.get(), 130); m_recordingButton->setTooltip(TRANS("Last recorded file: ") + filepath); @@ -1373,7 +1399,7 @@ void PaulstretchpluginAudioProcessorEditor::toggleOutputRecording() else { // show error starting record String lasterr = processor.getLastErrorMessage(); - //showPopTip(lasterr, 0, mRecordingButton.get()); + showPopTip(lasterr, 0, m_recordingButton.get()); } m_fileRecordingLabel->setText("", dontSendNotification); diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h index 753372a..667c606 100644 --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -564,6 +564,9 @@ private: void toggleOutputRecording(); + void showPopTip(const String & message, int timeoutMs, Component * target, int maxwidth=100); + + CustomLookAndFeel m_lookandfeel; PaulstretchpluginAudioProcessor& processor; @@ -639,6 +642,10 @@ private: std::unique_ptr tooltipWindow; + // keep this down here, so it gets destroyed early + std::unique_ptr popTip; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PaulstretchpluginAudioProcessorEditor) }; diff --git a/Source/RenderSettingsComponent.cpp b/Source/RenderSettingsComponent.cpp index 61e2c6d..eda2489 100644 --- a/Source/RenderSettingsComponent.cpp +++ b/Source/RenderSettingsComponent.cpp @@ -284,17 +284,22 @@ void RenderSettingsComponent::buttonClicked (Button* buttonThatWasClicked) else if (buttonThatWasClicked == &buttonSelectFile) { File lastexportfolder; // File(g_propsfile->getValue("last_export_file")).getParentDirectory(); - + Component * parent = nullptr; +#if JUCE_IOS + parent = JUCEApplication::isStandaloneApp() ? nullptr : getActiveEditor(); +#endif + m_filechooser = std::make_unique("Please select audio file to render...", lastexportfolder, - "*.wav"); + "*.wav", true, false, parent); m_filechooser->launchAsync(FileBrowserComponent::saveMode, [this](const FileChooser &chooser) { String newpath = chooser.getResult().getFullPathName(); #if JUCE_IOS - // not actually used here, but just in case for later newpath = chooser.getResult().getFileName(); #endif - outfileNameEditor.setText(newpath, dontSendNotification); + if (newpath.isNotEmpty()) { + outfileNameEditor.setText(newpath, dontSendNotification); + } if (newpath.isNotEmpty() && pendingRender) { buttonClicked(&buttonRender); }