diff --git a/Source/PS_Source/StretchSource.cpp b/Source/PS_Source/StretchSource.cpp index fa53f6a..00184a3 100644 --- a/Source/PS_Source/StretchSource.cpp +++ b/Source/PS_Source/StretchSource.cpp @@ -58,7 +58,7 @@ std::vector StretchAudioSource::getSpectrumProcessOrder() void StretchAudioSource::setSpectrumProcessOrder(std::vector order) { - std::lock_guard locker(m_mutex); + ScopedLock locker(m_cs); m_specproc_order = order; for (int i = 0; i < m_stretchers.size(); ++i) { @@ -88,7 +88,7 @@ ValueTree StretchAudioSource::getStateTree() void StretchAudioSource::setStateTree(ValueTree state) { - std::lock_guard locker(m_mutex); + ScopedLock locker(m_cs); getFromTreeProperties(state, "pitch_shift", m_ppar.pitch_shift.cents, "octaves_minus2", m_ppar.octave.om2, "octaves_minus1", m_ppar.octave.om1, @@ -111,7 +111,7 @@ bool StretchAudioSource::isLoopingEnabled() void StretchAudioSource::setLoopingEnabled(bool b) { - std::lock_guard locker(m_mutex); + ScopedLock locker(m_cs); if (m_inputfile != nullptr) { m_inputfile->setLoopEnabled(b); @@ -120,37 +120,43 @@ void StretchAudioSource::setLoopingEnabled(bool b) void StretchAudioSource::setAudioBufferAsInputSource(AudioBuffer* buf, int sr, int len) { - std::lock_guard locker(m_mutex); + ScopedLock locker(m_cs); m_inputfile->setAudioBuffer(buf, sr, len); m_seekpos = 0.0; - + m_curfile = File(); if (m_playrange.isEmpty()) setPlayRange({ 0.0,1.0 }, true); + ++m_param_change_count; } void StretchAudioSource::setMainVolume(double decibels) { if (decibels == m_main_volume) return; - std::lock_guard locker(m_mutex); - m_main_volume = jlimit(-144.0, 12.0, decibels); - ++m_param_change_count; + if (m_cs.tryEnter()) + { + m_main_volume = jlimit(-144.0, 12.0, decibels); + ++m_param_change_count; + m_cs.exit(); + } } void StretchAudioSource::setLoopXFadeLength(double lenseconds) { if (lenseconds == m_loopxfadelen) return; - std::lock_guard locker(m_mutex); - m_loopxfadelen = jlimit(0.0, 1.0, lenseconds); - ++m_param_change_count; + if (m_cs.tryEnter()) + { + m_loopxfadelen = jlimit(0.0, 1.0, lenseconds); + ++m_param_change_count; + m_cs.exit(); + } } 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... - std::lock_guard locker(m_mutex); + ScopedLock locker(m_cs); if (m_stretchoutringbuf.available() > 0) m_output_has_begun = true; bool freezing = m_freezing; @@ -356,7 +362,7 @@ bool StretchAudioSource::isLooping() const String StretchAudioSource::setAudioFile(File file) { - std::lock_guard locker(m_mutex); + ScopedLock locker(m_cs); if (m_inputfile->openAudioFile(file)) { m_curfile = file; @@ -378,7 +384,7 @@ void StretchAudioSource::setNumOutChannels(int chans) void StretchAudioSource::initObjects() { - std::lock_guard locker(m_mutex); + ScopedLock locker(m_cs); m_inputfile->setActiveRange(m_playrange); m_inputfile->seek(m_seekpos); @@ -448,32 +454,32 @@ void StretchAudioSource::setRate(double rate) { if (rate == m_playrate) return; - std::lock_guard locker(m_mutex); - //if (rate != m_lastplayrate) + if (m_cs.tryEnter()) { - //m_output_counter = m_output_counter*rate; - //m_output_length = (2*m_process_fftsize)+m_inputfile->getActiveRangeFrames().getLength()*rate; - //Logger::writeToLog("new len " + String(m_output_length) + " new output pos " + String(m_output_counter)); m_playrate = rate; for (int i = 0; i < m_stretchers.size(); ++i) { m_stretchers[i]->set_rap((float)rate); } + ++m_param_change_count; + m_cs.exit(); } - ++m_param_change_count; } void StretchAudioSource::setProcessParameters(ProcessParameters * pars) { if (*pars == m_ppar) return; - std::lock_guard locker(m_mutex); - m_ppar = *pars; - for (int i = 0; i < m_stretchers.size(); ++i) + if (m_cs.tryEnter()) { - m_stretchers[i]->set_parameters(pars); + m_ppar = *pars; + for (int i = 0; i < m_stretchers.size(); ++i) + { + m_stretchers[i]->set_parameters(pars); + } + ++m_param_change_count; + m_cs.exit(); } - ++m_param_change_count; } const ProcessParameters& StretchAudioSource::getProcessParameters() @@ -485,7 +491,7 @@ void StretchAudioSource::setFFTWindowingType(int windowtype) { if (windowtype==m_fft_window_type) return; - std::lock_guard locker(m_mutex); + ScopedLock locker(m_cs); m_fft_window_type = windowtype; for (int i = 0; i < m_stretchers.size(); ++i) { @@ -498,7 +504,7 @@ void StretchAudioSource::setFFTSize(int size) jassert(size>0); if (m_xfadetask.state == 0 && (m_process_fftsize == 0 || size != m_process_fftsize)) { - std::lock_guard locker(m_mutex); + ScopedLock locker(m_cs); if (m_xfadetask.buffer.getNumChannels() < m_num_outchans) { m_xfadetask.buffer.setSize(m_num_outchans, m_xfadetask.buffer.getNumSamples()); @@ -523,10 +529,10 @@ void StretchAudioSource::setFFTSize(int size) void StretchAudioSource::seekPercent(double pos) { - std::lock_guard locker(m_mutex); + ScopedLock locker(m_cs); m_seekpos = pos; m_inputfile->seek(pos); - + ++m_param_change_count; } double StretchAudioSource::getOutputDurationSecondsForRange(Range range, int fftsize) @@ -539,31 +545,34 @@ double StretchAudioSource::getOutputDurationSecondsForRange(Range range, void StretchAudioSource::setOnsetDetection(double x) { - std::lock_guard locker(m_mutex); + ScopedLock locker(m_cs); m_onsetdetection = x; for (int i = 0; i < m_stretchers.size(); ++i) { m_stretchers[i]->set_onset_detection_sensitivity((float)x); } + ++m_param_change_count; } void StretchAudioSource::setPlayRange(Range playrange, bool isloop) { if (m_playrange.isEmpty() == false && playrange == m_playrange) return; - std::lock_guard locker(m_mutex); - if (playrange.isEmpty()) - m_playrange = { 0.0,1.0 }; - else - m_playrange = playrange; - m_stream_end_reached = false; - m_inputfile->setActiveRange(m_playrange); - m_inputfile->setLoopEnabled(isloop); - if (m_playrange.contains(m_seekpos)==false) - m_inputfile->seek(m_playrange.getStart()); - m_seekpos = m_playrange.getStart(); - ++m_param_change_count; - + if (m_cs.tryEnter()) + { + if (playrange.isEmpty()) + m_playrange = { 0.0,1.0 }; + else + m_playrange = playrange; + m_stream_end_reached = false; + m_inputfile->setActiveRange(m_playrange); + m_inputfile->setLoopEnabled(isloop); + if (m_playrange.contains(m_seekpos) == false) + m_inputfile->seek(m_playrange.getStart()); + m_seekpos = m_playrange.getStart(); + ++m_param_change_count; + m_cs.exit(); + } } bool StretchAudioSource::isLoopEnabled() diff --git a/Source/PS_Source/StretchSource.h b/Source/PS_Source/StretchSource.h index 6112632..3ffc413 100644 --- a/Source/PS_Source/StretchSource.h +++ b/Source/PS_Source/StretchSource.h @@ -128,7 +128,7 @@ private: int64_t m_maxloops = 0; std::unique_ptr m_resampler; std::vector m_resampler_outbuf; - std::recursive_mutex m_mutex; + CriticalSection m_cs; std::vector m_specproc_order; bool m_stop_play_requested = false; double m_freeze_pos = 0.0; diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp index b71d408..f612f0c 100644 --- a/Source/PluginEditor.cpp +++ b/Source/PluginEditor.cpp @@ -42,8 +42,8 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor (Pa addAndMakeVisible(&m_rec_enable); m_rec_enable.setButtonText("Capture"); attachCallback(m_rec_enable, [this]() { processor.setRecordingEnabled(m_rec_enable.getToggleState()); }); - addAndMakeVisible(&m_specvis); - setSize (700, 30+pars.size()*25+200); + //addAndMakeVisible(&m_specvis); + setSize (1000, 30+(pars.size()/2)*25+200); m_wavecomponent.TimeSelectionChangedCallback = [this](Range range, int which) { *processor.getFloatParameter(5) = range.getStart(); @@ -80,11 +80,13 @@ void PaulstretchpluginAudioProcessorEditor::resized() for (int i = 0; i < m_parcomps.size(); ++i) { - m_parcomps[i]->setBounds(1, 30 + i * 25, getWidth()-2, 24); + int gridx = i % 2; + int gridy = i / 2; + m_parcomps[i]->setBounds(1+gridx*(getWidth()/2), 30 + gridy * 25, getWidth()/2-2, 24); } int yoffs = m_parcomps.back()->getBottom() + 1; - //m_wavecomponent.setBounds(1, yoffs, getWidth()-2, getHeight()-1-yoffs); - m_specvis.setBounds(1, yoffs, getWidth() - 2, getHeight() - 1 - yoffs); + m_wavecomponent.setBounds(1, yoffs, getWidth()-2, getHeight()-1-yoffs); + //m_specvis.setBounds(1, yoffs, getWidth() - 2, getHeight() - 1 - yoffs); } void PaulstretchpluginAudioProcessorEditor::timerCallback(int id) @@ -114,8 +116,8 @@ void PaulstretchpluginAudioProcessorEditor::timerCallback(int id) } if (id == 3) { - m_specvis.setState(processor.getStretchSource()->getProcessParameters(), processor.getStretchSource()->getFFTSize() / 2, - processor.getSampleRate()); + //m_specvis.setState(processor.getStretchSource()->getProcessParameters(), processor.getStretchSource()->getFFTSize() / 2, + // processor.getSampleRate()); } } diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h index 4bb9e58..f98175d 100644 --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -237,6 +237,22 @@ private: bool m_lock_timesel_set = false; }; +class MyDynamicObject : public DynamicObject +{ +public: + bool hasMethod(const Identifier& methodName) const override + { + if (methodName == Identifier("setLabelBounds") || + methodName == Identifier("setComponentBounds")) + return true; + return false; + } + var invokeMethod(Identifier methodName, + const var::NativeFunctionArgs& args) override + { + return var(); + } +}; class PaulstretchpluginAudioProcessorEditor : public AudioProcessorEditor, public MultiTimer @@ -260,6 +276,8 @@ private: TextButton m_import_button; Label m_info_label; void chooseFile(); + JavascriptEngine m_js_engine; + MyDynamicObject m_js_object; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PaulstretchpluginAudioProcessorEditor) }; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 06357b6..eeeb282 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -98,7 +98,17 @@ PaulstretchpluginAudioProcessor::PaulstretchpluginAudioProcessor() addParameter(new AudioParameterFloat("compress0", "Compress", 0.0f, 1.0f, 0.0f)); // 9 addParameter(new AudioParameterFloat("loopxfadelen0", "Loop xfade length", 0.0f, 1.0f, 0.0f)); // 10 addParameter(new AudioParameterFloat("numharmonics0", "Num harmonics", 0.0f, 100.0f, 0.0f)); // 11 - addParameter(new AudioParameterFloat("harmonicsfreq0", "Harmonics base freq", 1.0f, 5000.0f, 100.0f)); // 12 + addParameter(new AudioParameterFloat("harmonicsfreq0", "Harmonics base freq", + NormalisableRange(1.0f, 5000.0f, 1.00f, 0.5), 128.0f)); // 12 + addParameter(new AudioParameterFloat("harmonicsbw0", "Harmonics bandwidth", 0.1f, 200.0f, 25.0f)); // 13 + addParameter(new AudioParameterBool("harmonicsgauss0", "Gaussian harmonics", false)); // 14 + addParameter(new AudioParameterFloat("octavemixm2_0", "2 octaves down level", 0.0f, 1.0f, 0.0f)); // 15 + addParameter(new AudioParameterFloat("octavemixm1_0", "Octave down level", 0.0f, 1.0f, 0.0f)); // 16 + addParameter(new AudioParameterFloat("octavemix0_0", "Normal pitch level", 0.0f, 1.0f, 1.0f)); // 17 + addParameter(new AudioParameterFloat("octavemix1_0", "1 octave up level", 0.0f, 1.0f, 0.0f)); // 18 + addParameter(new AudioParameterFloat("octavemix15_0", "1 octave and fifth up level", 0.0f, 1.0f, 0.0f)); // 19 + addParameter(new AudioParameterFloat("octavemix2_0", "2 octaves up level", 0.0f, 1.0f, 0.0f)); // 20 + } PaulstretchpluginAudioProcessor::~PaulstretchpluginAudioProcessor() @@ -216,7 +226,7 @@ void PaulstretchpluginAudioProcessor::startplay(Range playrange, int num void PaulstretchpluginAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock) { - std::lock_guard locker(m_mutex); + ScopedLock locker(m_cs); if (getNumOutputChannels() != m_cur_num_out_chans) m_ready_to_play = false; if (m_using_memory_buffer == true) @@ -291,7 +301,7 @@ void copyAudioBufferWrappingPosition(const AudioBuffer& src, AudioBuffer< void PaulstretchpluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) { - std::lock_guard locker(m_mutex); + ScopedLock locker(m_cs); ScopedNoDenormals noDenormals; const int totalNumInputChannels = getTotalNumInputChannels(); const int totalNumOutputChannels = getTotalNumOutputChannels(); @@ -316,24 +326,31 @@ void PaulstretchpluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, M m_stretch_source->setMainVolume(*getFloatParameter(0)); m_stretch_source->setRate(*getFloatParameter(1)); - setFFTSize(*getFloatParameter(2)); - m_ppar.pitch_shift.cents = *getFloatParameter(3) * 100.0; - m_ppar.freq_shift.Hz = *getFloatParameter(4); - m_ppar.spread.enabled = *getFloatParameter(8) > 0.0f; - m_ppar.spread.bandwidth = *getFloatParameter(8); - m_ppar.compressor.power = *getFloatParameter(9); - m_ppar.harmonics.enabled = *getFloatParameter(11)>=1.0; - m_ppar.harmonics.nharmonics = *getFloatParameter(11); - m_ppar.harmonics.freq = *getFloatParameter(12); - m_stretch_source->setLoopXFadeLength(*getFloatParameter(10)); - double t0 = *getFloatParameter(5); - double t1 = *getFloatParameter(6); + setFFTSize(*getFloatParameter(cpi_fftsize)); + m_ppar.pitch_shift.cents = *getFloatParameter(cpi_pitchshift) * 100.0; + m_ppar.freq_shift.Hz = *getFloatParameter(cpi_frequencyshift); + m_ppar.spread.enabled = *getFloatParameter(cpi_spreadamount) > 0.0f; + m_ppar.spread.bandwidth = *getFloatParameter(cpi_spreadamount); + m_ppar.compressor.power = *getFloatParameter(cpi_compress); + m_ppar.harmonics.enabled = *getFloatParameter(cpi_numharmonics)>=1.0; + m_ppar.harmonics.nharmonics = *getFloatParameter(cpi_numharmonics); + m_ppar.harmonics.freq = *getFloatParameter(cpi_harmonicsfreq); + m_ppar.octave.om2 = *getFloatParameter(cpi_octavesm2); + m_ppar.octave.om1 = *getFloatParameter(cpi_octavesm1); + m_ppar.octave.o0 = *getFloatParameter(cpi_octaves0); + m_ppar.octave.o1 = *getFloatParameter(cpi_octaves1); + m_ppar.octave.o15 = *getFloatParameter(cpi_octaves15); + m_ppar.octave.o2 = *getFloatParameter(cpi_octaves2); + m_ppar.octave.enabled = true; + m_stretch_source->setLoopXFadeLength(*getFloatParameter(cpi_loopxfadelen)); + double t0 = *getFloatParameter(cpi_soundstart); + double t1 = *getFloatParameter(cpi_soundend); if (t0 > t1) std::swap(t0, t1); if (t1 - t0 < 0.001) t1 = t0 + 0.001; m_stretch_source->setPlayRange({ t0,t1 }, true); - m_stretch_source->setFreezing(getParameter(7)); + m_stretch_source->setFreezing(getParameter(cpi_freeze)); m_stretch_source->setProcessParameters(&m_ppar); AudioSourceChannelInfo aif(buffer); @@ -377,7 +394,7 @@ void PaulstretchpluginAudioProcessor::setStateInformation (const void* data, int if (tree.isValid()) { { - std::lock_guard locker(m_mutex); + ScopedLock locker(m_cs); for (int i = 0; i < getNumParameters(); ++i) { auto par = getFloatParameter(i); @@ -399,7 +416,7 @@ void PaulstretchpluginAudioProcessor::setStateInformation (const void* data, int void PaulstretchpluginAudioProcessor::setRecordingEnabled(bool b) { - std::lock_guard locker(m_mutex); + ScopedLock locker(m_cs); int lenbufframes = getSampleRate()*m_max_reclen; if (b == true) { @@ -445,7 +462,7 @@ String PaulstretchpluginAudioProcessor::setAudioFile(File f) //MessageManager::callAsync([cb, file]() { cb("Too high bit depth in file " + file.getFullPathName()); }); return "Too high bit depth in file " + f.getFullPathName(); } - std::lock_guard locker(m_mutex); + ScopedLock locker(m_cs); m_stretch_source->setAudioFile(f); m_current_file = f; m_using_memory_buffer = false; diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 25094d6..8198363 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -15,6 +15,31 @@ class MyThumbCache; +const int cpi_main_volume = 0; +const int cpi_stretchamount = 1; +const int cpi_fftsize = 2; +const int cpi_pitchshift = 3; +const int cpi_frequencyshift = 4; +const int cpi_soundstart = 5; +const int cpi_soundend = 6; +const int cpi_freeze = 7; +const int cpi_spreadamount = 8; +const int cpi_compress = 9; +const int cpi_loopxfadelen = 10; +const int cpi_numharmonics = 11; +const int cpi_harmonicsfreq = 12; +const int cpi_harmonicsbw = 13; +const int cpi_harmonicsgauss = 14; +const int cpi_octavesm2 = 15; +const int cpi_octavesm1 = 16; +const int cpi_octaves0 = 17; +const int cpi_octaves1 = 18; +const int cpi_octaves15 = 19; +const int cpi_octaves2 = 20; +const int cpi_tonalvsnoisebw = 21; +const int cpi_tonalvsnoisepreserve = 22; +const int cpi_filter_low = 23; +const int cpi_filter_high = 24; class PaulstretchpluginAudioProcessor : public AudioProcessor { @@ -79,7 +104,7 @@ private: void finishRecording(int lenrecorded); bool m_using_memory_buffer = true; int m_cur_num_out_chans = 2; - std::mutex m_mutex; + CriticalSection m_cs; File m_current_file;