SynthMaker

Executing a loop only when it needs it

Archive · 2011 10 old posts

From the original SynthMaker forum (2004–2014), with its members’ names and dates.

pjackson ·

Hi, Im new to synthmaker and only just working things out.

What I am trying to do - I want to make plugin that takes wavelength long samples(I think these are called grains but Im not completely sure on terminology) of an input signal, quickly processes them and then streams them out again. I figure with this sort of thing i can switch octaves by lengthening the grain before its output again, or do other things.

This is the way Ive been trying to do it. I have three buffers - writeBuffer, swapBuffer and playbuffer. Writebuffer constantly reads in the input signal, when the signal crosses zero it writes out its data to swapBuffer. PlayBuffer constantly plays out what it contains, looping around and round. When it reaches the end of its grain it copies whatever was in swapbuffer over.

So basically data goes from writebuffer -> swapBuffer -> playBuffer

My problem comes when I want to copy one buffer over to another. my buffers are 4096 floats big. And I cant find a way to make a loop that only calculates when I actually want to copy the values. All my code executes every sample. Here is an example of how Im trying to do it, Im not used to these bitmask things either-

//copy writeBuffer to swapBuffer loopIndexA = 0; loop(4096) { swapBuffer[loopIndexA] = (zeroCrossing == 1) & writeBuffer[loopIndexA] + (zeroCrossing == 0) & swapBuffer[loopIndexA]; loopIndexA = loopIndexA + 1; }

That loops round 4096 times every sample! Am I doing something that will never work? Is there another way to acheive what i want? can I make a loop only execute when i want it to?

Heres all my code if your interested, this doesnt work at all though!! It just maxes out the CPU - obviously because its doing these loops 8000 times per sample-

streamin in; streamout out;

float writeBuffer[4096]; float writeCounter = 0; float writeGrainSize = 4096;

float swapBuffer[4096]; //float swapCounter = 0; float swapGrainSize = 4096;

float playBuffer[4096]; float playCounter = 0; float playGrainSize = 4096;

float aboveOrBelow = 0; //0 is below, 1 is above float aboveOrBelowDelayed = 0; float zeroCrossing = 0;

float loopIndexA; float loopIndexB;

//main section //---------------------------------------------------------------

//set aboveorBelow for zero crossings aboveOrBelow = in > 0.0 & 1.0;

//detect zero crossing and do something zeroCrossing = (aboveOrBelow == 1) & (aboveOrBelowDelayed == 0); //copy writeBuffer to swapBuffer loopIndexA = 0; loop(4096) { swapBuffer[loopIndexA] = (zeroCrossing == 1) & writeBuffer[loopIndexA] + (zeroCrossing == 0) & swapBuffer[loopIndexA]; loopIndexA = loopIndexA + 1; } //set grainsize swapGrainSize = (zeroCrossing == 1) & loopIndexA + (zeroCrossing == 0) & swapGrainSize; //set writeCounter back to zero writeCounter = writeCounter - (zeroCrossing == 1) & writeCounter;

//write to the writeBuffer writeBuffer[writeCounter] = in;

//play the playbuffer out = playBuffer[playCounter];

//getting stuff ready for next sample //---------------------------------------------------------------

//write out delayed aboveOrBelow aboveOrBelowDelayed = aboveOrBelow;

//increase counters writeCounter = writeCounter + 1.0; writeCounter = writeCounter - (writeCounter >= writeGrainSize) & writeGrainSize; playCounter = playCounter + 1.0;

//copy swapBuffer to playBuffer if grain size is reached loopIndexB = 0; loop(4096) { playBuffer[loopIndexB] = (playCounter >= playGrainSize) & swapBuffer[loopIndexB] + (playCounter < playGrainSize) & playBuffer[loopIndexB]; loopIndexB = loopIndexB + 1; } //set grainsize playGrainSize = (playCounter >= playGrainSize) & swapGrainSize + (playCounter >= playGrainSize) & playGrainSize; //set playCounter back to zero playCounter = playCounter - (playCounter >= playGrainSize) & playCounter;

Id be really greatful for any help you can give me? maybe point me in the right direction at least?..

cheers

infuzion ·

Welcome to SM pjackson! Why 3 buffers? Why not Mem Get At primitive?

pjackson ·

Hi infusion, wow your quick! thanks for helping me out. This is the first time Ive ever programmed any audio so im still learning..

Why 3 buffers?

I obviously havent got it working yet, so this is all in my head. I thought 3 buffers would be necessary as I want them to be able to be out of sync - for example I might want to take a grain in, change its length and play it out again.

One of the things id like to make is a real-time octave shifter by doubling the length of grains and skipping every second one. I want to do other things as well but thats the starting point 🙂

Since writeBuffer is in a constant state of being written to there will be times when it is half written - the new grain is being written over the top of the old one, I thought Id need an intermediate but I could be wrong.

Why not Mem Get At primitive?

This might be what Im after, but ive done a search and cant find it in the user guide, do you have a link to how it works?

infuzion ·

Maybe Wave Read would be better?

trogluddite ·

infuzion wrote: Why 3 buffers?

This is the crux of the problem - trying to copy entire buffer contents will always make for a large CPU hit, and as you have found, you can't selectively execute a block of code.

But your intermediate buffer is just storage for input data from a short time ago, and the playback buffer stores data that is a little older still. So the key to the algorithm is to have only one, larger buffer - instead of moving large amounts of data around, you can change which part of the buffer is played back by updating start and end pointers according the zero crossings that you find. To do this, you will need to use the bitmasking technique to selectively choose between updating a variable, or retaining its current value. The general form for this is...

Variable = Variable + (NewValue - Variable) & (<condition>);

& (<condition>) results in a mask that either lets the preceding value through (if true), or results in zero (if false).

So if false, we get... Variable = Variable + zero = Variable;

And if true... Variable = Variable +(NewValue-Variable) = NewValue.

infuzion ·

Summery: Wave Read + [old link]

MegaHurtz ·

LOL even I cant read this trogg. But there outta be a file somewhere on the forum.

infuzion ·

There are a few approaches, but just having an Int array or 2 with start/end points that moves the Index around should work. I try to make people learn SM to do what they want, but I like putting them on the path. If they don't want that path, then they can pay me to go on it for them 😉

trogluddite ·

MegaHurtz wrote: But there outta be a file somewhere on the forum.

Indeed there is... Smooth the Grains

pjackson ·

I just want to say thanks to everyone for your help. I got it working using trogluddite's method of one big array. Ive uploaded what Ive done so far if anyone''s interested. It only works with simple waveforms of course but thats all i wanted. Its still not perfect as at the moment it skips when it reaches the end of the array and goes back to the start, got to work out how to fix that still.. Thanks again this is a very helpfull forum!

Wrote something here? To have a post removed or your name hidden, write to [email protected].

Before your first post

A few rules keep this a friendly place. You agree to them once.

Shown next to what you post, here and in the app. It doesn’t have to be your real name: 3–24 lower-case letters, digits or _ (capitals become lower case, spaces become _).

    Then your post goes up straight away.

    Delete this reply?

    Open it in SynthMaker?

    It goes on the track you’re editing there, in place of that track’s sound, and into My sounds. Your other tracks stay as they are.

    Want to keep that track’s sound? Start a new song in SynthMaker first (Song › New song), then open this.

    Report this reply?

    Only the developer reads reports. The person isn’t told who reported them.

    What’s wrong with it?

    Block this person?

    You won’t see their posts and replies here any more. They aren’t told, and you can unblock them at any time.

    People you’ve blocked

    Their posts and replies are hidden from you. Unblock someone to see them again.

    The community rules

    A few rules keep this a friendly place. Everyone agrees to them once, before their first post.