Dealing with 1st block/buffer, old sample, last buffer


#1

Friendly greetings !

The context is a VST audio plugin.

I’m dealing with an algorithm that, in an ideal world, edit block in the future.
It goes with saying that i cause a “little” problem at the end of a buffer :smiley:

Soo… i store N sample in N registers, and instead of modifying future data depending of current data, i modify current data depending ot old data stored in the N registers.
And when the next buffer come, i have the last N sample of the previous buffer in my N register and everyone can live happily ever after !

It create latency, it seems to be the way to go but it create a new kind of problem.

  • The very first block need special care (as the registers contain undefined data). How do you handle this “first buffer special case” ?
  • how to deal with pause, seek, restart or anything that make the N registers obsolete ?
  • i came up with this idea of storing data in registers to avoid editing future sample all by myself, i maybe be totally wrong about it ! If so… what’s the way to go please ?

i have trouble finding vst source code that include algorithm that need to access more than the current sample.

Bonus question : the basic template deal with the entire buffer of 1st channel, then process the 2nd channel.
Is there any inconvenient in editing both channel at the same time ?

template :

  • channel1 sample 1, channel1 sample2, …, channel1 sample N ;
  • channel2 sample 1, channel2 sample 2 …, channel2 sample N. ;

both at the same time :

  • channel1 sample 1, channel2 sample1;
  • channel1 sample 2, channel2 sample2;
  • …;
  • channel1 sample N, channel2 sample N.

thank you <3


#2

I think, initialising in prepareToPlay with zero should do? What I tend to do is, to save, if I was bypassed the last run and fade in, if the state just changed. I don’t think, there is a reliable way to tell, if the signal jumped. More and more hosts start that uncomfortable behaviour not to call processBlock, whenever the host thinks it is expendable (this differs from many plugin developers point of view, me included). There is the AudioPlayHead struct (by calling AudioProcessor::getPlayHead()), you can track the information of that, but I am not sure, if this gives reliable results over all hosts…

The CPU will not appreciate that, because it has to jump between the arrays. So there might be a cache penalty for doing so. You should try to avoid that jumps, but it is possible to do. YMMV.


#3

Thx for the answer.

Considering the lack of reaction, may i assume that my way of dealing with the problem of modifying samples isn’t incorrect ?


#4

Well, it is Sunday evening, and it was just one hour… :wink: I am also not sure, if I understood every detail of your question. Seems a bit vague to me…
But I would say, go and try. It doesn’t sound stupid to me at all. But if it works or not, you will find out.


#5

well, you didn’t jumpscare at me shouting “OMG YOU IDIOT!!”, that’s why i immediately assumed i was a genius :wink:

As for testing… a few hours ago i had a few glitch to fix (due the buffer block) and now all i get is garbage noise destroying my eardrum. I’m trying to fix it :smiley:


#6
		channelData = buffer.getWritePointer(1);
	
	out_lp_20 = a0_lp + channelData[0] + a1_lp * channelData[1] + a2_lp * channelData[2] - b1_lp * channelData[3] - b2_lp * channelData[4];
	mem_lp_22 = channelData[1];
	mem_lp_21 = channelData[0];
	mem_lp_24 = channelData[3];
	mem_lp_23 = out_lp_20;

	// ..do something to the data...
	for (int sample = 1; sample < buffer.getNumSamples(); sample++) {
		//do something with samples
		out_lp_20 = a0_lp + out_lp_20 + a1_lp * mem_lp_21 + a2_lp * mem_lp_22 - b1_lp * mem_lp_23 - b2_lp * mem_lp_24;
		mem_lp_22 = mem_lp_21;
		mem_lp_21 = channelData[sample];
		mem_lp_24 = mem_lp_23;
		mem_lp_23 = out_lp_20;
		channelData[sample] = out_lp_20;
	}

Something horribly wrong is hidden in this code.

EDIT : OMG GetSampleRate() doesn’t works in PrepareToPlay !! That was my main problem. But i butchered my code now … edit3 : disregard that… it’s provided in argument, i was being an idiot. but my garbage problem was related to this. Anyway, i still have artefact as mentioned in edit2.
EDIT2 : horribly wrongness fixed. when rewriting the code i put an addition instead of a multiplication : a0_lp + out_lp_20. Now i’m back to my regular buffer problem


#7

Something doesn’t works.
I have 2 methods of doing this, one of left channel, one on right channel.

Both produce different artifacts that seems to be very related to buffer size and therefore imply invalid data somewhere (at the beginning or end, dunno)


#8

The problem is obvious. The solution… i’m stuck ::frowning:


#9

i fixed it with this but i’m very unhappy with this solution

		if (isFirstBuffer) {
		out_lp_10 = a0_lp * channelData[0] + a1_lp * channelData[1] + a2_lp * channelData[2] - b1_lp * channelData[3] - b2_lp * channelData[4];
		mem_lp_12 = channelData[1];
		mem_lp_11 = channelData[0];
		mem_lp_14 = channelData[3];
		mem_lp_13 = out_lp_10;
		isFirstBuffer = false;
	}

	// ..do something to the data...
	for (int sample = 0; sample < buffer.getNumSamples(); sample++) {
		//do something with samples
		out_lp_10 = a0_lp * out_lp_10 + a1_lp * mem_lp_11 + a2_lp * mem_lp_12 - b1_lp * mem_lp_13 - b2_lp * mem_lp_14;
		mem_lp_12 = mem_lp_11;
		mem_lp_11 = channelData[sample];
		mem_lp_14 = mem_lp_13;
		mem_lp_13 = out_lp_10;
		channelData[sample] = out_lp_10;
	}