Need help modifying the PreciseCounter module in Wave Player
Archive · 20116 old posts
From the original SynthMaker forum (2004–2014), with its members’ names and dates.
simonbreak ·
Hi all, SM noob here but I have a lot of experience with Max, Reaktor and programming in general.
I am currently trying to make a modified version of the standard Wave Player module. My modified version will take, instead of a frequency in hz, a float indicating the playback speed. In this scheme 1 would be normal speed, 2 double speed, 0 stopped and -1 reverse playback at normal speed.
I have got it working fine for positive speed values, but playback stops once the speed goes negative. Actually, this is not precisely true: playback works fine but looping is broken. If you start the speed out positive, then switch to negative the sample will play in reverse until it gets to the start of the sample, but it will not then loop around to the end of the sample.
As far as I can see the problem is with the PreciseCounter module (inside the Counter module) inside the Wave Player. If you give it a negative step size, it doesn't loop properly. However neither the code block nor the schematic itself has any comments to indicate what it is supposed to be doing. As a result I can't figure out what I need to change to make this module work with negative step sizes.
I would be very grateful if anyone could explain to me how this module works, in particular what the code block is supposed to be doing. I would be even more grateful if they could explain to me how I can make it handle -ve step sizes correctly.
Finally I would like to respectfully submit to the devs that it would be enormously helpful to noobs like myself if the standard modules contained comments, as I feel that opening and modifying these modules is probably the best way to learn SM.
Cheers [sb]
infuzion ·
Welcome to SM Simon!
The big blue box is SM's Code, where it is not an "High Level Language" like C++, but just barely a step above Assembly. There are no IF...THEN statements, but conditionals & masks. So if we take this line:
looplen=(looping>0)&(lend-lstart);
it is equivalent to
IF (looping > 0) THEN looplen = lend-lstart ELSE looplen = 0
See also: [old link]
oddson ·
simonbreak wrote: As far as I can see the problem is with the PreciseCounter module (inside the Counter module) inside the Wave Player. If you give it a negative step size, it doesn't loop properly. However neither the code block nor the schematic itself has any comments to indicate what it is supposed to be doing. As a result I can't figure out what I need to change to make this module work with negative step sizes.
I would be very grateful if anyone could explain to me how this module works, in particular what the code block is supposed to be doing. I would be even more grateful if they could explain to me how I can make it handle -ve step sizes correctly.
I'm not sure how to advise you on fixing the loop issue as I can't make inverting the 'step' work.
But I think I've figured out the way the PriciseCounter module works... so here it goes.
Let's start with the Loop/Reset code.
Essentially it just passes the step value to be added to the running index value except when it needs to be reset.
It needs to be reset to zero when a retrigger is present and it needs to loop over the correct amount when the length is exceeded. The first line detects when this has happened (if the loop variable has been set).
This line says set the subInt value to the length of the audio in samples iff adding the step size to the current index will make the next index greater than the audio's length AND the loop variable has been set. Otherwise subInt is set to zero (as there is no other value in the assignment so when either of the logical conditions are not met it gets zero value).
Why this is done makes sense in connection with the next line:
This line passes the step value in all but two cases. Here's how.
As the two conditionals are mutually exclusive the value is either set to step minus subInt (remembering subInt is usually zero thereby passing the step value in most cases) OR to the inverse of the current index when the retrigger signal is present.
In the latter case this value is later added to the current index value thus resetting it to zero
In the loop case, when subInt was set to length in the previous step, the new step value is a negative value just shy of the length of the sample by the normal step size. As the index value has already exceeded the length it should then step to the appropriate index back towards the beginning of the audio.
The rest of the module is pretty simple (except that its in double precision values to avoid getting incorrect difference numbers once the integer parts become large).
In the upper path the index value is looped into itself adding the step size with each iteration and then rounded (upwards) to become the upper index value.
The bottom stream takes the difference between the precise counter and the upper-rounded index. This will be used in weighting between two samples in interpolated read module.
I hope this helps (and I hope I've got it correct!).
So the problem with negative step sizes and looping is it's not detecting the need to reset nor how to get it to reset correctly.
I would think that detecting means looking for indexInt<0 but I've not quite figured out how to set the correct subInt in both negative and positive cases yet.
simonbreak ·
Hi infuzion + oddson, thanks very much for your help.
That tutorial you linked to clarified things a lot. I actually started writing a long post explaining the things I couldn't understand in detail but, as so often happens, the process of explaining the problem led me to the solution!
Oddson, I rewrote the code with lots of comments & bidirectional looping. Here it is:
// This code calculates the amount to step on each timeslice
// taking into account looping and retriggering
streamin indexInt; // Current position in buffer
streamin step; // Amount to step when we are playing
streamin retrigger; // Momentarily 1 when we start playback
streamin length; // Length of sample
streamin loop; // 1 if looping
streamout subInt; // Output: Actual calculated step
// Summary of logic:
// - If sample playback is retriggered, jump to start of sample
// by sending out step = negative of current index
// - If looping is on & end of sample has been reached, jump to start of
// sample by sending out step = negative of sample length
// - If looping is on & start of sample has been reached, jump to end of
// sample by sending out step = sample length
// - Else just send out the given step size
subInt = indexInt+step;
subInt = (((subInt>length)&length) - ((subInt<0)&length)) & (loop>0);
subInt = (retrigger!=1)&(step-subInt) - (retrigger==1)&(indexInt);
Pretty pleased with myself right now 😀
If anybody wants the complete thing let me know.
[sb]
infuzion ·
simonbreak wrote: Hi infuzion + oddson, thanks very much for your help.
That tutorial you linked to clarified things a lot. I actually started writing a long post explaining the things I couldn't understand in detail but, as so often happens, the process of explaining the problem led me to the solution!
If anybody wants the complete thing let me know.
Congrats & you're welcome!
You just replace your Code with the Code block inside, & did not change anything else? If not, I guess we'll need a demo... not to sure where you turn on the reverse...
infuzion ·
I simple search found this: [old link]
There is/was a more upgraded version somewhere on the forum though...
Wrote something here? To have a post removed or your name hidden, write to [email protected].