Attempt to do a crossfade when changing FFT size, using the same stretchsource instance. It's tricky and not really working yet like this.
This commit is contained in:
		@@ -14,6 +14,8 @@ StretchAudioSource::StretchAudioSource(int initialnumoutchans, AudioFormatManage
 | 
				
			|||||||
	m_inputfile = std::make_unique<AInputS>(m_afm);
 | 
						m_inputfile = std::make_unique<AInputS>(m_afm);
 | 
				
			||||||
	m_specproc_order = { 0,1,2,3,4,5,6,7 };
 | 
						m_specproc_order = { 0,1,2,3,4,5,6,7 };
 | 
				
			||||||
	setNumOutChannels(initialnumoutchans);
 | 
						setNumOutChannels(initialnumoutchans);
 | 
				
			||||||
 | 
						m_crossfadebuffer.setSize(initialnumoutchans, 65536);
 | 
				
			||||||
 | 
						m_crossfadebuffer.clear();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
StretchAudioSource::~StretchAudioSource()
 | 
					StretchAudioSource::~StretchAudioSource()
 | 
				
			||||||
@@ -56,7 +58,7 @@ std::vector<int> StretchAudioSource::getSpectrumProcessOrder()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void StretchAudioSource::setSpectrumProcessOrder(std::vector<int> order)
 | 
					void StretchAudioSource::setSpectrumProcessOrder(std::vector<int> order)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	std::lock_guard <std::mutex> locker(m_mutex);
 | 
						std::lock_guard <decltype(m_mutex)> locker(m_mutex);
 | 
				
			||||||
	m_specproc_order = order;
 | 
						m_specproc_order = order;
 | 
				
			||||||
	for (int i = 0; i < m_stretchers.size(); ++i)
 | 
						for (int i = 0; i < m_stretchers.size(); ++i)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -86,7 +88,7 @@ ValueTree StretchAudioSource::getStateTree()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void StretchAudioSource::setStateTree(ValueTree state)
 | 
					void StretchAudioSource::setStateTree(ValueTree state)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	std::lock_guard <std::mutex> locker(m_mutex);
 | 
						std::lock_guard <decltype(m_mutex)> locker(m_mutex);
 | 
				
			||||||
	getFromTreeProperties(state, "pitch_shift", m_ppar.pitch_shift.cents,
 | 
						getFromTreeProperties(state, "pitch_shift", m_ppar.pitch_shift.cents,
 | 
				
			||||||
		"octaves_minus2", m_ppar.octave.om2,
 | 
							"octaves_minus2", m_ppar.octave.om2,
 | 
				
			||||||
		"octaves_minus1", m_ppar.octave.om1,
 | 
							"octaves_minus1", m_ppar.octave.om1,
 | 
				
			||||||
@@ -109,7 +111,7 @@ bool StretchAudioSource::isLoopingEnabled()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void StretchAudioSource::setLoopingEnabled(bool b)
 | 
					void StretchAudioSource::setLoopingEnabled(bool b)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	std::lock_guard <std::mutex> locker(m_mutex);
 | 
						std::lock_guard <decltype(m_mutex)> locker(m_mutex);
 | 
				
			||||||
	if (m_inputfile != nullptr)
 | 
						if (m_inputfile != nullptr)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		m_inputfile->setLoopEnabled(b);
 | 
							m_inputfile->setLoopEnabled(b);
 | 
				
			||||||
@@ -118,7 +120,7 @@ void StretchAudioSource::setLoopingEnabled(bool b)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void StretchAudioSource::setAudioBufferAsInputSource(AudioBuffer<float>* buf, int sr, int len)
 | 
					void StretchAudioSource::setAudioBufferAsInputSource(AudioBuffer<float>* buf, int sr, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	std::lock_guard <std::mutex> locker(m_mutex);
 | 
						std::lock_guard <decltype(m_mutex)> locker(m_mutex);
 | 
				
			||||||
	m_inputfile->setAudioBuffer(buf, sr, len);
 | 
						m_inputfile->setAudioBuffer(buf, sr, len);
 | 
				
			||||||
	m_seekpos = 0.0;
 | 
						m_seekpos = 0.0;
 | 
				
			||||||
	m_lastinpos = 0.0;
 | 
						m_lastinpos = 0.0;
 | 
				
			||||||
@@ -130,7 +132,7 @@ void StretchAudioSource::setAudioBufferAsInputSource(AudioBuffer<float>* buf, in
 | 
				
			|||||||
void StretchAudioSource::getNextAudioBlock(const AudioSourceChannelInfo & bufferToFill)
 | 
					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...
 | 
						// for realtime play, this is assumed to be used with BufferingAudioSource, so mutex locking should not be too bad...
 | 
				
			||||||
	std::lock_guard <std::mutex> locker(m_mutex);
 | 
						std::lock_guard <decltype(m_mutex)> locker(m_mutex);
 | 
				
			||||||
	if (m_stretchoutringbuf.available() > 0)
 | 
						if (m_stretchoutringbuf.available() > 0)
 | 
				
			||||||
		m_output_has_begun = true;
 | 
							m_output_has_begun = true;
 | 
				
			||||||
	bool freezing = m_freezing;
 | 
						bool freezing = m_freezing;
 | 
				
			||||||
@@ -256,10 +258,21 @@ void StretchAudioSource::getNextAudioBlock(const AudioSourceChannelInfo & buffer
 | 
				
			|||||||
		for (int j = 0; j < outbufchans; ++j)
 | 
							for (int j = 0; j < outbufchans; ++j)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			double outsample = m_resampler_outbuf[i*m_num_outchans + j];
 | 
								double outsample = m_resampler_outbuf[i*m_num_outchans + j];
 | 
				
			||||||
 | 
								if (m_is_crossfading == true)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									jassert(m_crossfade_len > 0);
 | 
				
			||||||
 | 
									jassert(m_crossfade_counter >= 0 && m_crossfade_counter < m_crossfade_len);
 | 
				
			||||||
 | 
									double xfadegain = 1.0 / m_crossfade_len * m_crossfade_counter;
 | 
				
			||||||
 | 
									jassert(xfadegain >= 0.0 && xfadegain <= 1.0);
 | 
				
			||||||
 | 
									double outsample2 = m_crossfadebuffer.getSample(j, m_crossfade_counter);
 | 
				
			||||||
 | 
									outsample = (1.0 - xfadegain)*outsample2 + xfadegain * outsample;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			outarrays[j][i + offset] = jlimit(-samplelimit,samplelimit , outsample * smoothed_gain);
 | 
								outarrays[j][i + offset] = jlimit(-samplelimit,samplelimit , outsample * smoothed_gain);
 | 
				
			||||||
			mixed += outsample;
 | 
								mixed += outsample;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							++m_crossfade_counter;
 | 
				
			||||||
 | 
							if (m_crossfade_counter >= m_crossfade_len)
 | 
				
			||||||
 | 
								m_is_crossfading = false;
 | 
				
			||||||
		if (source_ended && m_output_counter>=2*m_process_fftsize)
 | 
							if (source_ended && m_output_counter>=2*m_process_fftsize)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (fabs(mixed) < silencethreshold)
 | 
								if (fabs(mixed) < silencethreshold)
 | 
				
			||||||
@@ -297,7 +310,7 @@ bool StretchAudioSource::isLooping() const
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
String StretchAudioSource::setAudioFile(File file)
 | 
					String StretchAudioSource::setAudioFile(File file)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	std::lock_guard <std::mutex> locker(m_mutex);
 | 
						std::lock_guard <decltype(m_mutex)> locker(m_mutex);
 | 
				
			||||||
	if (m_inputfile->openAudioFile(file))
 | 
						if (m_inputfile->openAudioFile(file))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		m_curfile = file;
 | 
							m_curfile = file;
 | 
				
			||||||
@@ -319,7 +332,7 @@ void StretchAudioSource::setNumOutChannels(int chans)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void StretchAudioSource::initObjects()
 | 
					void StretchAudioSource::initObjects()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	std::lock_guard<std::mutex> locker(m_mutex);
 | 
						std::lock_guard <decltype(m_mutex)> locker(m_mutex);
 | 
				
			||||||
	m_inputfile->setActiveRange(m_playrange);
 | 
						m_inputfile->setActiveRange(m_playrange);
 | 
				
			||||||
	m_inputfile->seek(m_seekpos);
 | 
						m_inputfile->seek(m_seekpos);
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
@@ -389,7 +402,7 @@ void StretchAudioSource::setRate(double rate)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (rate == m_playrate)
 | 
						if (rate == m_playrate)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	std::lock_guard<std::mutex> locker(m_mutex);
 | 
						std::lock_guard <decltype(m_mutex)> locker(m_mutex);
 | 
				
			||||||
	//if (rate != m_lastplayrate)
 | 
						//if (rate != m_lastplayrate)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		//m_output_counter = m_output_counter*rate;
 | 
							//m_output_counter = m_output_counter*rate;
 | 
				
			||||||
@@ -408,7 +421,7 @@ void StretchAudioSource::setProcessParameters(ProcessParameters * pars)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (*pars == m_ppar)
 | 
						if (*pars == m_ppar)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	std::lock_guard<std::mutex> locker(m_mutex);
 | 
						std::lock_guard <decltype(m_mutex)> locker(m_mutex);
 | 
				
			||||||
	m_ppar = *pars;
 | 
						m_ppar = *pars;
 | 
				
			||||||
	for (int i = 0; i < m_stretchers.size(); ++i)
 | 
						for (int i = 0; i < m_stretchers.size(); ++i)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -426,7 +439,7 @@ void StretchAudioSource::setFFTWindowingType(int windowtype)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    if (windowtype==m_fft_window_type)
 | 
					    if (windowtype==m_fft_window_type)
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    std::lock_guard<std::mutex> locker(m_mutex);
 | 
						std::lock_guard <decltype(m_mutex)> locker(m_mutex);
 | 
				
			||||||
    m_fft_window_type = windowtype;
 | 
					    m_fft_window_type = windowtype;
 | 
				
			||||||
    for (int i = 0; i < m_stretchers.size(); ++i)
 | 
					    for (int i = 0; i < m_stretchers.size(); ++i)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -439,6 +452,39 @@ void StretchAudioSource::setFFTSize(int size)
 | 
				
			|||||||
    jassert(size>0);
 | 
					    jassert(size>0);
 | 
				
			||||||
    if (m_process_fftsize == 0 || size != m_process_fftsize)
 | 
					    if (m_process_fftsize == 0 || size != m_process_fftsize)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							std::lock_guard <decltype(m_mutex)> locker(m_mutex);
 | 
				
			||||||
 | 
							if (m_crossfadebuffer.getNumChannels() < m_num_outchans)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								m_crossfadebuffer.setSize(m_num_outchans, m_crossfadebuffer.getNumSamples());
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (m_process_fftsize > 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								double curpos = getInfilePositionPercent();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								m_crossfade_len = m_crossfade_requested_len; //std::min(m_stretchoutringbuf.available() / m_num_outchans, m_crossfade_len);
 | 
				
			||||||
 | 
								m_is_crossfading = false;
 | 
				
			||||||
 | 
								m_crossfadebuffer.clear();
 | 
				
			||||||
 | 
								int sampstofill = std::min(m_crossfade_requested_len, m_stretchoutringbuf.available() / m_num_outchans);
 | 
				
			||||||
 | 
								for (int i = 0; i < sampstofill; ++i)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									for (int j = 0; j < m_num_outchans; ++j)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										m_crossfadebuffer.setSample(j, i, m_stretchoutringbuf.get());
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								m_crossfade_len = sampstofill;
 | 
				
			||||||
 | 
								Logger::writeToLog("crossfade len " + String(m_crossfade_len));
 | 
				
			||||||
 | 
								//AudioSourceChannelInfo aif(&m_crossfadebuffer,0,m_crossfade_len);
 | 
				
			||||||
 | 
								//getNextAudioBlock(aif);
 | 
				
			||||||
 | 
								m_crossfade_counter = 0;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								m_is_crossfading = true;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//m_seekpos = curpos;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
		m_process_fftsize = size;
 | 
							m_process_fftsize = size;
 | 
				
			||||||
		initObjects();
 | 
							initObjects();
 | 
				
			||||||
		++m_param_change_count;
 | 
							++m_param_change_count;
 | 
				
			||||||
@@ -447,7 +493,7 @@ void StretchAudioSource::setFFTSize(int size)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void StretchAudioSource::seekPercent(double pos)
 | 
					void StretchAudioSource::seekPercent(double pos)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	std::lock_guard<std::mutex> locker(m_mutex);
 | 
						std::lock_guard <decltype(m_mutex)> locker(m_mutex);
 | 
				
			||||||
	m_seekpos = pos;
 | 
						m_seekpos = pos;
 | 
				
			||||||
	m_inputfile->seek(pos);
 | 
						m_inputfile->seek(pos);
 | 
				
			||||||
	m_lastinpos = pos;
 | 
						m_lastinpos = pos;
 | 
				
			||||||
@@ -463,7 +509,7 @@ double StretchAudioSource::getOutputDurationSecondsForRange(Range<double> range,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void StretchAudioSource::setOnsetDetection(double x)
 | 
					void StretchAudioSource::setOnsetDetection(double x)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	std::lock_guard<std::mutex> locker(m_mutex);
 | 
						std::lock_guard <decltype(m_mutex)> locker(m_mutex);
 | 
				
			||||||
	m_onsetdetection = x;
 | 
						m_onsetdetection = x;
 | 
				
			||||||
	for (int i = 0; i < m_stretchers.size(); ++i)
 | 
						for (int i = 0; i < m_stretchers.size(); ++i)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -475,7 +521,7 @@ void StretchAudioSource::setPlayRange(Range<double> playrange, bool isloop)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (m_playrange.isEmpty() == false && playrange == m_playrange)
 | 
						if (m_playrange.isEmpty() == false && playrange == m_playrange)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	std::lock_guard<std::mutex> locker(m_mutex);
 | 
						std::lock_guard <decltype(m_mutex)> locker(m_mutex);
 | 
				
			||||||
	if (playrange.isEmpty())
 | 
						if (playrange.isEmpty())
 | 
				
			||||||
		m_playrange = { 0.0,1.0 };
 | 
							m_playrange = { 0.0,1.0 };
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -123,7 +123,7 @@ private:
 | 
				
			|||||||
	int64_t m_maxloops = 0;
 | 
						int64_t m_maxloops = 0;
 | 
				
			||||||
	std::unique_ptr<WDL_Resampler> m_resampler;
 | 
						std::unique_ptr<WDL_Resampler> m_resampler;
 | 
				
			||||||
	std::vector<double> m_resampler_outbuf;
 | 
						std::vector<double> m_resampler_outbuf;
 | 
				
			||||||
	std::mutex m_mutex;
 | 
						std::recursive_mutex m_mutex;
 | 
				
			||||||
	std::vector<int> m_specproc_order;
 | 
						std::vector<int> m_specproc_order;
 | 
				
			||||||
	bool m_stop_play_requested = false;
 | 
						bool m_stop_play_requested = false;
 | 
				
			||||||
	double m_freeze_pos = 0.0;
 | 
						double m_freeze_pos = 0.0;
 | 
				
			||||||
@@ -132,6 +132,11 @@ private:
 | 
				
			|||||||
	bool m_clip_output = true;
 | 
						bool m_clip_output = true;
 | 
				
			||||||
	void initObjects();
 | 
						void initObjects();
 | 
				
			||||||
	AudioFormatManager* m_afm = nullptr;
 | 
						AudioFormatManager* m_afm = nullptr;
 | 
				
			||||||
 | 
						std::atomic<bool> m_is_crossfading{ false };
 | 
				
			||||||
 | 
						AudioBuffer<float> m_crossfadebuffer;
 | 
				
			||||||
 | 
						int m_crossfade_requested_len = 8192;
 | 
				
			||||||
 | 
						int m_crossfade_len = 0;
 | 
				
			||||||
 | 
						int m_crossfade_counter = 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MultiStretchAudioSource final : public PositionableAudioSource
 | 
					class MultiStretchAudioSource final : public PositionableAudioSource
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -86,7 +86,7 @@
 | 
				
			|||||||
                       headerPath="Source/PS_Source
Source/WDL
" vstBinaryLocation="C:\VSTPlugins_64bit"/>
 | 
					                       headerPath="Source/PS_Source
Source/WDL
" vstBinaryLocation="C:\VSTPlugins_64bit"/>
 | 
				
			||||||
        <CONFIGURATION name="Release" winWarningLevel="4" generateManifest="1" winArchitecture="x64"
 | 
					        <CONFIGURATION name="Release" winWarningLevel="4" generateManifest="1" winArchitecture="x64"
 | 
				
			||||||
                       debugInformationFormat="ProgramDatabase" enablePluginBinaryCopyStep="1"
 | 
					                       debugInformationFormat="ProgramDatabase" enablePluginBinaryCopyStep="1"
 | 
				
			||||||
                       linkTimeOptimisation="1" isDebug="0" optimisation="3" targetName="paulstretchplugin"
 | 
					                       linkTimeOptimisation="0" isDebug="0" optimisation="3" targetName="paulstretchplugin"
 | 
				
			||||||
                       headerPath="Source/PS_Source
Source/WDL
" vstBinaryLocation="C:\VSTPlugins_64bit"/>
 | 
					                       headerPath="Source/PS_Source
Source/WDL
" vstBinaryLocation="C:\VSTPlugins_64bit"/>
 | 
				
			||||||
      </CONFIGURATIONS>
 | 
					      </CONFIGURATIONS>
 | 
				
			||||||
      <MODULEPATHS>
 | 
					      <MODULEPATHS>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user