XHip--Please finish your synth!!
-
AdmiralQuality AdmiralQuality https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=83902
- Banned
- 6657 posts since 10 Oct, 2005 from Toronto, Canada
Yes I said it backwards. But I meant it the way you have it, deprecated process function acting as the payload of processReplacing.aciddose wrote:"By encasing processReplacing inside process"
i said:
"i think you've got this backwards."
you DO have this backwards!
- KVRAF
- 12615 posts since 7 Dec, 2004
"you're adding an unnecessary memset (because all those values would get written anyway, no need to initialize them) and an unnecessary addition for each sample. Sure, it's not a lot of time, but it's infinitely more than zero operations."
if you'll consider the fact that there is more than one mixing pass at all times, the only operation possible is accumulation. it isnt possible (without as i said maintaining a redundant mix buffer) to use a copy rather than accumulate.
if your synth works without mixing, i'd be very interested to see how
actually you're not thinking clearly because in your synth you do have a seperate mix buffer which you use for decimation. you most likely have several buffers that you use. i only ever touch the buffer supplied by the host, there are no internal buffers in xhip.
if you'll consider the fact that there is more than one mixing pass at all times, the only operation possible is accumulation. it isnt possible (without as i said maintaining a redundant mix buffer) to use a copy rather than accumulate.
if your synth works without mixing, i'd be very interested to see how
actually you're not thinking clearly because in your synth you do have a seperate mix buffer which you use for decimation. you most likely have several buffers that you use. i only ever touch the buffer supplied by the host, there are no internal buffers in xhip.
-
AdmiralQuality AdmiralQuality https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=83902
- Banned
- 6657 posts since 10 Oct, 2005 from Toronto, Canada
That accumulation is AFTER your process, whatever it does, and is meant to accumulate into the host's buffer. Say for an obsolete kind of send return bus, all the send effects would process (accumulating) into that bus, so that each effect did a += into the buffer, rather than the host having to applying mixing after the fact. I don't know exactly when this was called really, it's from a much older VST rev, but again, I've never seen a host call process().
These days, everything is inline and the mixing is explicit. processReplacing() IS the one that's called, and it's called "replacing" because it writes on the buffer, replacing whatever was in it (contents undefined and safe to write on).
It's just plain faster, you're being stubborn and silly again. No memset vs memset? += vs =? PER SAMPLE. It's real work and it adds up.
These days, everything is inline and the mixing is explicit. processReplacing() IS the one that's called, and it's called "replacing" because it writes on the buffer, replacing whatever was in it (contents undefined and safe to write on).
It's just plain faster, you're being stubborn and silly again. No memset vs memset? += vs =? PER SAMPLE. It's real work and it adds up.
-
AdmiralQuality AdmiralQuality https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=83902
- Banned
- 6657 posts since 10 Oct, 2005 from Toronto, Canada
I'm just in the habit of copying the entire function body of processReplacing into process right before a final build and changing the = to +=.VST 2.3 SDK docs wrote: process
virtual void process (float **inputs, float **outputs, long sampleFrames);
Audio processing in the plug is accomplished by one of 2 methods, namely process, and processReplacing. The process method must be provided, while the second one is optional (but it is highly recommended to always implement both methods). While process takes input data, applies its pocessing algorithm, and then adds the result to the output (accumulating), processReplacing overwrites the output buffer. The host provides both input and output buffers for either process method.
The reasoning behind the accumulating version (process) is that it is much more efficient in the case where many processors operate on the same output (aux-send bus), while for simple chained connection schemes (inserts), the replacing method is more efficient.
The plug has to over-ride both these two possible member functions that actually do the work. These are repeatedly called by the host application, each time with a new block of data.
inputs An array of pointers to the data.
outputsuts An array of pointers to where the datacan be written to.
sampleFrames How big the block is.
processReplacing
virtual void processReplacing (float **inputs, float **outputs, long sampleFrames);
Audio processing in the plug is accomplished by one of 2 methods, namely process, and processReplacing. The process method must be provided, while the second one is optional (but it is highly recommended to always implement both methods). While process takes input data, applies its pocessing algorithm, and then adds the result to the output (accumulating), processReplacing overwrites the output buffer. The host provides both input and output buffers for either process method.
The reasoning behind the accumulating version (process) is that it is much more efficient in the case where many processors operate on the same output (aux-send bus), while for simple chained connection schemes (inserts), the replacing method is more efficient.
inputs An array of pointers to the data.
outputsuts An array of pointers to where the datacan be written to.
sampleFrames How big the block is.
I see no reason NOT to include process() anyway, but processReplacing should be considered the "main" (like, most often used) one.VST 2.4 SDK docs wrote: AEffectProcessProc AEffect::process
Deprecated:
Accumulating process mode is deprecated in VST 2.4! Use AEffect::processReplacing instead!
- KVRAF
- 12615 posts since 7 Dec, 2004
you're explaining this to me like i'm a preschooler. do you really enjoy teaching grandmother to suck eggs?
it's clear that i know what i'm talking about, and you've no clue, at this point. it wouldnt be more efficient in any way what-so-ever to do what you're suggesting. in fact, it would be a complete waste of effort and would decrease the efficiency. if you want to do things wrong in your own code, you're welcome to. do not come preaching to me about this stuff and treating me like a preschooler though - do you even have a clue who you're talking to or has your memory gone?
let me put this in very simple terms for you - when you're mixing you do:
mix += input;
wow, look at that, this is accumulation.
now, lets replace "mix" by the output buffer supplied by the host. let's replace "input" by the sample you just generated.
now - think for just a moment here gilligan - in order to work with a buffer which is not initially set to zero - we must set it to zero ourselves. the only way we could possibly increase the efficiency by a tiny fraction would be to do our first channel with moves, and the rest with accumulation. the real difference here is zero.
what you said:
"It's just plain faster, you're being stubborn and silly again. No memset vs memset? += vs =? PER SAMPLE. It's real work and it adds up."
is absolute bullshit. i appreciate if you're trying to be helpful but at this point you're merely working to really piss me off and you're absolutely wrong as well. if you can come up with a real example where the numbers are significant i'll listen to you.
i'm telling you two things:
1) what you're talking about doesnt apply to what i'm doing and is completely impractical. you obviously do not even have a clue what i'm doing.
2) even if it were applicable, the efficiency difference you'd see with what you're talking about would be essentially zero.
you do have the ability to prove your point with regard to #2, however even if you can prove that in some particular circumstance there is an appreciable difference, it will still not be applicable to my situation.
it's clear that i know what i'm talking about, and you've no clue, at this point. it wouldnt be more efficient in any way what-so-ever to do what you're suggesting. in fact, it would be a complete waste of effort and would decrease the efficiency. if you want to do things wrong in your own code, you're welcome to. do not come preaching to me about this stuff and treating me like a preschooler though - do you even have a clue who you're talking to or has your memory gone?
let me put this in very simple terms for you - when you're mixing you do:
mix += input;
wow, look at that, this is accumulation.
now, lets replace "mix" by the output buffer supplied by the host. let's replace "input" by the sample you just generated.
now - think for just a moment here gilligan - in order to work with a buffer which is not initially set to zero - we must set it to zero ourselves. the only way we could possibly increase the efficiency by a tiny fraction would be to do our first channel with moves, and the rest with accumulation. the real difference here is zero.
what you said:
"It's just plain faster, you're being stubborn and silly again. No memset vs memset? += vs =? PER SAMPLE. It's real work and it adds up."
is absolute bullshit. i appreciate if you're trying to be helpful but at this point you're merely working to really piss me off and you're absolutely wrong as well. if you can come up with a real example where the numbers are significant i'll listen to you.
i'm telling you two things:
1) what you're talking about doesnt apply to what i'm doing and is completely impractical. you obviously do not even have a clue what i'm doing.
2) even if it were applicable, the efficiency difference you'd see with what you're talking about would be essentially zero.
you do have the ability to prove your point with regard to #2, however even if you can prove that in some particular circumstance there is an appreciable difference, it will still not be applicable to my situation.
-
AdmiralQuality AdmiralQuality https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=83902
- Banned
- 6657 posts since 10 Oct, 2005 from Toronto, Canada
- KVRAF
- 12615 posts since 7 Dec, 2004
like i said i really do appreciate the effort if you're trying to be helpful, it's just you're completely missing out on something here which prevents you from seeing that there would be really no advantage to doing things any differently.
-
- KVRAF
- 3528 posts since 18 Apr, 2002 from British Columbia, Canada
two of the most stubborn developers on kvr arguing about stuff i don't understand... and yet it's a strangely compelling read 
i love both your synths, btw. If i hadn't lost my income i would be a proud ownser of polyana, but xhip does very nicely in the meantime. with the quality of both instruments, i have so assume that for each of your own specific uses you must both be right.
i love both your synths, btw. If i hadn't lost my income i would be a proud ownser of polyana, but xhip does very nicely in the meantime. with the quality of both instruments, i have so assume that for each of your own specific uses you must both be right.
-
Alex@ProgressAudio Alex@ProgressAudio https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=58042
- KVRist
- 338 posts since 15 Feb, 2005 from London, UK
If I may chip in regarding the process() versus processReplacing() thing.. The reason these two existed in the spec was all to do with effects, so you won't get it by thinking from a synth point of view.
process() is quicker for a send effect like a reverb, because you can just mix your reverb effect straight into the existing sound using +=
processReplacing() on the other hand is quicker for insert effects like compressors. Since an insert will replace the audio in that channel with its own output, you can just do an '=' to write your output to the buffer. This means that the host doesn't need to zero the output buffer beforehand since you will be overwriting it, and this saved significant CPU (in the old days, now it's insignificant).
In a polyphonic synth, process() makes more sense since you'll be mixing multiple notes so the accumulating process() makes more sense.
HOWEVER, in the VST 2.4 standard, process() has become deprecated therefore you should implement processReplacing() for compatibility with modern hosts. I know this from experience as a customer emailed me saying that my products didn't make any sound in NI's Kore, although they worked in lots of other hosts. I got the demo of Kore, and with a bit of debugging found that processReplacing() was called but process() wasn't.
So, the bottom line is, implement processReplacing() or your plugs will produce silence in some new hosts. It takes 30 seconds to implement so it's a no brainer.
Thanks,
Alex
process() is quicker for a send effect like a reverb, because you can just mix your reverb effect straight into the existing sound using +=
processReplacing() on the other hand is quicker for insert effects like compressors. Since an insert will replace the audio in that channel with its own output, you can just do an '=' to write your output to the buffer. This means that the host doesn't need to zero the output buffer beforehand since you will be overwriting it, and this saved significant CPU (in the old days, now it's insignificant).
In a polyphonic synth, process() makes more sense since you'll be mixing multiple notes so the accumulating process() makes more sense.
HOWEVER, in the VST 2.4 standard, process() has become deprecated therefore you should implement processReplacing() for compatibility with modern hosts. I know this from experience as a customer emailed me saying that my products didn't make any sound in NI's Kore, although they worked in lots of other hosts. I got the demo of Kore, and with a bit of debugging found that processReplacing() was called but process() wasn't.
So, the bottom line is, implement processReplacing() or your plugs will produce silence in some new hosts. It takes 30 seconds to implement so it's a no brainer.
Thanks,
Alex
- KVRAF
- 12615 posts since 7 Dec, 2004
it's always been "implemented" in xhip, it's just that i wasnt using the canprocessreplacing flag with a true value since some hosts may clear the buffer using some other method which is more efficient than memsetd. while hosts which do not call process will work fine since they do not check the flag, they check the function pointer (based upon my experience.)
- KVRist
- 352 posts since 8 Jul, 2003
To add my cents here.. Orion is just treating processReplacing and process the same way. The canProcessReplacing flag is respected. Both calls get empty zeroed buffers which are then both mixed same way. Each VST instance has own buffers. This mostly because of multithreading requirements for multi processors/cores, so I wish is that please do make your process* functions 100% thread safe and assume all code there should run paraller between instances for maximum effiency, and that the thread context is not guranteed to be same for every call.
jouni - www.markvera.net - Stardrive Studio - Orionology
-
- KVRAF
- 16154 posts since 2 Dec, 2003 from Nashville, TN
I say aciddose wins. His synth is free, and just as good apparently(I don't "do" synths, so I'm going by feedback alone, and also guessing).
Brent
Brent
My host is better than your host
- KVRAF
- 12615 posts since 7 Dec, 2004
i've made some more filter changes which solve the "drop out and back in" at the highest frequencies for the band/high/notch modes. the distortion has been reduced and stability increased. it sounds better to me than the old version although it does sound slighty different.. i havent tested it extensively. i think i want to stick with this change the same as i've stuck with the res compensation change. tell me what you guys think if you have the time to compare the last versiion with this:
http://xhip.cjb.net/temp/public/adxhip.0.6.12.8.fr.dll
i fixed some problems i introduced in the last few versions and i'm going to have a go at throughly testing for bugs and squashing them before i make the next alpha release (0.6.13.0) which will be the last release before i make the major changes to handling of patches. hopefully that shouldnt take too much effort.
http://xhip.cjb.net/temp/public/adxhip.0.6.12.8.fr.dll
i fixed some problems i introduced in the last few versions and i'm going to have a go at throughly testing for bugs and squashing them before i make the next alpha release (0.6.13.0) which will be the last release before i make the major changes to handling of patches. hopefully that shouldnt take too much effort.
- u-he
- 30213 posts since 8 Aug, 2002 from Berlin
Oki. Prominent stuff. IMHO Process is BS and overhead from old times. Someone thought it was useful. Back in the days. Who knows. It requires (well, mostly) the plugin to *read* the target buffer and then to *write* to it:
*ptr = *ptr + fx_out;
ptr++;
This is a wonderful pipeline killer. Memory controllers simply *love* this
It's probably as fast to just write out the results to any buffer, and then mix this buffer with the actual "accumulation buffer". It doesn't matter anyway. Moving a bit of memory is neglectible on any modern cpu...
AD, why does the buffer have to be cleared? It's way more fun *not* to clear the buffers and just overwrite them.
Urs
*ptr = *ptr + fx_out;
ptr++;
This is a wonderful pipeline killer. Memory controllers simply *love* this
It's probably as fast to just write out the results to any buffer, and then mix this buffer with the actual "accumulation buffer". It doesn't matter anyway. Moving a bit of memory is neglectible on any modern cpu...
AD, why does the buffer have to be cleared? It's way more fun *not* to clear the buffers and just overwrite them.

