Another coding question... (about echoing)

DSP, Plugin and Host development discussion.
Post Reply New Topic
RELATED
PRODUCTS

Post

I know I had another topic just going.. so please forgive me for being such a pain.

Anyways... I'm trying to allow a user to have control over the number of echoes that should be heard.

So... I have a buffer for "delayed" samples, but I though maybe I would have another array which would keep track of how many times each buffered sample gets played.

Then, if the number of times some sample has been "echoed" passes some user-defined limit, then I wouldn't echo the sample again.

I'm not the best at coming up with algorithms... so I would appreciate any feedback as to whether I'm going in the right direction or not.

Thanks for your patience with me!

Post

If I were to write an echo plugin, this is the basic algorithm I would use:

Code: Select all

while(--sampleFrames) {
  for(int i = 0; i < num_echos; i++) {
    buffer[buffer_index + (i * delay_time)] +=
      (*inputs) / num_echos;
  }
  buffer_index++;

  (*outputs++) = (*inputs++) + buffer[buffer_index];
}

Your algorithm isn't bad, but every ounce of CPU time counts in VST coding, so don't use extra memory or CPU cycles if you don't have to.

Hope this gives some food for thought. =)

Post

Thanks - i'll study your suggestion and get back to you.

Post

you'll need to wrap the buffer index or it will crash, and also clear the buffer just after reading from sa location.

also, yo must make sure that num_echos * delay does nopt exceed the buffer size.

Post

texture wrote:and also clear the buffer just after reading from sa location.
What do you mean by this exactly?

Post

This is what I'm working with so far... it's not working, but it's not crashing (at least).

Code: Select all

float curr = 0;
int delay_time = 1000;
int num_echoes = 5;
while (--sampleFrames >= 0)
{
		curr = (*in1++);

		int index = 0;
		for(int i=0; i < num_echoes; i++)
		{
			index = mCursor + (i * delay_time);
			if (index >= mSize)
				index %= mSize;

			mBuffer[index] += curr / (float)num_echoes;
		}
      mCursor++;

		if (mCursor >= mSize)
			mCursor = 0;

      (*out1++) = curr + mBuffer[mCursor];
	   (*out2++) = curr + mBuffer[mCursor];
}
mSize is 44100 in this case, and the buffer length is the same.

Post

what about this:

Code: Select all

#include <vector>

template <typename T>
class FixedEchoUnit
{
public:
	FixedEchoUnit(size_t size) 
	: buffer_(size, T(0))	// set to 'size' and initialise with '0'
	, feedback_(0)
	, index_(0)
	, repeats_(1)
	, delay_samples_(0)
	{
	}

	bool set_repeats(unsigned repeats);
	bool set_delay_samples(unsigned samples);
	void set_feedback(float feedback) { feedback_ = feedback; }

	inline unsigned get_repeats() const { return repeats_; }
	inline unsigned get_delay_samples() const { return delay_; }
	inline unsigned get_size() const { return buffer_.size(); }

	void process(T input, T& output);

private:
	typedef std::vector<T> buffer_type;
	typedef typename buffer_type::iterator iterator;

	inline size_t wrap(const size_t& v) const { return (v >= get_size()) ? (v - get_size()) : v; }

	inline bool check_valid_params(unsigned repeats, unsigned delay_samples) const {
		return ((repeats * delay_samples) <= buffer_.size());
	}

	buffer_type buffer_;
	T feedback_;
	size_t index_;
	unsigned repeats_;
	unsigned delay_samples_;
};

template <typename T>
inline void
FixedEchoUnit<T>::process(T input, T& output)
{
	output = buffer_[index_] + input;
	buffer_[index_] = 0;

	size_t idx = index_;
	unsigned echo = repeats_;

	while (echo-- > 0) {
        input *= feedback_;
		idx = wrap(idx + delay_samples_);
        buffer_[idx] += input;
	}

	index_ = wrap(++index_);
}

// returns false if the repeats value would have been invalid.
template <typename T>
inline bool
FixedEchoUnit<T>::set_repeats(unsigned repeats)
{
	bool r = false;

	if (check_valid_params(repeats, delay_samples_)) {
		repeats_ = repeats;
		r = true;
	}

	return r;
}


// returns false if the delay time would have been invalid.

template <typename T>
inline bool
FixedEchoUnit<T>::set_delay_samples(unsigned samples)
{
	bool r = false;

	if (check_valid_params(repeats_, samples)) {
		delay_samples_ = samples;
		r = true;
	}

	return r;
}


// in the plugin class
// you'll need to initialise them in the 
// initialisation list of the construtor 
// and then call set_delay, set_repeats
// and set_feedback to give them resaonable values.


	FixedEchoUnit<float> echo_left_;
	FixedEchoUnit<float> echo_right_;



// process replacing:

    while(--sampleFrames >= 0)
    {
		echo_left_.process(*in1, *out1);
		echo_right_.process(*in2, *out2);

		++in1;
		++in2;
		++out1;
		++out2;
    }



Post

I appreciate you trying to help - but I'm trying to agonize through this so I can wrap my head around it. Also, I'm doing it for a school assignment so I can't really copy your code anyways. I'll try to understand it though to see what's going on.

Thanks again.

Post

Finally!! I got it working!

Thanks for all of your input. I don't know what I'd do without this forum!

Post Reply

Return to “DSP and Plugin Development”