diff --git a/Source/PS_Source/Input/AInputS.h b/Source/PS_Source/Input/AInputS.h index a049fd5..4c5b5c1 100644 --- a/Source/PS_Source/Input/AInputS.h +++ b/Source/PS_Source/Input/AInputS.h @@ -48,14 +48,27 @@ public: PlayRangeEndCallback=[](AInputS*){}; } ~AInputS() {} - + void setAudioBuffer(AudioBuffer* buf, int samplerate, int len) + { + m_afreader = nullptr; + m_using_memory_buffer = true; + m_readbuf = *buf; + info.nchannels = buf->getNumChannels(); + info.nsamples = len; + info.samplerate = samplerate; + m_currentsample = 0; + m_crossfadebuf.setSize(info.nchannels, m_crossfadebuf.getNumSamples()); + m_cached_file_range = { 0,len }; + updateXFadeCache(); + } bool openAudioFile(File file) override { m_silenceoutputted = 0; AudioFormatReader* reader = m_manager->createReaderFor(file); if (reader) { - m_afreader = std::unique_ptr(reader); + m_using_memory_buffer = false; + m_afreader = std::unique_ptr(reader); m_currentsample = 0; info.samplerate = (int)m_afreader->sampleRate; info.nchannels = m_afreader->numChannels; @@ -80,9 +93,12 @@ public: } int readNextBlock(AudioBuffer& abuf, int nsmps, int numchans) override { - if (m_afreader == nullptr) + if (m_afreader == nullptr && m_using_memory_buffer == false) return 0; - int inchans = m_afreader->numChannels; + int inchans = 0; + if (m_afreader) + inchans = m_afreader->numChannels; + else inchans = m_readbuf.getNumChannels(); int64_t subsect_t0 = (int64_t)(m_activerange.getStart()*info.nsamples); int64_t subsect_t1 = (int64_t)(m_activerange.getEnd()*info.nsamples); int64_t subsectlen = subsect_t1 - subsect_t0; @@ -130,7 +146,7 @@ public: for (int i = 0; i < nsmps; ++i) { - if (m_afreader->numChannels == 1 && numchans > 0) + if (inchans == 1 && numchans > 0) { float sig = getCrossFadedSampleLambda(m_currentsample, 0, subsect_t0, subsect_t1, xfadelen); for (int j = 0; j < numchans; ++j) @@ -138,7 +154,7 @@ public: smps[j][i] = sig; } } - else if (m_afreader->numChannels > 1 && numchans > 1) + else if (inchans > 1 && numchans > 1) { for (int j = 0; j < numchans; ++j) { @@ -172,6 +188,17 @@ public: } void seek(double pos) override //0=start,1.0=end { + if (m_using_memory_buffer == true) + { + jassert(m_readbuf.getNumSamples() > 0 && m_afreader==nullptr); + m_loopcount = 0; + m_silenceoutputted = 0; + m_cache_misses = 0; + m_currentsample = (int64_t)(pos*m_readbuf.getNumSamples()); + m_currentsample = jlimit(0, m_readbuf.getNumSamples(), m_currentsample); + m_cached_file_range = { 0,m_readbuf.getNumSamples() }; + return; + } if (m_afreader==nullptr) return; m_loopcount = 0; @@ -199,8 +226,11 @@ public: { if (m_xfadelen>m_crossfadebuf.getNumSamples()) m_crossfadebuf.setSize(info.nchannels,m_xfadelen); - m_afreader->read(&m_crossfadebuf, 0, m_xfadelen, (int64_t)(m_activerange.getStart()*info.nsamples), true, true); - m_cached_crossfade_range = + if (m_afreader != nullptr && m_using_memory_buffer == false) + m_afreader->read(&m_crossfadebuf, 0, m_xfadelen, (int64_t)(m_activerange.getStart()*info.nsamples), true, true); + if (m_afreader == nullptr && m_using_memory_buffer == true) + m_crossfadebuf.copyFrom(0, 0, m_readbuf, 0, (int64_t)(m_activerange.getStart()*info.nsamples), m_xfadelen); + m_cached_crossfade_range = Range((int64_t)(m_activerange.getStart()*info.nsamples),(int64_t)(m_activerange.getStart()*info.nsamples+m_xfadelen)); } void setActiveRange(Range rng) override @@ -243,6 +273,7 @@ public: } bool isReversed() { return m_reverseplay; } int64_t getLoopCount() { return m_loopcount; } + private: std::function PlayRangeEndCallback; std::unique_ptr m_afreader; @@ -256,5 +287,6 @@ private: int m_xfadelen = 0; bool m_reverseplay = false; int64_t m_loopcount = 0; + bool m_using_memory_buffer = false; AudioFormatManager* m_manager = nullptr; }; diff --git a/Source/PS_Source/StretchSource.cpp b/Source/PS_Source/StretchSource.cpp index 4b1906c..afcca2b 100644 --- a/Source/PS_Source/StretchSource.cpp +++ b/Source/PS_Source/StretchSource.cpp @@ -116,6 +116,14 @@ void StretchAudioSource::setLoopingEnabled(bool b) } } +void StretchAudioSource::setAudioBufferAsInputSource(AudioBuffer* buf, int sr, int len) +{ + std::lock_guard locker(m_mutex); + m_inputfile->setAudioBuffer(buf, sr, len); + m_seekpos = 0.0; + m_lastinpos = 0.0; +} + void StretchAudioSource::getNextAudioBlock(const AudioSourceChannelInfo & bufferToFill) { // for realtime play, this is assumed to be used with BufferingAudioSource, so mutex locking should not be too bad... @@ -489,6 +497,12 @@ std::pair, Range> MultiStretchAudioSource::getFileCachedRa return getActiveStretchSource()->getFileCachedRangesNormalized(); } +void MultiStretchAudioSource::setAudioBufferAsInputSource(AudioBuffer* buf, int sr, int len) +{ + m_stretchsources[0]->setAudioBufferAsInputSource(buf, sr, len); + m_stretchsources[1]->setAudioBufferAsInputSource(buf, sr, len); +} + StretchAudioSource * MultiStretchAudioSource::getActiveStretchSource() const { return m_stretchsources[0].get(); diff --git a/Source/PS_Source/StretchSource.h b/Source/PS_Source/StretchSource.h index cfee13d..309f54f 100644 --- a/Source/PS_Source/StretchSource.h +++ b/Source/PS_Source/StretchSource.h @@ -90,6 +90,7 @@ public: bool isLoopingEnabled(); void setLoopingEnabled(bool b); void setMaxLoops(int64_t numloops) { m_maxloops = numloops; } + void setAudioBufferAsInputSource(AudioBuffer* buf, int sr, int len); private: CircularBuffer m_stretchoutringbuf{ 1024 * 1024 }; AudioBuffer m_file_inbuf; @@ -187,6 +188,7 @@ public: Value val_XFadeLen; //ValueTree getStateTree(); //void setStateTree(ValueTree state); + void setAudioBufferAsInputSource(AudioBuffer* buf, int sr, int len); private: std::vector> m_stretchsources; bool m_is_in_switch{ false }; diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp index 6f5c650..afeb59b 100644 --- a/Source/PluginEditor.cpp +++ b/Source/PluginEditor.cpp @@ -16,6 +16,7 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor (PaulstretchpluginAudioProcessor& p) : AudioProcessorEditor (&p), processor (p) { + addAndMakeVisible(&m_info_label); const auto& pars = processor.getParameters(); for (int i=0;iupdateComponent(); + if (processor.isRecordingEnabled() != m_rec_enable.getToggleState()) + m_rec_enable.setToggleState(processor.isRecordingEnabled(), dontSendNotification); + m_info_label.setText(String(processor.getRecordingPositionPercent()*100.0, 1),dontSendNotification); } } diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h index bd43ec1..6246d14 100644 --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -85,5 +85,6 @@ private: PaulstretchpluginAudioProcessor& processor; std::vector> m_parcomps; ToggleButton m_rec_enable; + Label m_info_label; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PaulstretchpluginAudioProcessorEditor) }; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index a2c2501..0e2ea59 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -167,11 +167,17 @@ void PaulstretchpluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, M return; if (m_is_recording == true) { + if (m_rec_pos + buffer.getNumSamples() < m_recbuffer.getNumSamples()) + { + m_recbuffer.copyFrom(0, m_rec_pos, buffer, 0, 0, buffer.getNumSamples()); + m_recbuffer.copyFrom(1, m_rec_pos, buffer, 1, 0, buffer.getNumSamples()); + } m_rec_pos += buffer.getNumSamples(); if (m_rec_pos >= m_max_reclen * getSampleRate()) { m_is_recording = false; - // Set record buffer as strech source... + m_control->getStretchAudioSource()->setAudioBufferAsInputSource(&m_recbuffer, getSampleRate(), + m_max_reclen*getSampleRate()); } return; } @@ -220,15 +226,24 @@ void PaulstretchpluginAudioProcessor::setRecordingEnabled(bool b) if (b == true) { m_is_recording = true; - m_recbuffer.setSize(2, m_max_reclen*getSampleRate()); + m_recbuffer.setSize(2, m_max_reclen*getSampleRate()+4096); + m_recbuffer.clear(); m_rec_pos = 0; } else { m_is_recording = false; + m_control->getStretchAudioSource()->setAudioBufferAsInputSource(&m_recbuffer, getSampleRate(), m_rec_pos); } } +double PaulstretchpluginAudioProcessor::getRecordingPositionPercent() +{ + if (m_is_recording==false) + return 0.0; + return 1.0 / m_recbuffer.getNumSamples()*m_rec_pos; +} + //============================================================================== // This creates new instances of the plugin.. AudioProcessor* JUCE_CALLTYPE createPluginFilter() diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 152abfd..fa4e0f6 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -60,13 +60,15 @@ public: return dynamic_cast(getParameters()[index]); } void setRecordingEnabled(bool b); + bool isRecordingEnabled() { return m_is_recording; } + double getRecordingPositionPercent(); private: std::unique_ptr m_control; std::unique_ptr m_afm; bool m_ready_to_play = false; AudioBuffer m_recbuffer; double m_max_reclen = 10.0; - bool m_is_recording = true; + bool m_is_recording = false; int m_rec_pos = 0; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PaulstretchpluginAudioProcessor)