diff --git a/Source/PS_Source/globals.h b/Source/PS_Source/globals.h index 3d50a73..a2bc9f2 100644 --- a/Source/PS_Source/globals.h +++ b/Source/PS_Source/globals.h @@ -294,3 +294,11 @@ inline bool is_in_range(T val, T start, T end) { return val >= start && val <= end; } + +inline void sanitizeTimeRange(double& t0, double& t1) +{ + if (t0 > t1) + std::swap(t0, t1); + if (t1 - t0 < 0.001) + t1 = t0 + 0.001; +} diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp index 01e4623..75c7332 100644 --- a/Source/PluginEditor.cpp +++ b/Source/PluginEditor.cpp @@ -358,6 +358,7 @@ void PaulstretchpluginAudioProcessorEditor::showSettingsMenu() menu.addItem(6, "Dump preset to clipboard", true, false); #endif menu.addItem(7, "Show technical info", true, processor.m_show_technical_info); + menu.addItem(8, "Offline render...", true, false); int r = menu.show(); if (r >= 200 && r < 210) { @@ -415,6 +416,10 @@ void PaulstretchpluginAudioProcessorEditor::showSettingsMenu() toggleBool(processor.m_show_technical_info); processor.m_propsfile->m_props_file->setValue("showtechnicalinfo", processor.m_show_technical_info); } + if (r == 8) + { + processor.offlineRender(File("C:\\MusicAudio\\sourcesamples\\paultesmaus\\plugin_offline_test\\out.wav")); + } } WaveformComponent::WaveformComponent(AudioFormatManager* afm, AudioThumbnail* thumb) diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 5761c6e..3ccec75 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -411,9 +411,60 @@ void PaulstretchpluginAudioProcessor::updateStretchParametersFromPluginParameter pars.tonal_vs_noise.preserve = *getFloatParameter(cpi_tonalvsnoisepreserve); } +String PaulstretchpluginAudioProcessor::offlineRender(File outputfile) +{ + File outputfiletouse = outputfile.getNonexistentSibling(); + int numoutchans = *getIntParameter(cpi_num_outchans); + auto ss = std::make_shared(numoutchans,m_afm); + int blocksize = 2048; + int64_t outlen = 10 * getSampleRateChecked(); + int64_t outcounter = 0; + ss->setFFTSize(m_fft_size_to_use); + ss->setAudioFile(m_current_file); + ProcessParameters renderpars; + updateStretchParametersFromPluginParameters(renderpars); + ss->setProcessParameters(&renderpars); + double t0 = *getFloatParameter(cpi_soundstart); + double t1 = *getFloatParameter(cpi_soundend); + sanitizeTimeRange(t0, t1); + ss->setRate(*getFloatParameter(cpi_stretchamount)); + ss->setPlayRange({ t0,t1 }, true); + ss->setLoopingEnabled(true); + ss->setNumOutChannels(numoutchans); + ss->setFFTWindowingType(1); + ss->setPreviewDry(true); + ss->setOnsetDetection(*getFloatParameter(cpi_onsetdetection)); + ss->setLoopXFadeLength(*getFloatParameter(cpi_loopxfadelen)); + ss->setFreezing(getParameter(cpi_freeze)); + ss->setPaused(getParameter(cpi_pause_enabled)); + ss->prepareToPlay(blocksize, getSampleRateChecked()); + AudioBuffer renderbuffer(numoutchans, blocksize); + + WavAudioFormat wavformat; + FileOutputStream* outstream = outputfiletouse.createOutputStream(); + if (outstream == nullptr) + return "Could not create output file"; + auto writer = wavformat.createWriterFor(outstream, getSampleRateChecked(), numoutchans, 32, StringPairArray(), 0); + if (writer == nullptr) + { + delete outstream; + return "Could not create WAV writer"; + } + AudioSourceChannelInfo asci(renderbuffer); + while (outcounter < outlen) + { + ss->setMainVolume(*getFloatParameter(cpi_main_volume)); + ss->getNextAudioBlock(asci); + writer->writeFromAudioSampleBuffer(renderbuffer,0,blocksize); + outcounter += blocksize; + } + delete writer; + return "Rendered OK"; +} + double PaulstretchpluginAudioProcessor::getSampleRateChecked() { - if (m_cur_sr < 1.0) + if (m_cur_sr < 1.0 || m_cur_sr>1000000.0) return 44100.0; return m_cur_sr; } @@ -503,14 +554,6 @@ void copyAudioBufferWrappingPosition(const AudioBuffer& src, AudioBuffer< } } -inline void sanitizeTimeRange(double& t0, double& t1) -{ - if (t0 > t1) - std::swap(t0, t1); - if (t1 - t0 < 0.001) - t1 = t0 + 0.001; -} - void PaulstretchpluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) { ScopedLock locker(m_cs); diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 8f72c71..9f66851 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -161,6 +161,7 @@ public: bool m_load_file_with_state = true; ValueTree getStateTree(bool ignoreoptions, bool ignorefile); void setStateFromTree(ValueTree tree); + String offlineRender(File outputfile); bool m_state_dirty = false; std::unique_ptr m_thumb; bool m_show_technical_info = false; @@ -207,6 +208,7 @@ private: void setParameters(const std::vector& pars); float m_cur_playrangeoffset = 0.0; void updateStretchParametersFromPluginParameters(ProcessParameters& pars); + //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PaulstretchpluginAudioProcessor) };