2022-04-22 03:04:30 +00:00
// SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
// Copyright (C) 2017 Xenakios
// Copyright (C) 2020 Jesse Chappell
2017-11-13 15:06:08 +00:00
# include "PluginProcessor.h"
# include "PluginEditor.h"
2017-11-16 17:45:40 +00:00
# include <set>
2018-02-26 22:32:33 +00:00
# include <thread>
2017-11-16 17:45:40 +00:00
2022-04-14 20:31:54 +00:00
# include "CrossPlatformUtils.h"
2022-04-13 17:48:09 +00:00
2017-11-25 19:25:46 +00:00
# ifdef WIN32
2017-11-15 15:52:47 +00:00
# undef min
# undef max
2017-11-25 19:25:46 +00:00
# endif
2017-11-13 15:06:08 +00:00
2017-11-20 22:39:07 +00:00
int get_optimized_updown ( int n , bool up ) {
int orig_n = n ;
while ( true ) {
n = orig_n ;
2022-04-26 21:58:45 +00:00
# if PS_USE_VDSP_FFT
2022-04-12 22:47:43 +00:00
// only powers of two allowed if using VDSP FFT
2022-04-26 21:58:45 +00:00
# elif PS_USE_PFFFT
// only powers of two allowed if using pffft
# else
2022-04-12 22:47:43 +00:00
while ( ! ( n % 11 ) ) n / = 11 ;
2017-11-20 22:39:07 +00:00
while ( ! ( n % 7 ) ) n / = 7 ;
while ( ! ( n % 5 ) ) n / = 5 ;
while ( ! ( n % 3 ) ) n / = 3 ;
2022-04-12 22:47:43 +00:00
# endif
while ( ! ( n % 2 ) ) n / = 2 ;
2017-11-20 22:39:07 +00:00
if ( n < 2 ) break ;
if ( up ) orig_n + + ;
else orig_n - - ;
if ( orig_n < 4 ) return 4 ;
} ;
return orig_n ;
} ;
int optimizebufsize ( int n ) {
int n1 = get_optimized_updown ( n , false ) ;
int n2 = get_optimized_updown ( n , true ) ;
if ( ( n - n1 ) < ( n2 - n ) ) return n1 ;
else return n2 ;
} ;
2018-02-01 18:09:12 +00:00
inline AudioParameterFloat * make_floatpar ( String id , String name , float minv , float maxv , float defv , float step , float skew )
{
return new AudioParameterFloat ( id , name , NormalisableRange < float > ( minv , maxv , step , skew ) , defv ) ;
}
2022-04-22 03:04:30 +00:00
# if JUCE_IOS
# define ALTBUS_ACTIVE true
# else
# define ALTBUS_ACTIVE false
# endif
2022-04-24 22:11:57 +00:00
PaulstretchpluginAudioProcessor : : BusesProperties PaulstretchpluginAudioProcessor : : getDefaultLayout ( )
{
auto props = PaulstretchpluginAudioProcessor : : BusesProperties ( ) ;
auto plugtype = PluginHostType : : getPluginLoadedAs ( ) ;
// common to all
props = props . withInput ( " Main In " , AudioChannelSet : : stereo ( ) , true )
. withOutput ( " Main Out " , AudioChannelSet : : stereo ( ) , true ) ;
// extra inputs
if ( plugtype = = AudioProcessor : : wrapperType_AAX ) {
// only one sidechain mono allowed, doesn't even work anyway
props = props . withInput ( " Aux 1 In " , AudioChannelSet : : mono ( ) , ALTBUS_ACTIVE ) ;
}
else {
// throw in some input sidechains
props = props . withInput ( " Aux 1 In " , AudioChannelSet : : stereo ( ) , ALTBUS_ACTIVE )
. withInput ( " Aux 2 In " , AudioChannelSet : : stereo ( ) , ALTBUS_ACTIVE )
. withInput ( " Aux 3 In " , AudioChannelSet : : stereo ( ) , ALTBUS_ACTIVE )
. withInput ( " Aux 4 In " , AudioChannelSet : : stereo ( ) , ALTBUS_ACTIVE )
. withInput ( " Aux 5 In " , AudioChannelSet : : stereo ( ) , ALTBUS_ACTIVE )
. withInput ( " Aux 6 In " , AudioChannelSet : : stereo ( ) , ALTBUS_ACTIVE )
. withInput ( " Aux 7 In " , AudioChannelSet : : stereo ( ) , ALTBUS_ACTIVE )
. withInput ( " Aux 8 In " , AudioChannelSet : : stereo ( ) , ALTBUS_ACTIVE ) ;
}
// outputs
props = props . withOutput ( " Aux 1 Out " , AudioChannelSet : : stereo ( ) , ALTBUS_ACTIVE )
. withOutput ( " Aux 2 Out " , AudioChannelSet : : stereo ( ) , ALTBUS_ACTIVE )
. withOutput ( " Aux 3 Out " , AudioChannelSet : : stereo ( ) , ALTBUS_ACTIVE )
. withOutput ( " Aux 4 Out " , AudioChannelSet : : stereo ( ) , ALTBUS_ACTIVE )
. withOutput ( " Aux 5 Out " , AudioChannelSet : : stereo ( ) , ALTBUS_ACTIVE )
. withOutput ( " Aux 6 Out " , AudioChannelSet : : stereo ( ) , ALTBUS_ACTIVE )
. withOutput ( " Aux 7 Out " , AudioChannelSet : : stereo ( ) , ALTBUS_ACTIVE )
. withOutput ( " Aux 8 Out " , AudioChannelSet : : stereo ( ) , ALTBUS_ACTIVE ) ;
return props ;
}
2017-11-13 15:06:08 +00:00
//==============================================================================
2019-03-29 14:37:36 +00:00
PaulstretchpluginAudioProcessor : : PaulstretchpluginAudioProcessor ( bool is_stand_alone_offline )
2022-04-24 22:11:57 +00:00
: AudioProcessor ( getDefaultLayout ( ) ) ,
2022-04-11 17:23:10 +00:00
m_bufferingthread ( " pspluginprebufferthread " ) , m_is_stand_alone_offline ( is_stand_alone_offline )
2017-11-13 15:06:08 +00:00
{
2022-04-22 03:04:30 +00:00
DBG ( " Attempt proc const " ) ;
2019-01-21 14:10:17 +00:00
m_filechoose_callback = [ this ] ( const FileChooser & chooser )
{
2022-04-13 17:48:09 +00:00
URL resu = chooser . getURLResult ( ) ;
//String pathname = resu.getFullPathName();
//if (pathname.startsWith("/localhost"))
//{
// pathname = pathname.substring(10);
// resu = File(pathname);
//}
if ( ! resu . isEmpty ( ) ) {
m_propsfile - > m_props_file - > setValue ( " importfilefolder " , resu . getLocalFile ( ) . getParentDirectory ( ) . getFullPathName ( ) ) ;
String loaderr = setAudioFile ( resu ) ;
if ( auto ed = dynamic_cast < PaulstretchpluginAudioProcessorEditor * > ( getActiveEditor ( ) ) ; ed ! = nullptr )
{
ed - > m_last_err = loaderr ;
}
}
2019-01-21 14:10:17 +00:00
} ;
2018-02-09 13:34:39 +00:00
m_playposinfo . timeInSeconds = 0.0 ;
2018-02-27 00:33:41 +00:00
m_free_filter_envelope = std : : make_shared < breakpoint_envelope > ( ) ;
2018-02-27 22:32:18 +00:00
m_free_filter_envelope - > SetName ( " Free filter " ) ;
2018-02-27 13:21:36 +00:00
m_free_filter_envelope - > AddNode ( { 0.0 , 0.75 } ) ;
m_free_filter_envelope - > AddNode ( { 1.0 , 0.75 } ) ;
m_free_filter_envelope - > set_reset_nodes ( m_free_filter_envelope - > get_all_nodes ( ) ) ;
2022-04-22 03:04:30 +00:00
DBG ( " recbuffer " ) ;
2022-04-15 23:13:55 +00:00
m_recbuffer . setSize ( 2 , 48000 ) ;
2017-11-13 22:50:12 +00:00
m_recbuffer . clear ( ) ;
2017-11-23 23:44:30 +00:00
if ( m_afm - > getNumKnownFormats ( ) = = 0 )
m_afm - > registerBasicFormats ( ) ;
2019-03-29 14:37:36 +00:00
if ( m_is_stand_alone_offline = = false )
m_thumb = std : : make_unique < AudioThumbnail > ( 512 , * m_afm , * m_thumbcache ) ;
2022-04-22 03:04:30 +00:00
DBG ( " making bool pars " ) ;
2018-04-26 18:45:37 +00:00
m_sm_enab_pars [ 0 ] = new AudioParameterBool ( " enab_specmodule0 " , " Enable harmonics " , false ) ;
m_sm_enab_pars [ 1 ] = new AudioParameterBool ( " enab_specmodule1 " , " Enable tonal vs noise " , false ) ;
m_sm_enab_pars [ 2 ] = new AudioParameterBool ( " enab_specmodule2 " , " Enable frequency shift " , true ) ;
m_sm_enab_pars [ 3 ] = new AudioParameterBool ( " enab_specmodule3 " , " Enable pitch shift " , true ) ;
m_sm_enab_pars [ 4 ] = new AudioParameterBool ( " enab_specmodule4 " , " Enable ratios " , false ) ;
m_sm_enab_pars [ 5 ] = new AudioParameterBool ( " enab_specmodule5 " , " Enable spread " , false ) ;
2022-04-28 02:52:40 +00:00
m_sm_enab_pars [ 6 ] = new AudioParameterBool ( " enab_specmodule6 " , " Enable filter " , false ) ;
m_sm_enab_pars [ 7 ] = new AudioParameterBool ( " enab_specmodule7 " , " Enable free filter " , false ) ;
2018-04-26 18:45:37 +00:00
m_sm_enab_pars [ 8 ] = new AudioParameterBool ( " enab_specmodule8 " , " Enable compressor " , false ) ;
2018-04-26 20:07:08 +00:00
2022-04-22 03:04:30 +00:00
DBG ( " making stretch source " ) ;
2018-03-16 16:40:59 +00:00
2018-03-09 16:05:33 +00:00
m_stretch_source = std : : make_unique < StretchAudioSource > ( 2 , m_afm , m_sm_enab_pars ) ;
2017-11-20 22:39:07 +00:00
m_stretch_source - > setOnsetDetection ( 0.0 ) ;
m_stretch_source - > setLoopingEnabled ( true ) ;
2017-11-28 18:46:04 +00:00
m_stretch_source - > setFFTWindowingType ( 1 ) ;
2022-04-22 03:04:30 +00:00
DBG ( " About to add parameters " ) ;
2018-02-01 18:09:12 +00:00
addParameter ( make_floatpar ( " mainvolume0 " , " Main volume " , - 24.0 , 12.0 , - 3.0 , 0.1 , 1.0 ) ) ;
addParameter ( make_floatpar ( " stretchamount0 " , " Stretch amount " , 0.1 , 1024.0 , 2.0 , 0.1 , 0.25 ) ) ;
addParameter ( make_floatpar ( " fftsize0 " , " FFT size " , 0.0 , 1.0 , 0.7 , 0.01 , 1.0 ) ) ;
addParameter ( make_floatpar ( " pitchshift0 " , " Pitch shift " , - 24.0f , 24.0f , 0.0f , 0.1 , 1.0 ) ) ; // 3
addParameter ( make_floatpar ( " freqshift0 " , " Frequency shift " , - 1000.0f , 1000.0f , 0.0f , 1.0 , 1.0 ) ) ; // 4
addParameter ( make_floatpar ( " playrange_start0 " , " Sound start " , 0.0f , 1.0f , 0.0f , 0.0001 , 1.0 ) ) ; // 5
addParameter ( make_floatpar ( " playrange_end0 " , " Sound end " , 0.0f , 1.0f , 1.0f , 0.0001 , 1.0 ) ) ; // 6
2017-11-16 17:45:40 +00:00
addParameter ( new AudioParameterBool ( " freeze0 " , " Freeze " , false ) ) ; // 7
2018-02-01 18:09:12 +00:00
addParameter ( make_floatpar ( " spread0 " , " Frequency spread " , 0.0f , 1.0f , 0.0f , 0.001 , 1.0 ) ) ; // 8
addParameter ( make_floatpar ( " compress0 " , " Compress " , 0.0f , 1.0f , 0.0f , 0.001 , 1.0 ) ) ; // 9
addParameter ( make_floatpar ( " loopxfadelen0 " , " Loop xfade length " , 0.0f , 1.0f , 0.01f , 0.001 , 1.0 ) ) ; // 10
2018-01-30 16:56:00 +00:00
addParameter ( new AudioParameterInt ( " numharmonics0 " , " Num harmonics " , 1 , 100 , 10 ) ) ; // 11
2018-02-01 18:09:12 +00:00
addParameter ( make_floatpar ( " harmonicsfreq0 " , " Harmonics base freq " , 1.0 , 5000.0 , 128.0 , 0.1 , 0.5 ) ) ;
addParameter ( make_floatpar ( " harmonicsbw0 " , " Harmonics bandwidth " , 0.1f , 200.0f , 25.0f , 0.01 , 1.0 ) ) ; // 13
2017-12-12 17:14:43 +00:00
addParameter ( new AudioParameterBool ( " harmonicsgauss0 " , " Gaussian harmonics " , false ) ) ; // 14
2018-02-01 18:09:12 +00:00
addParameter ( make_floatpar ( " octavemixm2_0 " , " 2 octaves down level " , 0.0f , 1.0f , 0.0f , 0.001 , 1.0 ) ) ; // 15
addParameter ( make_floatpar ( " octavemixm1_0 " , " Octave down level " , 0.0f , 1.0f , 0.0f , 0.001 , 1.0 ) ) ; // 16
addParameter ( make_floatpar ( " octavemix0_0 " , " Normal pitch level " , 0.0f , 1.0f , 1.0f , 0.001 , 1.0 ) ) ; // 17
addParameter ( make_floatpar ( " octavemix1_0 " , " 1 octave up level " , 0.0f , 1.0f , 0.0f , 0.001 , 1.0 ) ) ; // 18
addParameter ( make_floatpar ( " octavemix15_0 " , " 1 octave and fifth up level " , 0.0f , 1.0f , 0.0f , 0.001 , 1.0 ) ) ; // 19
addParameter ( make_floatpar ( " octavemix2_0 " , " 2 octaves up level " , 0.0f , 1.0f , 0.0f , 0.001 , 1.0 ) ) ; // 20
addParameter ( make_floatpar ( " tonalvsnoisebw_0 " , " Tonal vs Noise BW " , 0.74f , 1.0f , 0.74f , 0.001 , 1.0 ) ) ; // 21
addParameter ( make_floatpar ( " tonalvsnoisepreserve_0 " , " Tonal vs Noise preserve " , - 1.0f , 1.0f , 0.5f , 0.001 , 1.0 ) ) ; // 22
2017-12-15 15:43:59 +00:00
auto filt_convertFrom0To1Func = [ ] ( float rangemin , float rangemax , float value )
{
if ( value < 0.5f )
return jmap < float > ( value , 0.0f , 0.5f , 20.0f , 1000.0f ) ;
return jmap < float > ( value , 0.5f , 1.0f , 1000.0f , 20000.0f ) ;
} ;
auto filt_convertTo0To1Func = [ ] ( float rangemin , float rangemax , float value )
{
if ( value < 1000.0f )
return jmap < float > ( value , 20.0f , 1000.0f , 0.0f , 0.5f ) ;
return jmap < float > ( value , 1000.0f , 20000.0f , 0.5f , 1.0f ) ;
} ;
2017-12-15 02:34:22 +00:00
addParameter ( new AudioParameterFloat ( " filter_low_0 " , " Filter low " ,
2017-12-15 15:43:59 +00:00
NormalisableRange < float > ( 20.0f , 20000.0f ,
filt_convertFrom0To1Func , filt_convertTo0To1Func ) , 20.0f ) ) ; // 23
2017-12-15 02:34:22 +00:00
addParameter ( new AudioParameterFloat ( " filter_high_0 " , " Filter high " ,
2017-12-15 15:43:59 +00:00
NormalisableRange < float > ( 20.0f , 20000.0f ,
filt_convertFrom0To1Func , filt_convertTo0To1Func ) , 20000.0f ) ) ; ; // 24
2018-02-01 18:09:12 +00:00
addParameter ( make_floatpar ( " onsetdetect_0 " , " Onset detection " , 0.0f , 1.0f , 0.0f , 0.01 , 1.0 ) ) ; // 25
2017-12-13 16:30:09 +00:00
addParameter ( new AudioParameterBool ( " capture_enabled0 " , " Capture " , false ) ) ; // 26
2022-04-24 22:11:57 +00:00
m_outchansparam = new AudioParameterInt ( " numoutchans0 " , " Num outs " , 1 , 32 , 2 ) ; // 27
2017-12-13 22:19:46 +00:00
addParameter ( m_outchansparam ) ; // 27
2022-04-18 19:11:22 +00:00
addParameter ( new AudioParameterBool ( " pause_enabled0 " , " Pause " , true ) ) ; // 28
2017-12-18 17:48:40 +00:00
addParameter ( new AudioParameterFloat ( " maxcapturelen_0 " , " Max capture length " , 1.0f , 120.0f , 10.0f ) ) ; // 29
2017-12-22 20:35:02 +00:00
addParameter ( new AudioParameterBool ( " passthrough0 " , " Pass input through " , false ) ) ; // 30
2018-02-07 14:00:49 +00:00
addParameter ( new AudioParameterBool ( " markdirty0 " , " Internal (don't use) " , false ) ) ; // 31
2022-04-24 22:11:57 +00:00
m_inchansparam = new AudioParameterInt ( " numinchans0 " , " Num ins " , 1 , 32 , 2 ) ; // 32
2018-02-12 14:44:21 +00:00
addParameter ( m_inchansparam ) ; // 32
2018-02-21 17:49:16 +00:00
addParameter ( new AudioParameterBool ( " bypass_stretch0 " , " Bypass stretch " , false ) ) ; // 33
2018-02-28 12:20:26 +00:00
addParameter ( new AudioParameterFloat ( " freefilter_shiftx_0 " , " Free filter shift X " , - 1.0f , 1.0f , 0.0f ) ) ; // 34
addParameter ( new AudioParameterFloat ( " freefilter_shifty_0 " , " Free filter shift Y " , - 1.0f , 1.0f , 0.0f ) ) ; // 35
2018-02-28 12:36:13 +00:00
addParameter ( new AudioParameterFloat ( " freefilter_scaley_0 " , " Free filter scale Y " , - 1.0f , 1.0f , 1.0f ) ) ; // 36
addParameter ( new AudioParameterFloat ( " freefilter_tilty_0 " , " Free filter tilt Y " , - 1.0f , 1.0f , 0.0f ) ) ; // 37
2018-03-03 15:22:23 +00:00
addParameter ( new AudioParameterInt ( " freefilter_randomybands0 " , " Random bands " , 2 , 128 , 16 ) ) ; // 38
addParameter ( new AudioParameterInt ( " freefilter_randomyrate0 " , " Random rate " , 1 , 32 , 2 ) ) ; // 39
addParameter ( new AudioParameterFloat ( " freefilter_randomyamount0 " , " Random amount " , 0.0 , 1.0 , 0.0 ) ) ; // 40
2018-03-06 11:44:36 +00:00
for ( int i = 0 ; i < 9 ; + + i ) // 41-49
{
addParameter ( m_sm_enab_pars [ i ] ) ;
2018-04-26 20:07:08 +00:00
m_sm_enab_pars [ i ] - > addListener ( this ) ;
2018-03-06 11:44:36 +00:00
}
2018-04-03 15:32:53 +00:00
addParameter ( make_floatpar ( " octavemix_extra0_0 " , " Ratio mix 7 level " , 0.0f , 1.0f , 0.0f , 0.001 , 1.0 ) ) ; // 50
addParameter ( make_floatpar ( " octavemix_extra1_0 " , " Ratio mix 8 level " , 0.0f , 1.0f , 0.0f , 0.001 , 1.0 ) ) ; // 51
2018-04-13 12:36:11 +00:00
std : : array < double , 8 > initialratios { 0.25 , 0.5 , 1.0 , 2.0 , 3.0 , 4.0 , 1.5 , 1.0 / 1.5 } ;
2018-04-03 15:32:53 +00:00
// 52-59
for ( int i = 0 ; i < 8 ; + + i )
{
2018-04-13 12:36:11 +00:00
addParameter ( make_floatpar ( " ratiomix_ratio_ " + String ( i ) + " _0 " , " Ratio mix ratio " + String ( i + 1 ) , 0.125f , 8.0f ,
initialratios [ i ] ,
0.001 ,
1.0 ) ) ;
2018-04-03 15:32:53 +00:00
}
2018-05-09 09:33:06 +00:00
addParameter ( new AudioParameterBool ( " loop_enabled0 " , " Loop " , true ) ) ; // 60
2022-04-22 04:55:35 +00:00
//addParameter(new AudioParameterBool("rewind0", "Rewind", false)); // 61
// have to add it this way to specify rewind as a Meta parameter, so that Apple auval will pass it
addParameter ( new AudioProcessorValueTreeState : : Parameter ( " rewind0 " ,
" Rewind " ,
" " ,
NormalisableRange < float > ( 0.0f , 1.0f ) ,
0.0f , // float defaultParameterValue,
nullptr , //std::function<String (float)> valueToTextFunction,
nullptr , // std::function<float (const String&)> textToValueFunction,
true , // bool isMetaParameter,
false , // bool isAutomatableParameter,
2022-04-22 05:51:33 +00:00
false , // bool isDiscrete,
2022-04-22 04:55:35 +00:00
AudioProcessorParameter : : Category : : genericParameter , // AudioProcessorParameter::Category parameterCategory,
true ) ) ; //bool isBoolean));
2018-08-21 08:49:28 +00:00
auto dprate_convertFrom0To1Func = [ ] ( float rangemin , float rangemax , float value )
{
if ( value < 0.5f )
return jmap < float > ( value , 0.0f , 0.5f , 0.1f , 1.0f ) ;
return jmap < float > ( value , 0.5f , 1.0f , 1.0f , 8.0f ) ;
} ;
auto dprate_convertTo0To1Func = [ ] ( float rangemin , float rangemax , float value )
{
if ( value < 1.0f )
return jmap < float > ( value , 0.1f , 1.0f , 0.0f , 0.5f ) ;
return jmap < float > ( value , 1.0f , 8.0f , 0.5f , 1.0f ) ;
} ;
addParameter ( new AudioParameterFloat ( " dryplayrate0 " , " Dry playrate " ,
NormalisableRange < float > ( 0.1f , 8.0f ,
dprate_convertFrom0To1Func , dprate_convertTo0To1Func ) , 1.0f ) ) ; // 62
2022-04-28 02:52:40 +00:00
addParameter ( new AudioParameterBool ( " binauralbeats " , " BinauralBeats Enable " , false ) ) ; // 63
addParameter ( new AudioParameterFloat ( " binauralbeatsmono " , " Binaural Beats Power " , 0.0 , 1.0 , 0.5 ) ) ; // 64
//addParameter(new AudioParameterFloat("binauralbeatsfreq", "BinauralBeats Freq", 0.0, 1.0, 0.5)); // 65
addParameter ( new AudioParameterFloat ( " binauralbeatsfreq " , " Binaural Beats Freq " ,
NormalisableRange < float > ( 0.05f , 50.0f , 0.0f , 0.25f ) , 4.0f ) ) ; // 65
addParameter ( new AudioParameterChoice ( " binauralbeatsmode " , " BinauralBeats Mode " , { " Left-Right " , " Right-Left " , " Symmetric " } , 0 ) ) ; // 66
m_bbpar . free_edit . extreme_y . set_min ( 0.05f ) ;
m_bbpar . free_edit . extreme_y . set_max ( 50.0f ) ;
2017-12-26 16:12:22 +00:00
auto & pars = getParameters ( ) ;
for ( const auto & p : pars )
m_reset_pars . push_back ( p - > getValue ( ) ) ;
2022-04-15 18:29:23 +00:00
if ( ! m_is_stand_alone_offline ) {
setPreBufferAmount ( 2 ) ;
2022-04-22 03:04:30 +00:00
startTimer ( 1 , 40 ) ;
2022-04-15 18:29:23 +00:00
}
2022-06-14 23:11:57 +00:00
# if (JUCE_IOS)
m_defaultRecordDir = File : : getSpecialLocation ( File : : userDocumentsDirectory ) . getFullPathName ( ) ;
# elif (JUCE_ANDROID)
auto parentDir = File : : getSpecialLocation ( File : : userApplicationDataDirectory ) ;
parentDir = parentDir . getChildFile ( " Recordings " ) ;
m_defaultRecordDir = parentDir . getFullPathName ( ) ;
# else
auto parentDir = File : : getSpecialLocation ( File : : userMusicDirectory ) ;
parentDir = parentDir . getChildFile ( " PaulXStretch " ) ;
m_defaultRecordDir = parentDir . getFullPathName ( ) ;
# endif
//m_defaultCaptureDir = parentDir.getChildFile("Captures").getFullPathName();
2022-04-15 18:29:23 +00:00
m_show_technical_info = m_propsfile - > m_props_file - > getBoolValue ( " showtechnicalinfo " , false ) ;
2022-04-22 03:04:30 +00:00
DBG ( " Constructed PS plugin " ) ;
2017-11-13 15:06:08 +00:00
}
PaulstretchpluginAudioProcessor : : ~ PaulstretchpluginAudioProcessor ( )
{
2022-04-02 16:45:02 +00:00
stopTimer ( 1 ) ;
2018-08-07 21:10:27 +00:00
//Logger::writeToLog("PaulX AudioProcessor destroyed");
2019-03-29 14:37:36 +00:00
if ( m_thumb )
m_thumb - > removeAllChangeListeners ( ) ;
2018-01-20 20:54:26 +00:00
m_thumb = nullptr ;
2022-04-14 07:26:26 +00:00
m_bufferingthread . stopThread ( 3000 ) ;
2017-11-20 22:39:07 +00:00
}
2017-12-26 16:12:22 +00:00
void PaulstretchpluginAudioProcessor : : resetParameters ( )
{
ScopedLock locker ( m_cs ) ;
for ( int i = 0 ; i < m_reset_pars . size ( ) ; + + i )
{
if ( i ! = cpi_main_volume & & i ! = cpi_passthrough )
setParameter ( i , m_reset_pars [ i ] ) ;
}
}
2017-11-20 22:39:07 +00:00
void PaulstretchpluginAudioProcessor : : setPreBufferAmount ( int x )
{
int temp = jlimit ( 0 , 5 , x ) ;
2017-12-20 01:58:50 +00:00
if ( temp ! = m_prebuffer_amount | | m_use_backgroundbuffering = = false )
2017-11-20 22:39:07 +00:00
{
2017-12-20 01:58:50 +00:00
m_use_backgroundbuffering = true ;
m_prebuffer_amount = temp ;
2017-11-20 22:39:07 +00:00
m_recreate_buffering_source = true ;
2017-12-20 01:58:50 +00:00
ScopedLock locker ( m_cs ) ;
2017-12-27 15:35:30 +00:00
m_prebuffering_inited = false ;
2017-12-20 01:58:50 +00:00
m_cur_num_out_chans = * m_outchansparam ;
//Logger::writeToLog("Switching to use " + String(m_cur_num_out_chans) + " out channels");
String err ;
2022-04-26 21:58:45 +00:00
setFFTSize ( * getFloatParameter ( cpi_fftsize ) , true ) ;
2017-12-20 01:58:50 +00:00
startplay ( { * getFloatParameter ( cpi_soundstart ) , * getFloatParameter ( cpi_soundend ) } ,
m_cur_num_out_chans , m_curmaxblocksize , err ) ;
2022-04-26 21:58:45 +00:00
m_stretch_source - > seekPercent ( m_stretch_source - > getLastSourcePositionPercent ( ) ) ;
2018-09-13 11:04:56 +00:00
m_prebuffering_inited = true ;
2017-11-20 22:39:07 +00:00
}
2017-11-13 15:06:08 +00:00
}
2017-12-22 20:35:02 +00:00
int PaulstretchpluginAudioProcessor : : getPreBufferAmount ( )
{
if ( m_use_backgroundbuffering = = false )
return - 1 ;
return m_prebuffer_amount ;
}
2017-12-27 20:43:07 +00:00
ValueTree PaulstretchpluginAudioProcessor : : getStateTree ( bool ignoreoptions , bool ignorefile )
2017-12-27 20:20:44 +00:00
{
ValueTree paramtree ( " paulstretch3pluginstate " ) ;
2019-02-12 12:56:37 +00:00
storeToTreeProperties ( paramtree , nullptr , getParameters ( ) , { getBoolParameter ( cpi_capture_trigger ) } ) ;
2022-04-13 17:48:09 +00:00
if ( m_current_file ! = URL ( ) & & ignorefile = = false )
2017-12-27 20:20:44 +00:00
{
2022-04-13 17:48:09 +00:00
paramtree . setProperty ( " importedfile " , m_current_file . toString ( false ) , nullptr ) ;
# if JUCE_IOS
// store bookmark data if necessary
if ( void * bookmark = getURLBookmark ( m_current_file ) ) {
const void * data = nullptr ;
size_t datasize = 0 ;
if ( urlBookmarkToBinaryData ( bookmark , data , datasize ) ) {
DBG ( " Audio file has bookmark, storing it in state, size: " < < datasize ) ;
paramtree . setProperty ( " importedfile_bookmark " , var ( data , datasize ) , nullptr ) ;
} else {
DBG ( " Bookmark is not valid! " ) ;
}
}
# endif
2017-12-27 20:20:44 +00:00
}
auto specorder = m_stretch_source - > getSpectrumProcessOrder ( ) ;
2018-03-21 11:15:48 +00:00
paramtree . setProperty ( " numspectralstagesb " , ( int ) specorder . size ( ) , nullptr ) ;
2017-12-27 20:20:44 +00:00
for ( int i = 0 ; i < specorder . size ( ) ; + + i )
{
2018-03-21 11:15:48 +00:00
paramtree . setProperty ( " specorderb " + String ( i ) , specorder [ i ] . m_index , nullptr ) ;
2017-12-27 20:20:44 +00:00
}
2017-12-27 20:43:07 +00:00
if ( ignoreoptions = = false )
{
if ( m_use_backgroundbuffering )
paramtree . setProperty ( " prebufamount " , m_prebuffer_amount , nullptr ) ;
else
paramtree . setProperty ( " prebufamount " , - 1 , nullptr ) ;
paramtree . setProperty ( " loadfilewithstate " , m_load_file_with_state , nullptr ) ;
2018-12-19 13:16:30 +00:00
storeToTreeProperties ( paramtree , nullptr , " playwhenhostrunning " , m_play_when_host_plays ,
" capturewhenhostrunning " , m_capture_when_host_plays , " savecapturedaudio " , m_save_captured_audio ,
2022-04-02 16:45:02 +00:00
" mutewhilecapturing " , m_mute_while_capturing , " muteprocwhilecapturing " , m_mute_processed_while_capturing ) ;
2017-12-27 20:43:07 +00:00
}
2018-06-29 12:13:49 +00:00
storeToTreeProperties ( paramtree , nullptr , " tabaindex " , m_cur_tab_index ) ;
2018-02-14 16:38:54 +00:00
storeToTreeProperties ( paramtree , nullptr , " waveviewrange " , m_wave_view_range ) ;
2018-02-27 01:41:54 +00:00
ValueTree freefilterstate = m_free_filter_envelope - > saveState ( Identifier ( " freefilter_envelope " ) ) ;
paramtree . addChild ( freefilterstate , - 1 , nullptr ) ;
2022-04-11 22:50:55 +00:00
storeToTreeProperties ( paramtree , nullptr , " pluginwidth " , mPluginWindowWidth ) ;
storeToTreeProperties ( paramtree , nullptr , " pluginheight " , mPluginWindowHeight ) ;
2022-04-15 23:13:55 +00:00
storeToTreeProperties ( paramtree , nullptr , " jumpsliders " , m_use_jumpsliders ) ;
2022-04-18 19:11:22 +00:00
storeToTreeProperties ( paramtree , nullptr , " restoreplaystate " , m_restore_playstate ) ;
2022-04-24 22:11:57 +00:00
storeToTreeProperties ( paramtree , nullptr , " autofinishrecord " , m_auto_finish_record ) ;
2022-04-11 22:50:55 +00:00
2022-06-14 23:11:57 +00:00
paramtree . setProperty ( " defRecordDir " , m_defaultRecordDir , nullptr ) ;
2022-06-14 23:18:08 +00:00
paramtree . setProperty ( " defRecordFormat " , ( int ) m_defaultRecordingFormat , nullptr ) ;
paramtree . setProperty ( " defRecordBitDepth " , ( int ) m_defaultRecordingBitsPerSample , nullptr ) ;
2022-06-14 23:11:57 +00:00
2018-02-27 01:41:54 +00:00
return paramtree ;
2017-12-27 20:20:44 +00:00
}
void PaulstretchpluginAudioProcessor : : setStateFromTree ( ValueTree tree )
{
if ( tree . isValid ( ) )
{
2022-04-18 19:11:22 +00:00
bool origpaused = getBoolParameter ( cpi_pause_enabled ) - > get ( ) ;
2017-12-27 20:20:44 +00:00
{
ScopedLock locker ( m_cs ) ;
2018-02-27 01:41:54 +00:00
ValueTree freefilterstate = tree . getChildWithName ( " freefilter_envelope " ) ;
m_free_filter_envelope - > restoreState ( freefilterstate ) ;
m_load_file_with_state = tree . getProperty ( " loadfilewithstate " , true ) ;
2018-06-04 20:27:08 +00:00
getFromTreeProperties ( tree , " playwhenhostrunning " , m_play_when_host_plays ,
2018-12-19 13:16:30 +00:00
" capturewhenhostrunning " , m_capture_when_host_plays , " mutewhilecapturing " , m_mute_while_capturing ,
2022-04-02 16:45:02 +00:00
" savecapturedaudio " , m_save_captured_audio , " muteprocwhilecapturing " , m_mute_processed_while_capturing ) ;
2018-06-29 12:13:49 +00:00
getFromTreeProperties ( tree , " tabaindex " , m_cur_tab_index ) ;
2022-04-11 22:50:55 +00:00
getFromTreeProperties ( tree , " pluginwidth " , mPluginWindowWidth ) ;
getFromTreeProperties ( tree , " pluginheight " , mPluginWindowHeight ) ;
2022-04-15 23:13:55 +00:00
getFromTreeProperties ( tree , " jumpsliders " , m_use_jumpsliders ) ;
2022-04-18 19:11:22 +00:00
getFromTreeProperties ( tree , " restoreplaystate " , m_restore_playstate ) ;
2022-04-24 22:11:57 +00:00
getFromTreeProperties ( tree , " autofinishrecord " , m_auto_finish_record ) ;
2022-04-11 22:50:55 +00:00
2018-03-21 11:15:48 +00:00
if ( tree . hasProperty ( " numspectralstagesb " ) )
2017-12-27 20:20:44 +00:00
{
2018-03-21 11:15:48 +00:00
std : : vector < SpectrumProcess > old_order = m_stretch_source - > getSpectrumProcessOrder ( ) ;
std : : vector < SpectrumProcess > new_order ;
int ordersize = tree . getProperty ( " numspectralstagesb " ) ;
if ( ordersize = = old_order . size ( ) )
2017-12-27 20:20:44 +00:00
{
2018-03-21 11:15:48 +00:00
for ( int i = 0 ; i < ordersize ; + + i )
{
2018-04-26 20:20:16 +00:00
int index = tree . getProperty ( " specorderb " + String ( i ) ) ;
2018-11-11 12:06:18 +00:00
new_order . push_back ( { ( SpectrumProcessType ) index , old_order [ index ] . m_enabled } ) ;
2018-03-21 11:15:48 +00:00
}
m_stretch_source - > setSpectrumProcessOrder ( new_order ) ;
2017-12-27 20:20:44 +00:00
}
}
2018-02-14 16:38:54 +00:00
getFromTreeProperties ( tree , " waveviewrange " , m_wave_view_range ) ;
2018-03-21 11:15:48 +00:00
getFromTreeProperties ( tree , getParameters ( ) ) ;
2022-06-14 23:11:57 +00:00
# if !(JUCE_IOS || JUCE_ANDROID)
setDefaultRecordingDirectory ( tree . getProperty ( " defRecordDir " , m_defaultRecordDir ) ) ;
# endif
2022-06-14 23:18:08 +00:00
m_defaultRecordingFormat = ( RecordFileFormat ) ( int ) tree . getProperty ( " defRecordFormat " , ( int ) m_defaultRecordingFormat ) ;
m_defaultRecordingBitsPerSample = ( int ) tree . getProperty ( " defRecordBitDepth " , ( int ) m_defaultRecordingBitsPerSample ) ;
2022-06-14 23:11:57 +00:00
2018-02-21 23:09:36 +00:00
}
2017-12-27 20:20:44 +00:00
int prebufamt = tree . getProperty ( " prebufamount " , 2 ) ;
if ( prebufamt = = - 1 )
m_use_backgroundbuffering = false ;
else
2022-04-15 18:29:23 +00:00
setPreBufferAmount ( m_is_stand_alone_offline ? 0 : prebufamt ) ;
2022-04-18 19:11:22 +00:00
if ( ! m_restore_playstate ) {
// use previous paused value
* ( getBoolParameter ( cpi_pause_enabled ) ) = origpaused ;
}
2017-12-27 20:20:44 +00:00
if ( m_load_file_with_state = = true )
{
2022-04-13 17:48:09 +00:00
String fn = tree . getProperty ( " importedfile " ) ;
if ( fn . isNotEmpty ( ) )
2017-12-27 20:20:44 +00:00
{
2022-04-13 17:48:09 +00:00
URL url ( fn ) ;
if ( ! url . isLocalFile ( ) ) {
// reconstruct just in case imported file string was not a URL
url = URL ( File ( fn ) ) ;
}
# if JUCE_IOS
// check for bookmark
auto bptr = tree . getPropertyPointer ( " importedfile_bookmark " ) ;
if ( bptr ) {
if ( auto * block = bptr - > getBinaryData ( ) ) {
DBG ( " Has file bookmark " ) ;
void * bookmark = binaryDataToUrlBookmark ( block - > getData ( ) , block - > getSize ( ) ) ;
setURLBookmark ( url , bookmark ) ;
}
}
else {
DBG ( " no url bookmark found " ) ;
}
# endif
setAudioFile ( url ) ;
2018-11-08 18:22:26 +00:00
}
2017-12-27 20:20:44 +00:00
}
2017-12-27 20:43:07 +00:00
m_state_dirty = true ;
2017-12-27 20:20:44 +00:00
}
}
2017-11-13 15:06:08 +00:00
//==============================================================================
const String PaulstretchpluginAudioProcessor : : getName ( ) const
{
return JucePlugin_Name ;
}
bool PaulstretchpluginAudioProcessor : : acceptsMidi ( ) const
{
# if JucePlugin_WantsMidiInput
return true ;
# else
return false ;
# endif
}
bool PaulstretchpluginAudioProcessor : : producesMidi ( ) const
{
# if JucePlugin_ProducesMidiOutput
return true ;
# else
return false ;
# endif
}
bool PaulstretchpluginAudioProcessor : : isMidiEffect ( ) const
{
# if JucePlugin_IsMidiEffect
return true ;
# else
return false ;
# endif
}
double PaulstretchpluginAudioProcessor : : getTailLengthSeconds ( ) const
{
2017-12-17 16:16:39 +00:00
return 0.0 ;
//return (double)m_bufamounts[m_prebuffer_amount]/getSampleRate();
2017-11-13 15:06:08 +00:00
}
int PaulstretchpluginAudioProcessor : : getNumPrograms ( )
{
2018-02-07 14:55:48 +00:00
return 1 ;
2017-11-13 15:06:08 +00:00
}
int PaulstretchpluginAudioProcessor : : getCurrentProgram ( )
{
2018-02-07 14:55:48 +00:00
return 0 ;
2017-11-13 15:06:08 +00:00
}
void PaulstretchpluginAudioProcessor : : setCurrentProgram ( int index )
{
2018-02-07 14:55:48 +00:00
2017-11-13 15:06:08 +00:00
}
const String PaulstretchpluginAudioProcessor : : getProgramName ( int index )
{
2018-02-07 14:55:48 +00:00
return String ( ) ;
2017-11-13 15:06:08 +00:00
}
void PaulstretchpluginAudioProcessor : : changeProgramName ( int index , const String & newName )
{
}
2018-04-26 20:07:08 +00:00
void PaulstretchpluginAudioProcessor : : parameterValueChanged ( int parameterIndex , float newValue )
{
if ( parameterIndex > = cpi_enable_spec_module0 & & parameterIndex < = cpi_enable_spec_module8 )
{
m_stretch_source - > setSpectralModuleEnabled ( parameterIndex - cpi_enable_spec_module0 , newValue > = 0.5 ) ;
}
}
void PaulstretchpluginAudioProcessor : : parameterGestureChanged ( int parameterIndex , bool gestureIsStarting )
{
}
2022-04-26 21:58:45 +00:00
void PaulstretchpluginAudioProcessor : : setFFTSize ( float size , bool force )
2017-11-20 22:39:07 +00:00
{
2022-04-26 21:58:45 +00:00
if ( fabsf ( m_last_fftsizeparamval - size ) > 0.00001f | | force ) {
if ( m_prebuffer_amount = = 5 )
m_fft_size_to_use = pow ( 2 , 7.0 + size * 14.5 ) ;
else m_fft_size_to_use = pow ( 2 , 7.0 + size * 10.0 ) ; // chicken out from allowing huge FFT sizes if not enough prebuffering
int optim = optimizebufsize ( m_fft_size_to_use ) ;
m_fft_size_to_use = optim ;
m_stretch_source - > setFFTSize ( optim , force ) ;
m_last_fftsizeparamval = size ;
//Logger::writeToLog(String(m_fft_size_to_use));
}
2017-11-20 22:39:07 +00:00
}
2017-12-14 17:06:26 +00:00
void PaulstretchpluginAudioProcessor : : startplay ( Range < double > playrange , int numoutchans , int maxBlockSize , String & err )
2017-11-20 22:39:07 +00:00
{
2018-05-18 13:20:51 +00:00
m_stretch_source - > setPlayRange ( playrange ) ;
2018-02-27 13:02:34 +00:00
m_stretch_source - > setFreeFilterEnvelope ( m_free_filter_envelope ) ;
2017-11-20 22:39:07 +00:00
int bufamt = m_bufamounts [ m_prebuffer_amount ] ;
if ( m_buffering_source ! = nullptr & & numoutchans ! = m_buffering_source - > getNumberOfChannels ( ) )
m_recreate_buffering_source = true ;
if ( m_recreate_buffering_source = = true )
{
m_buffering_source = std : : make_unique < MyBufferingAudioSource > ( m_stretch_source . get ( ) ,
m_bufferingthread , false , bufamt , numoutchans , false ) ;
m_recreate_buffering_source = false ;
}
2022-04-14 07:26:26 +00:00
if ( m_bufferingthread . isThreadRunning ( ) = = false ) {
m_bufferingthread . setPriority ( 8 ) ;
m_bufferingthread . startThread ( ) ;
}
2017-11-20 22:39:07 +00:00
m_stretch_source - > setNumOutChannels ( numoutchans ) ;
2022-04-26 21:58:45 +00:00
m_stretch_source - > setFFTSize ( m_fft_size_to_use , true ) ;
2022-04-28 02:52:40 +00:00
m_stretch_source - > setProcessParameters ( & m_ppar , & m_bbpar ) ;
2018-09-13 11:04:56 +00:00
m_stretch_source - > m_prebuffersize = bufamt ;
2019-03-29 15:11:04 +00:00
2017-11-20 22:39:07 +00:00
m_last_outpos_pos = 0.0 ;
m_last_in_pos = playrange . getStart ( ) * m_stretch_source - > getInfileLengthSeconds ( ) ;
2017-12-17 16:16:39 +00:00
m_buffering_source - > prepareToPlay ( maxBlockSize , getSampleRateChecked ( ) ) ;
}
2017-12-27 20:20:44 +00:00
void PaulstretchpluginAudioProcessor : : setParameters ( const std : : vector < double > & pars )
{
ScopedLock locker ( m_cs ) ;
for ( int i = 0 ; i < getNumParameters ( ) ; + + i )
{
if ( i < pars . size ( ) )
setParameter ( i , pars [ i ] ) ;
}
}
2022-04-28 02:52:40 +00:00
void PaulstretchpluginAudioProcessor : : updateStretchParametersFromPluginParameters ( ProcessParameters & pars , BinauralBeatsParameters & bbpar )
2018-02-26 14:34:13 +00:00
{
pars . pitch_shift . cents = * getFloatParameter ( cpi_pitchshift ) * 100.0 ;
pars . freq_shift . Hz = * getFloatParameter ( cpi_frequencyshift ) ;
pars . spread . bandwidth = * getFloatParameter ( cpi_spreadamount ) ;
pars . compressor . power = * getFloatParameter ( cpi_compress ) ;
pars . harmonics . nharmonics = * getIntParameter ( cpi_numharmonics ) ;
pars . harmonics . freq = * getFloatParameter ( cpi_harmonicsfreq ) ;
pars . harmonics . bandwidth = * getFloatParameter ( cpi_harmonicsbw ) ;
pars . harmonics . gauss = getParameter ( cpi_harmonicsgauss ) ;
pars . octave . om2 = * getFloatParameter ( cpi_octavesm2 ) ;
pars . octave . om1 = * getFloatParameter ( cpi_octavesm1 ) ;
pars . octave . o0 = * getFloatParameter ( cpi_octaves0 ) ;
pars . octave . o1 = * getFloatParameter ( cpi_octaves1 ) ;
pars . octave . o15 = * getFloatParameter ( cpi_octaves15 ) ;
pars . octave . o2 = * getFloatParameter ( cpi_octaves2 ) ;
2018-04-03 13:34:20 +00:00
pars . ratiomix . ratiolevels [ 0 ] = * getFloatParameter ( cpi_octavesm2 ) ;
pars . ratiomix . ratiolevels [ 1 ] = * getFloatParameter ( cpi_octavesm1 ) ;
pars . ratiomix . ratiolevels [ 2 ] = * getFloatParameter ( cpi_octaves0 ) ;
pars . ratiomix . ratiolevels [ 3 ] = * getFloatParameter ( cpi_octaves1 ) ;
pars . ratiomix . ratiolevels [ 4 ] = * getFloatParameter ( cpi_octaves15 ) ;
pars . ratiomix . ratiolevels [ 5 ] = * getFloatParameter ( cpi_octaves2 ) ;
2018-04-03 15:32:53 +00:00
pars . ratiomix . ratiolevels [ 6 ] = * getFloatParameter ( cpi_octaves_extra1 ) ;
pars . ratiomix . ratiolevels [ 7 ] = * getFloatParameter ( cpi_octaves_extra2 ) ;
for ( int i = 0 ; i < 8 ; + + i )
pars . ratiomix . ratios [ i ] = * getFloatParameter ( ( int ) cpi_octaves_ratio0 + i ) ;
2018-04-03 13:34:20 +00:00
2018-02-26 14:34:13 +00:00
pars . filter . low = * getFloatParameter ( cpi_filter_low ) ;
pars . filter . high = * getFloatParameter ( cpi_filter_high ) ;
pars . tonal_vs_noise . bandwidth = * getFloatParameter ( cpi_tonalvsnoisebw ) ;
pars . tonal_vs_noise . preserve = * getFloatParameter ( cpi_tonalvsnoisepreserve ) ;
2022-04-28 02:52:40 +00:00
bbpar . stereo_mode = ( BB_STEREO_MODE ) getChoiceParameter ( cpi_binauralbeats_mode ) - > getIndex ( ) ;
bbpar . mono = * getFloatParameter ( cpi_binauralbeats_mono ) ;
//bbpar.free_edit.set_all_values( *getFloatParameter(cpi_binauralbeats_freq));
auto * bbfreqp = getFloatParameter ( cpi_binauralbeats_freq ) ;
float bbfreq = * bbfreqp ;
float bbratio = ( bbfreq - bbfreqp - > getNormalisableRange ( ) . getRange ( ) . getStart ( ) ) / bbfreqp - > getNormalisableRange ( ) . getRange ( ) . getLength ( ) ;
if ( bbpar . free_edit . get_posy ( 0 ) ! = bbratio ) {
bbpar . free_edit . set_posy ( 0 , bbratio ) ;
bbpar . free_edit . set_posy ( 1 , bbratio ) ;
bbpar . free_edit . update_curve ( 2 ) ;
}
//bbpar.mono = 0.5f;
bbpar . free_edit . set_enabled ( * getBoolParameter ( cpi_binauralbeats ) ) ;
2018-02-26 14:34:13 +00:00
}
2018-11-08 18:22:26 +00:00
void PaulstretchpluginAudioProcessor : : saveCaptureBuffer ( )
{
auto task = [ this ] ( )
{
2022-04-15 23:13:55 +00:00
int inchans = jmin ( getMainBusNumInputChannels ( ) , getIntParameter ( cpi_num_inchans ) - > get ( ) ) ;
2018-11-08 18:22:26 +00:00
if ( inchans < 1 )
return ;
2022-06-14 23:11:57 +00:00
std : : unique_ptr < AudioFormat > audioFormat ;
String fextension ;
int bitsPerSample = std : : min ( 32 , m_defaultRecordingBitsPerSample ) ;
if ( m_defaultRecordingFormat = = FileFormatWAV ) {
audioFormat = std : : make_unique < WavAudioFormat > ( ) ;
fextension = " .wav " ;
}
else {
audioFormat = std : : make_unique < FlacAudioFormat > ( ) ;
fextension = " .flac " ;
bitsPerSample = std : : min ( 24 , bitsPerSample ) ;
}
2022-04-15 23:13:55 +00:00
String outfn ;
2022-04-24 22:11:57 +00:00
String filename = String ( " pxs_ " ) + Time : : getCurrentTime ( ) . formatted ( " %Y-%m-%d_%H.%M.%S " ) ;
filename = File : : createLegalFileName ( filename ) ;
2022-04-15 23:13:55 +00:00
if ( m_capture_location . isEmpty ( ) ) {
2022-06-14 23:11:57 +00:00
File capdir ( m_defaultRecordDir ) ;
outfn = capdir . getChildFile ( " Captures " ) . getNonexistentChildFile ( filename , fextension ) . getFullPathName ( ) ;
2022-04-15 23:13:55 +00:00
}
else {
2022-06-14 23:11:57 +00:00
outfn = File ( m_capture_location ) . getNonexistentChildFile ( filename , fextension ) . getFullPathName ( ) ;
2022-04-15 23:13:55 +00:00
}
2018-11-08 18:22:26 +00:00
File outfile ( outfn ) ;
2018-11-08 20:18:50 +00:00
outfile . create ( ) ;
if ( outfile . existsAsFile ( ) )
2018-11-08 18:22:26 +00:00
{
2018-12-19 13:16:30 +00:00
m_capture_save_state = 1 ;
2018-11-08 20:18:50 +00:00
auto outstream = outfile . createOutputStream ( ) ;
2022-06-14 23:11:57 +00:00
auto writer = unique_from_raw ( audioFormat - > createWriterFor ( outstream . get ( ) , getSampleRateChecked ( ) ,
inchans , bitsPerSample , { } , 0 ) ) ;
2018-11-08 20:18:50 +00:00
if ( writer ! = nullptr )
{
2022-04-02 16:45:02 +00:00
outstream . release ( ) ; // the writer takes ownership
2018-11-08 20:18:50 +00:00
auto sourcebuffer = getStretchSource ( ) - > getSourceAudioBuffer ( ) ;
jassert ( sourcebuffer - > getNumChannels ( ) = = inchans ) ;
jassert ( sourcebuffer - > getNumSamples ( ) > 0 ) ;
writer - > writeFromAudioSampleBuffer ( * sourcebuffer , 0 , sourcebuffer - > getNumSamples ( ) ) ;
2022-04-13 17:48:09 +00:00
m_current_file = URL ( outfile ) ;
2018-11-08 20:18:50 +00:00
}
else
{
Logger : : writeToLog ( " Could not create wav writer " ) ;
2020-03-25 23:32:39 +00:00
//delete outstream;
2018-11-08 20:18:50 +00:00
}
2018-11-08 18:22:26 +00:00
}
else
2018-11-08 20:18:50 +00:00
Logger : : writeToLog ( " Could not create output file " ) ;
2018-12-19 13:16:30 +00:00
m_capture_save_state = 0 ;
2018-11-08 18:22:26 +00:00
} ;
2018-11-08 20:48:06 +00:00
m_threadpool - > addJob ( task ) ;
2018-11-08 18:22:26 +00:00
}
2019-01-20 13:24:30 +00:00
String PaulstretchpluginAudioProcessor : : offlineRender ( OfflineRenderParams renderpars )
2018-02-26 15:49:19 +00:00
{
2019-01-20 13:24:30 +00:00
File outputfiletouse = renderpars . outputfile . getNonexistentSibling ( ) ;
ValueTree state { getStateTree ( false , false ) } ;
2022-04-15 23:13:55 +00:00
// override this to always load file with state if possible
state . setProperty ( " loadfilewithstate " , true , nullptr ) ;
2019-03-29 14:37:36 +00:00
auto processor = std : : make_shared < PaulstretchpluginAudioProcessor > ( true ) ;
processor - > setNonRealtime ( true ) ;
2018-07-09 17:21:06 +00:00
processor - > setStateFromTree ( state ) ;
2022-04-12 23:20:28 +00:00
double outsr { renderpars . outsr } ;
2022-04-12 22:47:43 +00:00
if ( outsr < 10.0 ) {
outsr = processor - > getStretchSource ( ) - > getInfileSamplerate ( ) ;
2022-04-15 23:13:55 +00:00
if ( outsr < 10.0 ) {
outsr = getSampleRateChecked ( ) ;
}
2022-04-12 22:47:43 +00:00
}
Logger : : writeToLog ( outputfiletouse . getFullPathName ( ) + " " + String ( outsr ) + " " + String ( renderpars . outputformat ) ) ;
2019-01-20 19:45:43 +00:00
int blocksize { 1024 } ;
2018-07-09 17:21:06 +00:00
int numoutchans = * processor - > getIntParameter ( cpi_num_outchans ) ;
2019-03-29 15:11:04 +00:00
auto sc = processor - > getStretchSource ( ) ;
2018-07-09 17:21:06 +00:00
double t0 = * processor - > getFloatParameter ( cpi_soundstart ) ;
double t1 = * processor - > getFloatParameter ( cpi_soundend ) ;
2018-02-26 15:49:19 +00:00
sanitizeTimeRange ( t0 , t1 ) ;
2022-04-15 18:29:23 +00:00
sc - > setPlayRange ( { t0 , t1 } , true ) ;
DBG ( " play range: " < < t0 < < " " < < t1 ) ;
DBG ( " SC play range s: " < < sc - > getPlayRange ( ) . getStart ( ) < < " e: " < < sc - > getPlayRange ( ) . getEnd ( ) ) ;
2019-03-29 15:11:04 +00:00
2022-04-12 23:20:28 +00:00
* ( processor - > getBoolParameter ( cpi_pause_enabled ) ) = false ;
2022-04-15 23:13:55 +00:00
if ( m_using_memory_buffer ) {
// copy it from the original
processor - > m_recbuffer . makeCopyOf ( m_recbuffer ) ;
processor - > m_using_memory_buffer = true ;
}
2019-03-29 15:11:04 +00:00
sc - > setMainVolume ( * processor - > getFloatParameter ( cpi_main_volume ) ) ;
sc - > setRate ( * processor - > getFloatParameter ( cpi_stretchamount ) ) ;
2022-04-15 23:13:55 +00:00
sc - > setPreviewDry ( * processor - > getBoolParameter ( cpi_bypass_stretch ) ) ;
2019-03-29 15:11:04 +00:00
sc - > setDryPlayrate ( * processor - > getFloatParameter ( cpi_dryplayrate ) ) ;
2022-04-15 23:13:55 +00:00
sc - > setPaused ( false ) ;
2022-04-15 18:29:23 +00:00
processor - > setFFTSize ( * processor - > getFloatParameter ( cpi_fftsize ) , true ) ;
2022-04-28 02:52:40 +00:00
processor - > updateStretchParametersFromPluginParameters ( processor - > m_ppar , processor - > m_bbpar ) ;
2019-03-29 15:11:04 +00:00
processor - > setPlayConfigDetails ( 2 , numoutchans , outsr , blocksize ) ;
processor - > prepareToPlay ( outsr , blocksize ) ;
2022-04-15 18:29:23 +00:00
2022-04-24 22:11:57 +00:00
if ( renderpars . numloops = = 1 ) {
// prevent any loop xfade getting into the output if only 1 loop selected
* processor - > getBoolParameter ( cpi_looping_enabled ) = false ;
}
2022-04-15 18:29:23 +00:00
//sc->setProcessParameters(&processor->m_ppar);
//sc->setFFTWindowingType(1);
DBG ( " SC post play range s: " < < sc - > getPlayRange ( ) . getStart ( ) < < " e: " < < sc - > getPlayRange ( ) . getEnd ( ) < < " fft: " < < sc - > getFFTSize ( ) < < " ourdur: " < < sc - > getOutputDurationSecondsForRange ( sc - > getPlayRange ( ) , sc - > getFFTSize ( ) ) ) ;
2019-03-29 15:11:04 +00:00
auto rendertask = [ sc , processor , outputfiletouse , renderpars , blocksize , numoutchans , outsr , this ] ( )
2018-02-26 15:49:19 +00:00
{
2019-01-20 18:21:29 +00:00
WavAudioFormat wavformat ;
2020-03-25 23:32:39 +00:00
auto outstream = outputfiletouse . createOutputStream ( ) ;
2019-03-29 21:27:08 +00:00
jassert ( outstream ! = nullptr ) ;
2019-01-20 18:21:29 +00:00
int oformattouse { 16 } ;
bool clipoutput { false } ;
if ( renderpars . outputformat = = 1 )
oformattouse = 24 ;
if ( renderpars . outputformat = = 2 )
oformattouse = 32 ;
if ( renderpars . outputformat = = 3 )
{
oformattouse = 32 ;
clipoutput = true ;
}
2020-03-25 23:32:39 +00:00
auto writer { unique_from_raw ( wavformat . createWriterFor ( outstream . get ( ) , outsr , numoutchans ,
2019-01-20 18:21:29 +00:00
oformattouse , StringPairArray ( ) , 0 ) ) } ;
if ( writer = = nullptr )
{
2020-03-25 23:32:39 +00:00
//delete outstream;
2019-01-20 18:21:29 +00:00
jassert ( false ) ;
2022-04-02 16:45:02 +00:00
m_offline_render_state = 200 ;
Logger : : writeToLog ( " Render failed, could not open file! " ) ;
2022-04-12 22:47:43 +00:00
if ( renderpars . completionHandler ) {
renderpars . completionHandler ( false , outputfiletouse ) ;
}
2022-04-02 16:45:02 +00:00
return ;
} else {
outstream . release ( ) ; // the writer takes ownership
AudioBuffer < float > renderbuffer { numoutchans , blocksize } ;
MidiBuffer dummymidi ;
double outlensecs = sc - > getOutputDurationSecondsForRange ( sc - > getPlayRange ( ) , sc - > getFFTSize ( ) ) ;
2022-04-15 18:29:23 +00:00
if ( * processor - > getBoolParameter ( cpi_looping_enabled ) ) {
outlensecs * = jmax ( 1 , renderpars . numloops ) ;
}
outlensecs = jmin ( outlensecs , renderpars . maxoutdur ) ;
2022-04-02 16:45:02 +00:00
int64_t outlenframes = outlensecs * outsr ;
int64_t outcounter { 0 } ;
m_offline_render_state = 0 ;
m_offline_render_cancel_requested = false ;
2022-04-15 18:29:23 +00:00
DBG ( " Starting rendering of " < < outlenframes < < " frames, " < < outlensecs < < " secs " < < " , loops: " < < renderpars . numloops < < " play range s: " < < sc - > getPlayRange ( ) . getStart ( ) < < " e: " < < sc - > getPlayRange ( ) . getEnd ( ) ) ;
2022-04-02 16:45:02 +00:00
while ( outcounter < outlenframes )
{
if ( m_offline_render_cancel_requested = = true )
break ;
processor - > processBlock ( renderbuffer , dummymidi ) ;
int64 framesToWrite = std : : min < int64 > ( blocksize , outlenframes - outcounter ) ;
writer - > writeFromAudioSampleBuffer ( renderbuffer , 0 , framesToWrite ) ;
outcounter + = blocksize ;
m_offline_render_state = 100.0 / outlenframes * outcounter ;
}
m_offline_render_state = 200 ;
2022-04-12 22:47:43 +00:00
if ( renderpars . completionHandler ) {
renderpars . completionHandler ( true , outputfiletouse ) ;
}
2022-04-02 16:45:02 +00:00
Logger : : writeToLog ( " Rendered ok! " ) ;
}
2018-02-26 17:55:32 +00:00
} ;
std : : thread th ( rendertask ) ;
th . detach ( ) ;
2018-02-26 15:49:19 +00:00
return " Rendered OK " ;
}
2017-12-17 16:16:39 +00:00
double PaulstretchpluginAudioProcessor : : getSampleRateChecked ( )
{
2018-02-26 15:49:19 +00:00
if ( m_cur_sr < 1.0 | | m_cur_sr > 1000000.0 )
2017-12-17 16:16:39 +00:00
return 44100.0 ;
return m_cur_sr ;
}
2017-11-20 22:39:07 +00:00
2017-11-13 16:15:07 +00:00
void PaulstretchpluginAudioProcessor : : prepareToPlay ( double sampleRate , int samplesPerBlock )
{
2018-02-21 23:54:21 +00:00
+ + m_prepare_count ;
ScopedLock locker ( m_cs ) ;
2019-01-17 17:47:56 +00:00
m_adsr . setSampleRate ( sampleRate ) ;
2017-12-17 16:16:39 +00:00
m_cur_sr = sampleRate ;
2017-12-14 17:06:26 +00:00
m_curmaxblocksize = samplesPerBlock ;
2022-04-22 03:04:30 +00:00
m_input_buffer . setSize ( getTotalNumInputChannels ( ) , samplesPerBlock ) ;
2022-04-22 04:55:35 +00:00
setParameter ( cpi_rewind , 0.0f ) ;
2018-05-31 10:55:32 +00:00
m_lastrewind = false ;
2017-12-13 22:19:46 +00:00
int numoutchans = * m_outchansparam ;
if ( numoutchans ! = m_cur_num_out_chans )
2017-12-27 15:35:30 +00:00
m_prebuffering_inited = false ;
2017-11-13 22:50:12 +00:00
if ( m_using_memory_buffer = = true )
2017-11-13 23:50:44 +00:00
{
2017-12-20 18:33:34 +00:00
int len = jlimit ( 100 , m_recbuffer . getNumSamples ( ) ,
int ( getSampleRateChecked ( ) * ( * getFloatParameter ( cpi_max_capture_len ) ) ) ) ;
2017-11-20 22:39:07 +00:00
m_stretch_source - > setAudioBufferAsInputSource ( & m_recbuffer ,
2017-12-17 16:16:39 +00:00
getSampleRateChecked ( ) ,
2017-11-13 23:50:44 +00:00
len ) ;
2018-02-19 19:09:09 +00:00
//m_thumb->reset(m_recbuffer.getNumChannels(), sampleRate, len);
2017-11-13 23:50:44 +00:00
}
2017-12-27 15:35:30 +00:00
if ( m_prebuffering_inited = = false )
2017-11-13 21:42:13 +00:00
{
2022-04-26 21:58:45 +00:00
setFFTSize ( * getFloatParameter ( cpi_fftsize ) , true ) ;
2022-04-28 02:52:40 +00:00
m_stretch_source - > setProcessParameters ( & m_ppar , & m_bbpar ) ;
2017-12-14 20:17:45 +00:00
m_stretch_source - > setFFTWindowingType ( 1 ) ;
2017-11-13 21:42:13 +00:00
String err ;
2017-12-14 17:57:14 +00:00
startplay ( { * getFloatParameter ( cpi_soundstart ) , * getFloatParameter ( cpi_soundend ) } ,
2017-12-14 17:06:26 +00:00
numoutchans , samplesPerBlock , err ) ;
2017-12-13 22:19:46 +00:00
m_cur_num_out_chans = numoutchans ;
2017-12-27 15:35:30 +00:00
m_prebuffering_inited = true ;
}
else
{
m_buffering_source - > prepareToPlay ( samplesPerBlock , getSampleRateChecked ( ) ) ;
2017-11-13 21:42:13 +00:00
}
2022-04-22 03:04:30 +00:00
m_standalone = juce : : PluginHostType : : getPluginLoadedAs ( ) = = AudioProcessor : : wrapperType_Standalone ;
2017-11-13 15:06:08 +00:00
}
void PaulstretchpluginAudioProcessor : : releaseResources ( )
{
2019-03-29 14:37:36 +00:00
2017-11-13 15:06:08 +00:00
}
# ifndef JucePlugin_PreferredChannelConfigurations
bool PaulstretchpluginAudioProcessor : : isBusesLayoutSupported ( const BusesLayout & layouts ) const
{
# if JucePlugin_IsMidiEffect
ignoreUnused ( layouts ) ;
return true ;
# else
2022-04-22 03:04:30 +00:00
// support anything
return true ;
2017-11-13 15:06:08 +00:00
// This is the place where you check if the layout is supported.
// In this template code we only support mono or stereo.
2022-04-22 03:04:30 +00:00
if ( /* layouts.getMainOutputChannelSet() != AudioChannelSet::mono() && */
layouts . getMainOutputChannelSet ( ) ! = AudioChannelSet : : stereo ( ) )
2017-11-13 15:06:08 +00:00
return false ;
// This checks if the input layout matches the output layout
# if ! JucePlugin_IsSynth
if ( layouts . getMainOutputChannelSet ( ) ! = layouts . getMainInputChannelSet ( ) )
return false ;
# endif
return true ;
# endif
}
# endif
2022-04-22 03:04:30 +00:00
static void copyAudioBufferWrappingPosition ( const AudioBuffer < float > & src , int numSamples , AudioBuffer < float > & dest , int destbufpos , int maxdestpos , float fademode )
2017-11-15 15:52:47 +00:00
{
2022-04-22 03:04:30 +00:00
int useNumSamples = jmin ( numSamples , src . getNumSamples ( ) ) ;
2017-11-15 15:52:47 +00:00
for ( int i = 0 ; i < dest . getNumChannels ( ) ; + + i )
{
int channel_to_copy = i % src . getNumChannels ( ) ;
2022-04-22 03:04:30 +00:00
if ( destbufpos + useNumSamples > maxdestpos )
2017-11-15 15:52:47 +00:00
{
2022-04-22 03:04:30 +00:00
int wrappos = ( destbufpos + useNumSamples ) % maxdestpos ;
int partial_len = useNumSamples - wrappos ;
if ( fademode = = 0.0f ) {
dest . copyFrom ( i , destbufpos , src , channel_to_copy , 0 , partial_len ) ;
dest . copyFrom ( i , partial_len , src , channel_to_copy , 0 , wrappos ) ;
} else {
//DBG("recfade wrap: " << fademode);
if ( fademode > 0.0f ) {
// fade in
dest . copyFromWithRamp ( i , destbufpos , src . getReadPointer ( channel_to_copy ) , partial_len , fademode > 0.0f ? 0.0f : 1.0f , fademode > 0.0f ? 1.0f : 0.0f ) ;
dest . copyFrom ( i , partial_len , src , channel_to_copy , 0 , wrappos ) ;
} else {
// fade out
dest . copyFrom ( i , destbufpos , src , channel_to_copy , 0 , partial_len ) ;
dest . copyFromWithRamp ( i , partial_len , src . getReadPointer ( channel_to_copy ) , wrappos , fademode > 0.0f ? 0.0f : 1.0f , fademode > 0.0f ? 1.0f : 0.0f ) ;
}
}
2017-11-15 15:52:47 +00:00
}
else
{
2022-04-22 03:04:30 +00:00
if ( fademode = = 0.0f ) {
dest . copyFrom ( i , destbufpos , src , channel_to_copy , 0 , useNumSamples ) ;
} else {
//DBG("recfade: " << fademode);
dest . copyFromWithRamp ( i , destbufpos , src . getReadPointer ( channel_to_copy ) , useNumSamples , fademode > 0.0f ? 0.0f : 1.0f , fademode > 0.0f ? 1.0f : 0.0f ) ;
}
2017-11-15 15:52:47 +00:00
}
}
}
2018-04-17 20:39:26 +00:00
/*
void PaulstretchpluginAudioProcessor : : processBlock ( AudioBuffer < double > & buffer , MidiBuffer & )
{
jassert ( false ) ;
}
*/
2017-11-13 15:06:08 +00:00
void PaulstretchpluginAudioProcessor : : processBlock ( AudioSampleBuffer & buffer , MidiBuffer & midiMessages )
{
2018-10-15 16:21:11 +00:00
ScopedLock locker ( m_cs ) ;
2018-05-31 10:21:35 +00:00
const int totalNumInputChannels = getTotalNumInputChannels ( ) ;
const int totalNumOutputChannels = getTotalNumOutputChannels ( ) ;
2022-04-22 03:04:30 +00:00
bool passthruEnabled = getParameter ( cpi_passthrough ) > 0.5f ;
AudioPlayHead * phead = getPlayHead ( ) ;
bool seektostart = false ;
2017-12-19 21:00:42 +00:00
if ( phead ! = nullptr )
{
phead - > getCurrentPosition ( m_playposinfo ) ;
2022-04-22 03:04:30 +00:00
2022-04-24 22:11:57 +00:00
if ( m_playposinfo . isPlaying & & ( m_playposinfo . ppqPosition = = 0.0 | | m_playposinfo . timeInSamples = = 0 ) ) {
2022-04-22 03:04:30 +00:00
seektostart = true ;
}
2017-12-19 21:00:42 +00:00
}
2022-04-22 03:04:30 +00:00
else {
2018-02-01 11:17:15 +00:00
m_playposinfo . isPlaying = false ;
2022-04-22 03:04:30 +00:00
}
2017-11-13 23:50:44 +00:00
ScopedNoDenormals noDenormals ;
2017-12-17 16:16:39 +00:00
double srtemp = getSampleRate ( ) ;
if ( srtemp ! = m_cur_sr )
m_cur_sr = srtemp ;
2018-05-01 15:22:21 +00:00
m_prebufsmoother . setSlope ( 0.9 , srtemp / buffer . getNumSamples ( ) ) ;
m_smoothed_prebuffer_ready = m_prebufsmoother . process ( m_buffering_source - > getPercentReady ( ) ) ;
2022-04-22 03:04:30 +00:00
if ( buffer . getNumSamples ( ) > m_input_buffer . getNumSamples ( ) ) {
// just in case
m_input_buffer . setSize ( totalNumInputChannels , buffer . getNumSamples ( ) , false , false , true ) ;
}
2017-12-20 18:33:34 +00:00
for ( int i = 0 ; i < totalNumInputChannels ; + + i )
m_input_buffer . copyFrom ( i , 0 , buffer , i , 0 , buffer . getNumSamples ( ) ) ;
2017-11-13 15:06:08 +00:00
for ( int i = totalNumInputChannels ; i < totalNumOutputChannels ; + + i )
buffer . clear ( i , 0 , buffer . getNumSamples ( ) ) ;
2022-04-22 03:04:30 +00:00
float fadepassthru = 0.0f ;
if ( ! passthruEnabled ) {
if ( m_lastpassthru ! = passthruEnabled ) {
// ramp it down
fadepassthru = - 1.0f ;
for ( int i = 0 ; i < totalNumInputChannels ; + + i )
buffer . applyGainRamp ( i , 0 , buffer . getNumSamples ( ) , 1.0f , 0.0f ) ;
}
else {
for ( int i = 0 ; i < totalNumInputChannels ; + + i )
buffer . clear ( i , 0 , buffer . getNumSamples ( ) ) ;
}
}
else if ( passthruEnabled ! = m_lastpassthru ) {
// ramp it up
fadepassthru = 1.0f ;
for ( int i = 0 ; i < totalNumInputChannels ; + + i )
buffer . applyGainRamp ( i , 0 , buffer . getNumSamples ( ) , 0.0f , 1.0f ) ;
}
m_lastpassthru = passthruEnabled ;
float recfade = 0.0f ;
if ( m_is_recording ! = m_is_recording_pending ) {
recfade = m_is_recording_pending ? 1.0f : - 1.0f ;
m_is_recording = m_is_recording_pending ;
}
2022-04-24 22:11:57 +00:00
if ( m_is_recording & & m_auto_finish_record & & ( m_rec_count + buffer . getNumSamples ( ) ) > m_max_reclen * getSampleRateChecked ( ) )
{
// finish recording automatically
recfade = - 1.0f ;
m_is_recording = m_is_recording_pending = false ;
DBG ( " Finish record automatically " ) ;
}
2022-04-22 03:04:30 +00:00
2018-09-26 16:19:10 +00:00
if ( m_previewcomponent ! = nullptr )
{
m_previewcomponent - > processBlock ( getSampleRate ( ) , buffer ) ;
return ;
}
2022-04-22 03:04:30 +00:00
if ( m_prebuffering_inited = = false )
2017-11-13 16:15:07 +00:00
return ;
2022-04-22 03:04:30 +00:00
if ( m_is_recording = = true | | recfade ! = 0.0f )
2017-11-13 19:21:30 +00:00
{
2022-04-22 03:04:30 +00:00
if ( m_playposinfo . isPlaying = = false & & m_capture_when_host_plays = = true & & ! m_standalone ) {
if ( ! m_is_recording )
m_is_recording_finished = true ;
2017-12-20 18:33:34 +00:00
return ;
2022-04-22 03:04:30 +00:00
}
2017-11-15 15:52:47 +00:00
int recbuflenframes = m_max_reclen * getSampleRate ( ) ;
2022-04-22 03:04:30 +00:00
copyAudioBufferWrappingPosition ( m_input_buffer , buffer . getNumSamples ( ) , m_recbuffer , m_rec_pos , recbuflenframes , recfade ) ;
m_thumb - > addBlock ( m_rec_pos , m_input_buffer , 0 , buffer . getNumSamples ( ) ) ;
2017-11-15 15:52:47 +00:00
m_rec_pos = ( m_rec_pos + buffer . getNumSamples ( ) ) % recbuflenframes ;
2018-06-05 18:11:17 +00:00
m_rec_count + = buffer . getNumSamples ( ) ;
2022-04-22 03:04:30 +00:00
if ( ! m_is_recording ) {
// to signal that it may be written, etc
2022-04-24 22:11:57 +00:00
DBG ( " Signal finish " ) ;
2022-04-22 03:04:30 +00:00
m_is_recording_finished = true ;
}
2018-06-05 18:11:17 +00:00
if ( m_rec_count < recbuflenframes )
m_recorded_range = { 0 , m_rec_count } ;
2022-04-22 03:04:30 +00:00
if ( m_mute_while_capturing = = true & & passthruEnabled ) {
if ( recfade < 0.0f ) {
buffer . applyGainRamp ( 0 , buffer . getNumSamples ( ) , 1.0f , 0.0f ) ;
}
else if ( recfade > 0.0f ) {
buffer . applyGainRamp ( 0 , buffer . getNumSamples ( ) , 0.0f , 1.0f ) ;
}
else {
buffer . clear ( ) ;
}
}
2022-04-02 16:45:02 +00:00
if ( m_mute_processed_while_capturing = = true )
return ;
2017-11-13 19:21:30 +00:00
}
2017-11-20 22:39:07 +00:00
jassert ( m_buffering_source ! = nullptr ) ;
jassert ( m_bufferingthread . isThreadRunning ( ) ) ;
2018-05-18 13:20:51 +00:00
double t0 = * getFloatParameter ( cpi_soundstart ) ;
double t1 = * getFloatParameter ( cpi_soundend ) ;
sanitizeTimeRange ( t0 , t1 ) ;
m_stretch_source - > setPlayRange ( { t0 , t1 } ) ;
2022-04-22 03:04:30 +00:00
float fadeproc = 0.0f ;
2017-12-19 23:12:47 +00:00
if ( m_last_host_playing = = false & & m_playposinfo . isPlaying )
{
2022-04-22 03:04:30 +00:00
if ( m_play_when_host_plays ) {
// should we even do this ever?
if ( seektostart )
m_stretch_source - > seekPercent ( * getFloatParameter ( cpi_soundstart ) ) ;
fadeproc = 1.0f ; // fadein
}
2017-12-19 23:12:47 +00:00
m_last_host_playing = true ;
}
else if ( m_last_host_playing = = true & & m_playposinfo . isPlaying = = false )
{
m_last_host_playing = false ;
2022-04-22 03:04:30 +00:00
if ( m_play_when_host_plays ) {
fadeproc = - 1.0f ; // fadeout
}
2017-12-19 23:12:47 +00:00
}
2022-04-22 03:04:30 +00:00
if ( m_play_when_host_plays = = true & & m_playposinfo . isPlaying = = false & & ! m_standalone & & fadeproc = = 0.0f )
2017-12-19 23:12:47 +00:00
return ;
2022-04-22 03:04:30 +00:00
2018-02-28 12:20:26 +00:00
m_free_filter_envelope - > m_transform_x_shift = * getFloatParameter ( cpi_freefilter_shiftx ) ;
m_free_filter_envelope - > m_transform_y_shift = * getFloatParameter ( cpi_freefilter_shifty ) ;
2018-02-28 12:36:13 +00:00
m_free_filter_envelope - > m_transform_y_scale = * getFloatParameter ( cpi_freefilter_scaley ) ;
m_free_filter_envelope - > m_transform_y_tilt = * getFloatParameter ( cpi_freefilter_tilty ) ;
2018-03-03 15:22:23 +00:00
m_free_filter_envelope - > m_transform_y_random_bands = * getIntParameter ( cpi_freefilter_randomy_numbands ) ;
m_free_filter_envelope - > m_transform_y_random_rate = * getIntParameter ( cpi_freefilter_randomy_rate ) ;
m_free_filter_envelope - > m_transform_y_random_amount = * getFloatParameter ( cpi_freefilter_randomy_amount ) ;
2019-01-17 13:23:01 +00:00
2018-11-15 18:14:56 +00:00
2018-04-26 20:07:08 +00:00
//m_stretch_source->setSpectralModulesEnabled(m_sm_enab_pars);
2018-03-06 11:44:36 +00:00
2018-05-09 09:33:06 +00:00
if ( m_stretch_source - > isLoopEnabled ( ) ! = * getBoolParameter ( cpi_looping_enabled ) )
m_stretch_source - > setLoopingEnabled ( * getBoolParameter ( cpi_looping_enabled ) ) ;
2022-04-22 04:55:35 +00:00
bool rew = getParameter ( cpi_rewind ) > 0.0f ;
2018-05-31 10:55:32 +00:00
if ( rew ! = m_lastrewind )
2018-05-18 13:20:51 +00:00
{
if ( rew = = true )
{
2022-04-22 04:55:35 +00:00
setParameter ( cpi_rewind , 0.0f ) ;
2018-05-18 13:20:51 +00:00
m_stretch_source - > seekPercent ( m_stretch_source - > getPlayRange ( ) . getStart ( ) ) ;
}
m_lastrewind = rew ;
}
2018-05-09 09:33:06 +00:00
2017-12-14 17:57:14 +00:00
m_stretch_source - > setMainVolume ( * getFloatParameter ( cpi_main_volume ) ) ;
m_stretch_source - > setRate ( * getFloatParameter ( cpi_stretchamount ) ) ;
2018-02-21 17:49:16 +00:00
m_stretch_source - > setPreviewDry ( * getBoolParameter ( cpi_bypass_stretch ) ) ;
2018-08-20 12:49:51 +00:00
m_stretch_source - > setDryPlayrate ( * getFloatParameter ( cpi_dryplayrate ) ) ;
2017-12-12 21:38:24 +00:00
setFFTSize ( * getFloatParameter ( cpi_fftsize ) ) ;
2018-01-30 15:54:06 +00:00
2022-04-28 02:52:40 +00:00
updateStretchParametersFromPluginParameters ( m_ppar , m_bbpar ) ;
2018-02-26 14:34:13 +00:00
2017-12-13 16:30:09 +00:00
m_stretch_source - > setOnsetDetection ( * getFloatParameter ( cpi_onsetdetection ) ) ;
2017-12-12 18:00:51 +00:00
m_stretch_source - > setLoopXFadeLength ( * getFloatParameter ( cpi_loopxfadelen ) ) ;
2018-05-18 13:20:51 +00:00
2022-04-15 23:13:55 +00:00
m_stretch_source - > setFreezing ( * getBoolParameter ( cpi_freeze ) ) ;
m_stretch_source - > setPaused ( * getBoolParameter ( cpi_pause_enabled ) ) ;
2019-01-20 18:21:29 +00:00
if ( m_midinote_control = = true )
{
MidiBuffer : : Iterator midi_it ( midiMessages ) ;
MidiMessage midi_msg ;
int midi_msg_pos ;
while ( true )
2019-01-17 17:26:41 +00:00
{
2019-01-20 18:21:29 +00:00
if ( midi_it . getNextEvent ( midi_msg , midi_msg_pos ) = = false )
break ;
if ( midi_msg . isNoteOff ( ) & & midi_msg . getNoteNumber ( ) = = m_midinote_to_use )
{
m_adsr . noteOff ( ) ;
break ;
}
if ( midi_msg . isNoteOn ( ) )
{
m_midinote_to_use = midi_msg . getNoteNumber ( ) ;
m_adsr . setParameters ( { 1.0 , 0.5 , 0.5 , 1.0 } ) ;
m_adsr . noteOn ( ) ;
break ;
}
2019-01-17 17:26:41 +00:00
}
}
2019-01-17 17:47:56 +00:00
if ( m_midinote_control = = true & & m_midinote_to_use > = 0 )
2019-01-17 17:26:41 +00:00
{
int note_offset = m_midinote_to_use - 60 ;
m_ppar . pitch_shift . cents + = 100.0 * note_offset ;
}
2022-04-28 02:52:40 +00:00
m_stretch_source - > setProcessParameters ( & m_ppar , & m_bbpar ) ;
2017-11-20 22:39:07 +00:00
AudioSourceChannelInfo aif ( buffer ) ;
2017-12-20 01:58:50 +00:00
if ( isNonRealtime ( ) | | m_use_backgroundbuffering = = false )
2017-12-18 22:37:02 +00:00
{
m_stretch_source - > getNextAudioBlock ( aif ) ;
}
else
{
m_buffering_source - > getNextAudioBlock ( aif ) ;
}
2022-04-22 03:04:30 +00:00
// fade processing if necessary
if ( fadeproc ! = 0.0f ) {
buffer . applyGainRamp ( 0 , buffer . getNumSamples ( ) , fadeproc > 0.0f ? 0.0f : 1.0f , fadeproc > 0.0f ? 1.0f : 0.0f ) ;
}
if ( fadepassthru ! = 0.0f
| | ( passthruEnabled & & ( ! m_is_recording | | ! m_mute_while_capturing ) )
| | ( recfade ! = 0.0f & & m_mute_while_capturing ) )
2017-12-20 18:33:34 +00:00
{
2022-04-22 03:04:30 +00:00
if ( recfade ! = 0.0f & & m_mute_while_capturing ) {
// DBG("Invert recfade");
fadepassthru = - recfade ;
}
2017-12-20 18:33:34 +00:00
for ( int i = 0 ; i < totalNumInputChannels ; + + i )
{
2022-04-22 03:04:30 +00:00
if ( fadepassthru ! = 0.0f ) {
buffer . addFromWithRamp ( i , 0 , m_input_buffer . getReadPointer ( i ) , buffer . getNumSamples ( ) , fadepassthru > 0.0f ? 0.0f : 1.0f , fadepassthru > 0.0f ? 1.0f : 0.0f ) ;
}
else
buffer . addFrom ( i , 0 , m_input_buffer , i , 0 , buffer . getNumSamples ( ) ) ;
2017-12-20 18:33:34 +00:00
}
2022-04-22 03:04:30 +00:00
}
2018-08-21 09:17:34 +00:00
bool abnordetected = false ;
2017-12-18 20:27:12 +00:00
for ( int i = 0 ; i < buffer . getNumChannels ( ) ; + + i )
{
for ( int j = 0 ; j < buffer . getNumSamples ( ) ; + + j )
{
float sample = buffer . getSample ( i , j ) ;
if ( std : : isnan ( sample ) | | std : : isinf ( sample ) )
2018-08-21 09:17:34 +00:00
{
2017-12-18 20:27:12 +00:00
+ + m_abnormal_output_samples ;
2018-08-21 09:17:34 +00:00
abnordetected = true ;
}
2017-12-18 20:27:12 +00:00
}
}
2018-08-21 09:17:34 +00:00
if ( abnordetected )
{
buffer . clear ( ) ;
}
2019-01-17 17:47:56 +00:00
else
{
if ( m_midinote_control = = true )
{
m_adsr . applyEnvelopeToBuffer ( buffer , 0 , buffer . getNumSamples ( ) ) ;
}
}
2019-02-12 12:59:51 +00:00
/*
2019-01-17 16:30:40 +00:00
auto ed = dynamic_cast < PaulstretchpluginAudioProcessorEditor * > ( getActiveEditor ( ) ) ;
if ( ed ! = nullptr )
{
ed - > m_sonogram . addAudioBlock ( buffer ) ;
}
2019-02-12 12:59:51 +00:00
*/
2022-06-14 23:11:57 +00:00
// output to file writer if necessary
if ( m_writingPossible . load ( ) ) {
const ScopedTryLock sl ( m_writerLock ) ;
if ( sl . isLocked ( ) )
{
if ( m_activeMixWriter . load ( ) ! = nullptr ) {
m_activeMixWriter . load ( ) - > write ( buffer . getArrayOfReadPointers ( ) , buffer . getNumSamples ( ) ) ;
}
m_elapsedRecordSamples + = buffer . getNumSamples ( ) ;
}
}
2017-11-13 15:06:08 +00:00
}
//==============================================================================
bool PaulstretchpluginAudioProcessor : : hasEditor ( ) const
{
return true ; // (change this to false if you choose to not supply an editor)
}
AudioProcessorEditor * PaulstretchpluginAudioProcessor : : createEditor ( )
{
2017-11-13 18:45:23 +00:00
return new PaulstretchpluginAudioProcessorEditor ( * this ) ;
2017-11-13 15:06:08 +00:00
}
//==============================================================================
void PaulstretchpluginAudioProcessor : : getStateInformation ( MemoryBlock & destData )
{
2017-12-27 20:43:07 +00:00
ValueTree paramtree = getStateTree ( false , false ) ;
2017-12-26 18:24:10 +00:00
MemoryOutputStream stream ( destData , true ) ;
2017-11-15 18:51:52 +00:00
paramtree . writeToStream ( stream ) ;
2017-11-13 15:06:08 +00:00
}
void PaulstretchpluginAudioProcessor : : setStateInformation ( const void * data , int sizeInBytes )
{
2017-11-23 15:57:37 +00:00
ValueTree tree = ValueTree : : readFromData ( data , sizeInBytes ) ;
2017-12-27 20:20:44 +00:00
setStateFromTree ( tree ) ;
2017-11-13 15:06:08 +00:00
}
2018-02-07 14:00:49 +00:00
void PaulstretchpluginAudioProcessor : : setDirty ( )
{
2018-02-13 17:41:52 +00:00
toggleBool ( getBoolParameter ( cpi_markdirty ) ) ;
2018-02-07 14:00:49 +00:00
}
2022-06-14 23:11:57 +00:00
void PaulstretchpluginAudioProcessor : : setInputRecordingEnabled ( bool b )
2017-11-13 19:21:30 +00:00
{
2017-12-12 18:43:43 +00:00
ScopedLock locker ( m_cs ) ;
2017-12-17 16:16:39 +00:00
int lenbufframes = getSampleRateChecked ( ) * m_max_reclen ;
2017-11-13 19:21:30 +00:00
if ( b = = true )
{
2017-11-15 18:51:52 +00:00
m_using_memory_buffer = true ;
2022-04-13 17:48:09 +00:00
m_current_file = URL ( ) ;
2022-04-15 23:13:55 +00:00
int numchans = jmin ( getMainBusNumInputChannels ( ) , m_inchansparam - > get ( ) ) ;
2018-02-13 13:37:16 +00:00
m_recbuffer . setSize ( numchans , m_max_reclen * getSampleRateChecked ( ) + 4096 , false , false , true ) ;
2017-11-13 20:35:36 +00:00
m_recbuffer . clear ( ) ;
2017-11-13 19:21:30 +00:00
m_rec_pos = 0 ;
2018-01-17 19:53:26 +00:00
m_thumb - > reset ( m_recbuffer . getNumChannels ( ) , getSampleRateChecked ( ) , lenbufframes ) ;
2022-04-24 22:11:57 +00:00
m_recorded_range = Range < int64 > ( ) ;
2018-06-05 18:11:17 +00:00
m_rec_count = 0 ;
2022-04-24 22:11:57 +00:00
m_next_rec_count = getSampleRateChecked ( ) * m_max_reclen ;
2022-04-22 03:04:30 +00:00
m_is_recording_pending = true ;
2017-11-13 19:21:30 +00:00
}
else
{
2022-04-22 03:04:30 +00:00
if ( m_is_recording = = true ) {
m_is_recording_finished = false ; // will be marked true when the recording is truly done
m_is_recording_pending = false ;
}
2017-11-13 19:21:30 +00:00
}
}
2022-06-14 23:11:57 +00:00
double PaulstretchpluginAudioProcessor : : getInputRecordingPositionPercent ( )
2017-11-13 20:35:36 +00:00
{
2022-04-22 03:04:30 +00:00
if ( m_is_recording_pending = = false )
2017-11-13 20:35:36 +00:00
return 0.0 ;
return 1.0 / m_recbuffer . getNumSamples ( ) * m_rec_pos ;
}
2022-04-13 17:48:09 +00:00
String PaulstretchpluginAudioProcessor : : setAudioFile ( const URL & url )
2017-11-14 16:14:14 +00:00
{
2022-04-13 17:48:09 +00:00
// this handles any permissions stuff (needed on ios)
std : : unique_ptr < InputStream > wi ( url . createInputStream ( false ) ) ;
File file = url . getLocalFile ( ) ;
auto ai = unique_from_raw ( m_afm - > createReaderFor ( file ) ) ;
2017-11-20 22:39:07 +00:00
if ( ai ! = nullptr )
2017-11-14 16:14:14 +00:00
{
2018-02-19 19:12:54 +00:00
if ( ai - > numChannels > 8 )
2017-11-20 22:39:07 +00:00
{
2022-04-13 17:48:09 +00:00
return " Too many channels in file " + file . getFullPathName ( ) ;
2017-11-20 22:39:07 +00:00
}
if ( ai - > bitsPerSample > 32 )
{
2022-04-13 17:48:09 +00:00
return " Too high bit depth in file " + file . getFullPathName ( ) ;
2017-11-20 22:39:07 +00:00
}
2019-03-29 14:37:36 +00:00
if ( m_thumb )
2022-04-13 17:48:09 +00:00
m_thumb - > setSource ( new FileInputSource ( file ) ) ;
2022-04-22 03:04:30 +00:00
// lets not lock
//ScopedLock locker(m_cs);
m_stretch_source - > setAudioFile ( url ) ;
//Range<double> currange{ *getFloatParameter(cpi_soundstart),*getFloatParameter(cpi_soundend) };
2018-01-30 15:32:23 +00:00
//if (currange.contains(m_stretch_source->getInfilePositionPercent())==false)
m_stretch_source - > seekPercent ( * getFloatParameter ( cpi_soundstart ) ) ;
2022-04-13 17:48:09 +00:00
m_current_file = url ;
# if JUCE_IOS
if ( void * bookmark = getURLBookmark ( m_current_file ) ) {
DBG ( " Loaded audio file has bookmark " ) ;
}
# endif
m_current_file_date = file . getLastModificationTime ( ) ;
2017-11-20 22:39:07 +00:00
m_using_memory_buffer = false ;
2018-02-07 14:00:49 +00:00
setDirty ( ) ;
2017-11-20 22:39:07 +00:00
return String ( ) ;
}
2022-04-13 17:48:09 +00:00
return " Could not open file " + file . getFullPathName ( ) ;
2017-11-14 16:14:14 +00:00
}
2017-11-16 14:58:04 +00:00
Range < double > PaulstretchpluginAudioProcessor : : getTimeSelection ( )
{
2017-12-14 17:57:14 +00:00
return { * getFloatParameter ( cpi_soundstart ) , * getFloatParameter ( cpi_soundend ) } ;
2017-11-16 14:58:04 +00:00
}
2017-11-20 22:39:07 +00:00
double PaulstretchpluginAudioProcessor : : getPreBufferingPercent ( )
{
if ( m_buffering_source = = nullptr )
return 0.0 ;
2018-05-01 15:22:21 +00:00
return m_smoothed_prebuffer_ready ;
2017-11-20 22:39:07 +00:00
}
2017-12-13 16:30:09 +00:00
void PaulstretchpluginAudioProcessor : : timerCallback ( int id )
{
if ( id = = 1 )
{
2018-11-08 19:48:51 +00:00
bool capture = * getBoolParameter ( cpi_capture_trigger ) ;
2017-12-18 17:48:40 +00:00
if ( capture = = false & & m_max_reclen ! = * getFloatParameter ( cpi_max_capture_len ) )
{
m_max_reclen = * getFloatParameter ( cpi_max_capture_len ) ;
//Logger::writeToLog("Changing max capture len to " + String(m_max_reclen));
}
2022-04-24 22:11:57 +00:00
if ( capture = = true & & m_is_recording_pending = = false & & ! m_is_recording_finished )
2017-12-13 16:30:09 +00:00
{
2022-04-24 22:11:57 +00:00
DBG ( " start recording " ) ;
2022-06-14 23:11:57 +00:00
setInputRecordingEnabled ( true ) ;
2017-12-13 16:30:09 +00:00
return ;
}
2022-04-24 22:11:57 +00:00
if ( capture = = false & & m_is_recording_pending = = true & & ! m_is_recording_finished )
2017-12-13 16:30:09 +00:00
{
2022-04-24 22:11:57 +00:00
DBG ( " stop recording " ) ;
2022-06-14 23:11:57 +00:00
setInputRecordingEnabled ( false ) ;
2017-12-13 16:30:09 +00:00
return ;
}
2022-04-22 03:04:30 +00:00
2022-04-24 22:11:57 +00:00
bool loopcommit = false ;
2022-04-22 03:04:30 +00:00
if ( m_is_recording_finished ) {
DBG ( " Recording is actually done, commit the finish " ) ;
int lenbufframes = getSampleRateChecked ( ) * m_max_reclen ;
finishRecording ( lenbufframes ) ;
2022-04-24 22:11:57 +00:00
* getBoolParameter ( cpi_capture_trigger ) = false ; // ensure it
}
else if ( m_is_recording & & loopcommit & & m_rec_count > m_next_rec_count ) {
DBG ( " Recording commit loop: " < < m_rec_count < < " next: " < < m_next_rec_count ) ;
int lenbufframes = getSampleRateChecked ( ) * m_max_reclen ;
commitRecording ( lenbufframes ) ;
m_next_rec_count + = lenbufframes ;
2022-04-22 03:04:30 +00:00
}
2022-04-24 22:11:57 +00:00
2017-12-13 22:44:46 +00:00
if ( m_cur_num_out_chans ! = * m_outchansparam )
{
2017-12-14 17:06:26 +00:00
jassert ( m_curmaxblocksize > 0 ) ;
2017-12-13 22:44:46 +00:00
ScopedLock locker ( m_cs ) ;
2017-12-27 15:35:30 +00:00
m_prebuffering_inited = false ;
2017-12-13 22:44:46 +00:00
m_cur_num_out_chans = * m_outchansparam ;
//Logger::writeToLog("Switching to use " + String(m_cur_num_out_chans) + " out channels");
String err ;
startplay ( { * getFloatParameter ( cpi_soundstart ) , * getFloatParameter ( cpi_soundend ) } ,
2017-12-14 17:06:26 +00:00
m_cur_num_out_chans , m_curmaxblocksize , err ) ;
2017-12-27 15:35:30 +00:00
m_prebuffering_inited = true ;
2017-12-13 22:44:46 +00:00
}
2017-12-13 16:30:09 +00:00
}
}
2018-09-26 16:19:10 +00:00
void PaulstretchpluginAudioProcessor : : setAudioPreview ( AudioFilePreviewComponent * afpc )
{
ScopedLock locker ( m_cs ) ;
m_previewcomponent = afpc ;
}
2018-04-25 12:25:29 +00:00
pointer_sized_int PaulstretchpluginAudioProcessor : : handleVstPluginCanDo ( int32 index , pointer_sized_int value , void * ptr , float opt )
{
if ( strcmp ( ( char * ) ptr , " xenakios " ) = = 0 )
{
2018-04-26 11:01:46 +00:00
if ( index = = 0 & & ( void * ) value ! = nullptr )
2018-04-25 12:25:29 +00:00
{
double t0 = * getFloatParameter ( cpi_soundstart ) ;
double t1 = * getFloatParameter ( cpi_soundend ) ;
2018-04-26 11:01:46 +00:00
double outlen = ( t1 - t0 ) * m_stretch_source - > getInfileLengthSeconds ( ) * ( * getFloatParameter ( cpi_stretchamount ) ) ;
//std::cout << "host requested output length, result " << outlen << "\n";
* ( ( double * ) value ) = outlen ;
2018-04-25 12:25:29 +00:00
}
if ( index = = 1 & & ( void * ) value ! = nullptr )
{
String fn ( CharPointer_UTF8 ( ( char * ) value ) ) ;
2018-04-26 11:01:46 +00:00
//std::cout << "host requested to set audio file " << fn << "\n";
2022-04-13 17:48:09 +00:00
auto err = setAudioFile ( URL ( fn ) ) ;
2018-04-26 11:01:46 +00:00
if ( err . isEmpty ( ) = = false )
std : : cout < < err < < " \n " ;
2018-04-25 12:25:29 +00:00
}
return 1 ;
}
return pointer_sized_int ( ) ;
}
pointer_sized_int PaulstretchpluginAudioProcessor : : handleVstManufacturerSpecific ( int32 index , pointer_sized_int value , void * ptr , float opt )
{
return pointer_sized_int ( ) ;
}
2022-04-24 22:11:57 +00:00
void PaulstretchpluginAudioProcessor : : commitRecording ( int lenrecording )
{
m_current_file = URL ( ) ;
auto currpos = m_stretch_source - > getLastSeekPos ( ) ;
m_stretch_source - > setAudioBufferAsInputSource ( & m_recbuffer , getSampleRateChecked ( ) , lenrecording ) ;
//m_stretch_source->seekPercent(currpos);
* getFloatParameter ( cpi_soundstart ) = 0.0f ;
* getFloatParameter ( cpi_soundend ) = jlimit < double > ( 0.01 , 1.0 , ( 1.0 / lenrecording ) * m_rec_count ) ;
}
void PaulstretchpluginAudioProcessor : : finishRecording ( int lenrecording , bool nosave )
2017-11-13 21:42:13 +00:00
{
2022-04-22 03:04:30 +00:00
m_is_recording_finished = false ;
m_is_recording_pending = false ;
2022-04-13 17:48:09 +00:00
m_current_file = URL ( ) ;
2017-12-17 16:16:39 +00:00
m_stretch_source - > setAudioBufferAsInputSource ( & m_recbuffer , getSampleRateChecked ( ) , lenrecording ) ;
2018-06-05 18:11:17 +00:00
* getFloatParameter ( cpi_soundstart ) = 0.0f ;
2022-04-24 22:11:57 +00:00
* getFloatParameter ( cpi_soundend ) = jlimit < double > ( 0.01 , 1.0 , ( 1.0 / lenrecording ) * m_rec_count ) ;
if ( nosave = = false & & m_save_captured_audio = = true )
2018-12-19 13:16:30 +00:00
{
saveCaptureBuffer ( ) ;
}
2017-11-13 21:42:13 +00:00
}
2022-06-14 23:11:57 +00:00
bool PaulstretchpluginAudioProcessor : : startRecordingToFile ( File & file , RecordFileFormat fileformat )
{
if ( ! m_recordingThread ) {
m_recordingThread = std : : make_unique < TimeSliceThread > ( " Recording Thread " ) ;
m_recordingThread - > startThread ( ) ;
}
stopRecordingToFile ( ) ;
bool ret = false ;
// Now create a WAV writer object that writes to our output stream...
//WavAudioFormat audioFormat;
std : : unique_ptr < AudioFormat > audioFormat ;
std : : unique_ptr < AudioFormat > wavAudioFormat ;
int qualindex = 0 ;
int bitsPerSample = std : : min ( 32 , m_defaultRecordingBitsPerSample ) ;
if ( getSampleRate ( ) < = 0 )
{
return false ;
}
File usefile = file ;
if ( fileformat = = FileFormatDefault ) {
fileformat = m_defaultRecordingFormat ;
}
m_totalRecordingChannels = getMainBusNumOutputChannels ( ) ;
if ( m_totalRecordingChannels = = 0 ) {
m_totalRecordingChannels = 2 ;
}
if ( fileformat = = FileFormatFLAC & & m_totalRecordingChannels > 8 ) {
// flac doesn't support > 8 channels
fileformat = FileFormatWAV ;
}
if ( fileformat = = FileFormatFLAC | | ( fileformat = = FileFormatAuto & & file . getFileExtension ( ) . toLowerCase ( ) = = " .flac " ) ) {
audioFormat = std : : make_unique < FlacAudioFormat > ( ) ;
bitsPerSample = std : : min ( 24 , bitsPerSample ) ;
usefile = file . withFileExtension ( " .flac " ) ;
}
else if ( fileformat = = FileFormatWAV | | ( fileformat = = FileFormatAuto & & file . getFileExtension ( ) . toLowerCase ( ) = = " .wav " ) ) {
audioFormat = std : : make_unique < WavAudioFormat > ( ) ;
usefile = file . withFileExtension ( " .wav " ) ;
}
else if ( fileformat = = FileFormatOGG | | ( fileformat = = FileFormatAuto & & file . getFileExtension ( ) . toLowerCase ( ) = = " .ogg " ) ) {
audioFormat = std : : make_unique < OggVorbisAudioFormat > ( ) ;
qualindex = 8 ; // 256k
usefile = file . withFileExtension ( " .ogg " ) ;
}
else {
m_lastError = TRANS ( " Could not find format for filename " ) ;
DBG ( m_lastError ) ;
return false ;
}
bool userwriting = false ;
// Create an OutputStream to write to our destination file...
usefile . deleteFile ( ) ;
if ( auto fileStream = std : : unique_ptr < FileOutputStream > ( usefile . createOutputStream ( ) ) )
{
if ( auto writer = audioFormat - > createWriterFor ( fileStream . get ( ) , getSampleRate ( ) , m_totalRecordingChannels , bitsPerSample , { } , qualindex ) )
{
fileStream . release ( ) ; // (passes responsibility for deleting the stream to the writer object that is now using it)
// Now we'll create one of these helper objects which will act as a FIFO buffer, and will
// write the data to disk on our background thread.
m_threadedMixWriter . reset ( new AudioFormatWriter : : ThreadedWriter ( writer , * m_recordingThread , 65536 ) ) ;
DBG ( " Started recording only mix file " < < usefile . getFullPathName ( ) ) ;
file = usefile ;
ret = true ;
} else {
m_lastError . clear ( ) ;
m_lastError < < TRANS ( " Error creating writer for " ) < < usefile . getFullPathName ( ) ;
DBG ( m_lastError ) ;
}
} else {
m_lastError . clear ( ) ;
m_lastError < < TRANS ( " Error creating output file: " ) < < usefile . getFullPathName ( ) ;
DBG ( m_lastError ) ;
}
if ( ret ) {
// And now, swap over our active writer pointers so that the audio callback will start using it..
const ScopedLock sl ( m_writerLock ) ;
m_elapsedRecordSamples = 0 ;
m_activeMixWriter = m_threadedMixWriter . get ( ) ;
m_writingPossible . store ( m_activeMixWriter ) ;
//DBG("Started recording file " << usefile.getFullPathName());
}
return ret ;
}
bool PaulstretchpluginAudioProcessor : : stopRecordingToFile ( )
{
// First, clear this pointer to stop the audio callback from using our writer object..
{
const ScopedLock sl ( m_writerLock ) ;
m_activeMixWriter = nullptr ;
m_writingPossible . store ( false ) ;
}
bool didit = false ;
if ( m_threadedMixWriter ) {
// Now we can delete the writer object. It's done in this order because the deletion could
// take a little time while remaining data gets flushed to disk, and we can't be blocking
// the audio callback while this happens.
m_threadedMixWriter . reset ( ) ;
DBG ( " Stopped recording mix file " ) ;
didit = true ;
}
return didit ;
}
bool PaulstretchpluginAudioProcessor : : isRecordingToFile ( )
{
return ( m_activeMixWriter . load ( ) ! = nullptr ) ;
}
2017-11-13 15:06:08 +00:00
AudioProcessor * JUCE_CALLTYPE createPluginFilter ( )
{
return new PaulstretchpluginAudioProcessor ( ) ;
}