Page 1 of 1

a stage(0) question

PostPosted: Thu Aug 22, 2019 9:31 am
by HughBanton
Hi all. Excuse my recent absense, I'm constantly on FS64 these days (marvellous) and I know much of my recent stuff would screw up on 32 bit. Anyway ...

Back in February I started a topic about skipping over code whenever there was 'no change', i.e. nothing new to calculate - for example when a note or chord is sustained. Which in cpu terms is most of the time.
http://www.dsprobotics.com/support/view ... ged#p47190

The inhibitor I devised back then (with a lot of help!) ended up something like this (posted previously)...
multi_table_array_read_with skip.fsm
(2.16 KiB) Downloaded 1214 times

It checks if any of the 4 notes in a SSE group have changed, and if they haven't it skips the code. So any new note runs the code just once.

I was revisiting it all yesterday (I'd screwed something else up, as you do ..) and it suddenly occurred to me -
In this particular case does the addition merely replicate what you get anyway by simply using stage(0)?
In effect :
Code: Select all
stage0;
< some assembler code >
stage2;


Doh :?:

Re: a stage(0) question

PostPosted: Thu Aug 22, 2019 10:19 am
by HughBanton
Just wading back in among all the porn posts :o (Can't imagine why they accumulate in the DSP section, must be us users! Oh dear ..)

I've just recalled a previous question I posted 18 months ago, also about stage(0) , and in a reply MV pointed out that note-number is not available in stage(0). I imagine this fact hasn't changed?

Therefore, because the code I'm processing is all about indexing from note-number I guess my skip method is actually THE way to achieve this. It certainly seems to work OK.

H

Re: a stage(0) question

PostPosted: Thu Aug 22, 2019 3:33 pm
by trogluddite
HughBanton wrote:note-number is not available in stage(0). I imagine this fact hasn't changed?

In versions up to 3.0.8, this is certainly still true; though I can't say for the 64bit alphas, as I haven't used them. A short assembly routine which passes input to output in stage(0) but with no stage(1/2) code will tell you for sure.

In general, I'd advise against relying on the stage(0) output values of any primitive or ASM/code block, and always to use stage(0) only for static setup. In simple linear chains, output values might be useful, but it's likely to lead to problems as soon as you introduce feedback loops or any primitive which doesn't implement stage(0) as you expect (analogous to how stage(1) is sometimes used to ensure that stage(2) data is valid.)

So; yes, I'd stick with your current implementation, as it's likely to be much more reliable - especially if you might want to re-use it in other designs.

HughBanton wrote:Just wading back in among all the porn posts :o (Can't imagine why they accumulate in the DSP section, must be us users! Oh dear ..)

I wonder sometimes whether they stereotype DSP-coding -> anti-soclal geeks -> can't get a girlfriend (not all that far-fetched - when I started using autism/Asperger's support sites, I started getting a lot of ads for dating/"foreign-wife" sites all of a sudden!). However, I suspect it's mostly just opportunism: the forum software has virtually no defences, and moderator appeals to DSPr for better anti-spam tools have thus far fallen on deaf ears. When you're a moderator on a trash-disposal sweep, you have to be particularly careful - some of them have embedded photos that you really wish you could "un-see"! :evil:

Re: a stage(0) question

PostPosted: Thu Aug 22, 2019 6:23 pm
by HughBanton
Many thanks trog; yes, I think I managed to prove that note-number is not available in stage(0) in FS64, using the method you suggested. Thanks for the tip.

I have so little confidence with 'anything assembler' - I literally only know what I've picked up here during the last year or so - but trying hard! So is this valid?
Code: Select all
mov eax,ecx; //ecx is sample counter
cmp eax,0;
jne skip;
<some assembler code>
skip:

.. which I figure will skip the code except when ecx is at zero, very first pass, and only execute it once. That's exactly what I've been trying to achieve but this is a way simpler method, if it's correct. :?:

And for that matter, could I say :
Code: Select all
mov eax,ecx; //ecx is sample counter
cmp eax,317;
jne skip;
<some assembler code>
skip:

.. to make the code execute just once, but when ecx reaches 317. (Arbitrary number).

Most grateful for guidance.
H

Re: a stage(0) question

PostPosted: Thu Aug 22, 2019 8:05 pm
by trogluddite
Your code is right in principle, but unfortunately, checking the sample counter won't work for poly streams. The ecx register is not a "four-in-one" SSE register, just a single value shared across all four SSE channels. IIRC, the counter does get reset to zero when a new block of four voices is initialised, but only the first voice out of the four will see the zero value. A better alternative might be to use the 'trigger' output of the MIDI-to-poly module, which IIRC outputs a single non-zero sample at the start of a new voice, and only to the new voice's SSE channel.

Incidentally, there is another little caveat, though it will only very rarely be a problem. Just like a car's odometer, the sample counter will wrap around to zero when it runs out of bits. For a 32-bit ecx and 44100 Hz sample rate, this will happen a little less than once per day (and several human lifetimes if FS64 uses a 64-bit counter!) Hopping works in a very similar way - ecx effectively gets shortened to fewer bits using a bitmask, so that it wraps around more often. As the bitmask has to be of the form 2^N - 1, this explains why you can usually only hop in powers of two.

Re: a stage(0) question

PostPosted: Fri Aug 23, 2019 6:20 pm
by HughBanton
Aww shucks.. life is cruel :(

I'm away from the research laboratory (spare bedroom ;) ) for a few days so will resume after I get back.

But.. I was slightly puzzled last night because, from what you said about ecx, I would have expected the result to be only the first of a four note group to play and the rest to go awol. In fact all four play. Likewise in my second example, if I set the arbitrary number to, say, 10000, then I get the same delay of roughly 1/4 second on all four notes. As though ecx is resetting upon every note on. I didn't have time to devise a way to test this for sure, but could it be??

H

Re: a stage(0) question

PostPosted: Fri Aug 23, 2019 7:24 pm
by trogluddite
I just checked, and you're quite right, ecx does appear to reset at every note-on. Serves me right for IIRC'ing; I should know better than to trust my memory these days! And, of course, my apologies for leading you up the garden path! :oops:

The shared ecx would be a problem if you needed to know which voice had just started (which I was jumbling up with your problem a little in my post, I suspect) - but if you just need to know that any voice in the group of four just started, your "ecx == 0" code looks to be a very neat and efficient solution!

Re: a stage(0) question

PostPosted: Sun Aug 25, 2019 1:53 pm
by HughBanton
That's OK, as long as you weren't twIIRC'ing :lol: I haven't progressed anything yet.

Also has a bearing on loop() I think, if long e.g. loop(4096). If you're playing a few notes very rapidly - causing ecx to reset before it gets to 4095 - the loops will be shortened. Could conceivably have a bearing on envelopes for instance, but maybe just academic in practice.

All just stuff to keep me awake at night :geek:

Re: a stage(0) question

PostPosted: Sun Aug 25, 2019 2:51 pm
by trogluddite
HughBanton wrote:Also has a bearing on loop() I think

Thankfully, this is one problem that we don't need to lose any sleep over (though my brain rarely has any trouble finding something to lose sleep over!)

DSP loops always run to completion for each sample rather than being spread across multiple samples. You can see this if you look at the ASM text output for a DSP primitive which includes a loop - the sample counter ecx isn't referenced at all, though the eax register is used temporarily as the loop counter. So the main issue with long loops is the CPU load from running every iteration for every sample - where possible, it's a good idea to hop around them generously or to confine them to stage(0) (e.g. for initialising an array with values.)

Incidentally, looping is one aspect of stream coding where knowing ASM can be extremely useful. DSP loops always have a fixed number of iterations (the ASM will show that the loop counter eax is assigned a hard-coded number, which is then reduced by one for each iteration until it reaches zero). Using ASM, it's possible to code loops where the number of iterations is set by a variable/streamin or by an arbitrary conditional test (similar to a while or until loop in other coding languages.) It's not something that's needed for audio streams very often, but when it is needed, ASM is the only way to do it in FlowStone.