| @@ -48,6 +48,7 @@ public: | |||
| PlayRangeEndCallback=[](AInputS*){}; | |||
| } | |||
| ~AInputS() {} | |||
| void setAudioBuffer(AudioBuffer<float>* buf, int samplerate, int len) | |||
| { | |||
| m_afreader = nullptr; | |||
| @@ -60,6 +61,7 @@ public: | |||
| m_loop_enabled = true; | |||
| m_crossfadebuf.setSize(info.nchannels, m_crossfadebuf.getNumSamples()); | |||
| m_cached_file_range = { 0,len }; | |||
| seek(m_activerange.getStart()); | |||
| updateXFadeCache(); | |||
| } | |||
| bool openAudioFile(File file) override | |||
| @@ -33,7 +33,7 @@ extern std::unique_ptr<PropertiesFile> g_propsfile; | |||
| Control::Control(AudioFormatManager* afm) : m_afm(afm), m_bufferingthread("stretchbufferingthread") | |||
| { | |||
| m_stretch_source = std::make_unique<MultiStretchAudioSource>(2,m_afm); | |||
| m_stretch_source = std::make_unique<StretchAudioSource>(2,m_afm); | |||
| wavinfo.samplerate=44100; | |||
| @@ -619,91 +619,3 @@ void Control::update_process_parameters() | |||
| //if (player) | |||
| // player->set_process_parameters(&ppar,&bbpar); | |||
| }; | |||
| AudioCallback::AudioCallback() : AudioIODeviceCallback(), | |||
| m_writethread("audio_out_record_thread") | |||
| { | |||
| } | |||
| void AudioCallback::audioDeviceAboutToStart(AudioIODevice * device) | |||
| { | |||
| m_debugcount = 0; | |||
| m_outpos = 0.0; | |||
| m_outsr = device->getCurrentSampleRate(); | |||
| if (m_aviscomponent) | |||
| m_aviscomponent->setNumChannels(m_numoutchans); | |||
| if (m_bufferingsource) | |||
| { | |||
| if (m_prebufferthread->isThreadRunning()==false) | |||
| m_prebufferthread->startThread(g_propsfile->getIntValue("prebufthreadpriority",5)); | |||
| int bufsize = std::max(512, device->getCurrentBufferSizeSamples()); | |||
| //Logger::writeToLog("Using buffer size " + String(bufsize)); | |||
| m_bufferingsource->prepareToPlay(bufsize, m_outsr); | |||
| } | |||
| m_playing = true; | |||
| //Logger::writeToLog("hw samplerate " + String(m_outsr)); | |||
| } | |||
| void AudioCallback::audioDeviceStopped() | |||
| { | |||
| m_writer = nullptr; | |||
| if (m_writethread.isThreadRunning() == true) | |||
| { | |||
| if (m_writethread.stopThread(1000) == false) | |||
| { | |||
| Logger::writeToLog("OUCH, live output recording thread didn't stop cleanly!"); | |||
| } | |||
| } | |||
| if (m_bufferingsource) | |||
| { | |||
| m_bufferingsource->releaseResources(); | |||
| if (m_prebufferthread->isThreadRunning() == true) | |||
| { | |||
| if (m_prebufferthread->stopThread(1000) == false) | |||
| Logger::writeToLog("OUCH, prebuffering thread did not stop cleanly!"); | |||
| } | |||
| } | |||
| m_playing = false; | |||
| } | |||
| void AudioCallback::audioDeviceIOCallback(const float ** /*inputChannelData*/, int, float ** outputChannelData, int numOutputChannels, int numSamples) | |||
| { | |||
| if (m_bufferingsource == nullptr) | |||
| return; | |||
| AudioBuffer<float> buf(outputChannelData, numOutputChannels, numSamples); | |||
| AudioSourceChannelInfo ainfo(buf); | |||
| m_bufferingsource->getNextAudioBlock(ainfo); | |||
| if (m_aviscomponent && m_aviscomponent->isVisible()) | |||
| { | |||
| m_aviscomponent->pushBuffer((const float**)outputChannelData, m_numoutchans, numSamples); | |||
| } | |||
| if (m_writer && m_is_recording == true) | |||
| { | |||
| m_writer->write((const float**)outputChannelData, numSamples); | |||
| } | |||
| m_outpos += (double)numSamples / m_outsr; | |||
| } | |||
| String AudioCallback::startRecording(File outfile) | |||
| { | |||
| WavAudioFormat wavformat; | |||
| auto outstream = outfile.createOutputStream(); | |||
| if (outstream == nullptr) | |||
| return "Could not create output stream"; | |||
| auto writer = wavformat.createWriterFor(outstream, m_outsr, m_numoutchans, 32, StringPairArray(), 0); | |||
| if (writer != nullptr) | |||
| { | |||
| if (m_writethread.isThreadRunning()==false) | |||
| m_writethread.startThread(); | |||
| m_writer = std::make_unique<AudioFormatWriter::ThreadedWriter>(writer, m_writethread, 65536); | |||
| m_is_recording = true; | |||
| return String(); | |||
| } | |||
| return "Could not create audio writer"; | |||
| } | |||
| void AudioCallback::setNumOutchans(int numchans) | |||
| { | |||
| m_numoutchans = jlimit(2, g_maxnumoutchans, numchans); | |||
| } | |||
| @@ -26,36 +26,6 @@ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| #include "../JuceLibraryCode/JuceHeader.h" | |||
| #include "../ps3_BufferingAudioSource.h" | |||
| class AudioCallback : public AudioIODeviceCallback | |||
| { | |||
| public: | |||
| AudioCallback(); | |||
| void audioDeviceAboutToStart(AudioIODevice* device) override; | |||
| void audioDeviceStopped() override; | |||
| void audioDeviceIOCallback (const float** inputChannelData, | |||
| int numInputChannels, | |||
| float** outputChannelData, | |||
| int numOutputChannels, | |||
| int numSamples) override; | |||
| String startRecording(File outfile); | |||
| std::atomic<bool> m_is_recording{ false }; | |||
| AudioVisualiserComponent* m_aviscomponent = nullptr; | |||
| std::unique_ptr<AudioFormatWriter::ThreadedWriter> m_writer; | |||
| TimeSliceThread m_writethread; | |||
| TimeSliceThread* m_prebufferthread = nullptr; | |||
| MyBufferingAudioSource* m_bufferingsource = nullptr; | |||
| MultiStretchAudioSource* m_sas = nullptr; | |||
| std::atomic<bool> m_playing{false}; | |||
| double m_outpos = 0.0; | |||
| void setNumOutchans(int numchans); | |||
| private: | |||
| std::mutex m_mutex; | |||
| int m_debugcount = 0; | |||
| int m_outsr = 44100; | |||
| int m_numoutchans = 2; | |||
| }; | |||
| class RenderInfo | |||
| { | |||
| public: | |||
| @@ -102,7 +72,7 @@ public: | |||
| void setFFTSize(double size); | |||
| int getFFTSize() { return m_fft_size_to_use; } | |||
| void setOnsetDetection(double x); | |||
| MultiStretchAudioSource* getStretchAudioSource() { return m_stretch_source.get(); } | |||
| StretchAudioSource* getStretchAudioSource() { return m_stretch_source.get(); } | |||
| void set_input_file(File filename, std::function<void(String)> cb);//return non empty String if the file cannot be opened | |||
| String get_input_filename(); | |||
| String get_stretch_info(Range<double> playrange); | |||
| @@ -169,7 +139,7 @@ private: | |||
| REALTYPE seek_pos; | |||
| AudioFormatManager* m_afm = nullptr; | |||
| TimeSliceThread m_bufferingthread; | |||
| std::unique_ptr<MultiStretchAudioSource> m_stretch_source; | |||
| std::unique_ptr<StretchAudioSource> m_stretch_source; | |||
| std::unique_ptr<MyBufferingAudioSource> m_buffering_source; | |||
| int m_prebuffer_amount = 1; | |||
| bool m_recreate_buffering_source = true; | |||
| @@ -123,6 +123,8 @@ void StretchAudioSource::setAudioBufferAsInputSource(AudioBuffer<float>* buf, in | |||
| m_seekpos = 0.0; | |||
| m_lastinpos = 0.0; | |||
| m_curfile = File(); | |||
| if (m_playrange.isEmpty()) | |||
| setPlayRange({ 0.0,1.0 }, true); | |||
| } | |||
| void StretchAudioSource::getNextAudioBlock(const AudioSourceChannelInfo & bufferToFill) | |||
| @@ -40,6 +40,7 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor (Pa | |||
| }; | |||
| m_wavecomponent.ShowFileCacheRange = true; | |||
| startTimer(1, 100); | |||
| m_wavecomponent.startTimer(100); | |||
| } | |||
| PaulstretchpluginAudioProcessorEditor::~PaulstretchpluginAudioProcessorEditor() | |||
| @@ -114,7 +114,17 @@ void PaulstretchpluginAudioProcessor::changeProgramName (int index, const String | |||
| void PaulstretchpluginAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock) | |||
| { | |||
| if (m_using_memory_buffer == true) | |||
| m_control->getStretchAudioSource()->setAudioBufferAsInputSource(&m_recbuffer, getSampleRate(), m_recbuffer.getNumSamples()); | |||
| { | |||
| int len = jlimit(100,m_recbuffer.getNumSamples(), m_rec_pos); | |||
| m_control->getStretchAudioSource()->setAudioBufferAsInputSource(&m_recbuffer, | |||
| getSampleRate(), | |||
| len); | |||
| auto ed = dynamic_cast<PaulstretchpluginAudioProcessorEditor*>(getActiveEditor()); | |||
| if (ed) | |||
| { | |||
| ed->setAudioBuffer(&m_recbuffer, getSampleRate(), len); | |||
| } | |||
| } | |||
| if (m_ready_to_play == false) | |||
| { | |||
| m_control->update_player_stretch(); | |||
| @@ -180,7 +190,8 @@ bool PaulstretchpluginAudioProcessor::isBusesLayoutSupported (const BusesLayout& | |||
| void PaulstretchpluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) | |||
| { | |||
| ScopedNoDenormals noDenormals; | |||
| std::lock_guard<std::mutex> locker(m_mutex); | |||
| ScopedNoDenormals noDenormals; | |||
| const int totalNumInputChannels = getTotalNumInputChannels(); | |||
| const int totalNumOutputChannels = getTotalNumOutputChannels(); | |||
| @@ -245,6 +256,7 @@ void PaulstretchpluginAudioProcessor::setStateInformation (const void* data, int | |||
| void PaulstretchpluginAudioProcessor::setRecordingEnabled(bool b) | |||
| { | |||
| std::lock_guard<std::mutex> locker(m_mutex); | |||
| if (b == true) | |||
| { | |||
| m_is_recording = true; | |||
| @@ -272,10 +284,11 @@ void PaulstretchpluginAudioProcessor::finishRecording(int lenrecording) | |||
| { | |||
| m_is_recording = false; | |||
| m_control->getStretchAudioSource()->setAudioBufferAsInputSource(&m_recbuffer, getSampleRate(), lenrecording); | |||
| m_control->getStretchAudioSource()->setPlayRange({ *getFloatParameter(5),*getFloatParameter(6) }, true); | |||
| auto ed = dynamic_cast<PaulstretchpluginAudioProcessorEditor*>(getActiveEditor()); | |||
| if (ed) | |||
| { | |||
| ed->setAudioBuffer(&m_recbuffer, getSampleRate(), m_rec_pos); | |||
| ed->setAudioBuffer(&m_recbuffer, getSampleRate(), lenrecording); | |||
| } | |||
| } | |||
| @@ -74,7 +74,7 @@ private: | |||
| int m_rec_pos = 0; | |||
| void finishRecording(int lenrecorded); | |||
| bool m_using_memory_buffer = true; | |||
| std::mutex m_mutex; | |||
| //============================================================================== | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PaulstretchpluginAudioProcessor) | |||
| }; | |||
| @@ -1,7 +1,7 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <JUCERPROJECT id="fn1Rg8" name="paulstretchplugin" displaySplashScreen="0" | |||
| reportAppUsage="1" splashScreenColour="Dark" projectType="audioplug" | |||
| reportAppUsage="0" splashScreenColour="Dark" projectType="audioplug" | |||
| version="1.0.0" bundleIdentifier="com.yourcompany.paulstretchplugin" | |||
| includeBinaryInAppConfig="1" cppLanguageStandard="latest" companyCopyright="" | |||
| buildVST="1" buildVST3="0" buildAU="1" buildAUv3="0" buildRTAS="0" | |||