Debugging in Flowstone.
Debugging in Flowstone is one of the areas that has been quite neglected and we are forced to rely solely on the “ad hoc” method of adding trigger counters, float primitives and watch statements ect scattered all over to look at values of interest. Which is fine but it is a very primitive way of debugging. Ideally Flowstone would come with some kind of debugger and enable us to add break points which freezes the schematic when they are reached, then showing a list of all variables and their values at exactly that point in time. All programming IDE’s have this kind of functionally and is a god send when hunting down bugs. But we don’t have that so rather than cry over it lets get into what we do have and the best ways to debug when working in Flowstone….
A little preparation goes a long way…
Preparation is key when debugging don’t just go diving in changing stuff hoping that “this might fix it”, you need to do the ground work first to prevent and fix any occurring bugs.
Keep your schematic tidy!
Firstly you want to make sure you are taking steps to reduce the likelihood of bug occurring in the first place. This means keeping your schematic tidy! Bugs are incredibly hard to fix if you are struggling to understand the code. All inputs and outputs on modules should have clear names, and where necessary the format of the values involved. You may have an oscillator that takes hertz as it’s frequency but if it is labeled “Freq” then you might forget and feed it a 0-1 freq and then be left wondering why you are getting no sound.
So keep things as tidy as possible and label everything clearly so there can be no misunderstanding about the values or ranges of values required. A tidy clear schematic makes bugs less likely to occur and makes them easier to fix. If you do have a bug that you are struggling with and your schematic is messy try tiding it up first and then debugging.
I don’t want to go to deep into the specifics of keeping things clean and tidy but Trogluddite has written a great post HERE which includes many great tips.
Save your schematic often
This is very important! I like to save every 10-20 minutes or whenever I have added anything significant. Saving often prevents losing all your work in the case of a crash too, which is devastating if you have been working on your project for 3 hours without saving trust me! You should also turn on auto recovery in the “Options” I have mine set to every 30 seconds. Why save often if auto recovery is on? isn’t that enough you might ask? . Well no it isn’t because in the case of a crash the crash may persist so when you open the recovery file it just crashes again. Meaning , well you just lost all your work. I have read somewhere on the forums that these files can be recovered with a bit of hacking but I have not looked into that and I believe it is just better and safer to save often and have auto recovery as a backup of your backup
You should save your schematics with a version number in the file name so you can see which is the latest version and easily go back in time through previous versions. For example first save could be “MySynth V0.1.fsm” second “MySynth V0.1.1.fsm” ect. So we just increment the version number from very low values, this gives us plenty of scope for new version numbers before hitting version 1.
Test your schematic often
Before every save it is a good idea to give the changes you just made a quick test. This can be as simple as playing a few notes on a Synth. No sound? opps , I just a made a change to my filter and forgot to reconnect a wire. If you test often then the changes you just made are fresh in your mind, so you might be able to figure out very quickly what went wrong. If you don’t test and come back to your schematic much later and cannot remember the last few changes you made then you might have to spend much longer tracking the problem down.
Repeat after me test and save, test and save, test and save! I cannot stress how important this is if you save often but do not test your changes then bugs can accumulate and ultimately become much harder to fix. Of course if you find a bug don’t just save it, fix it .
Check your assumptions
Bugs can often happen when we make assumptions that turn out to be incorrect. For instance when I was working on the Multi stage envelope years ago I noticed that the envelope had a delay equal to the size of the hop that was used (for those unfamiliar with DSP code a hop is used to ‘skip’ over so many samples instead of processing every sample to save CPU) ,this was a potential bug but I convinced myself that is just how the hop worked. I thought the hop meant the first sample wasn’t processed and processing actually started at the hop amount, causing a delay. A user reported a problem with clicks because of this and I told them that is just how it works and there is nothing I can do! until someone pointed out (thanks MyCo) that it was actually a bug in my code and my assumption was completely incorrect.
So check that your assumptions are correct because if they are not then that could be why you have the bug. Double check your assumptions about how certain components and features of Flowstone works by checking the User Guide or Component Reference. Failing that you can ask over on the Flowstone Forum.
Hello? can we do some debugging yet?
So you know that your project has a problem and is not working as intended but sometimes it is not always obvious where the bug is lurking. When this is the case you need to isolate the problem by removing code, disconnecting modules until the problem no longer appears or reverting to a previous version.
Isolating by reverting to a previous version
If you save often then reverting to a previous version you saved 10 minutes before means the changes you just made are still fresh in your mind, so if the previous version works but the current one doesn’t then the bug is obviously somewhere in the changes you just made.
Sometimes you may need to revert to a much older version so keep going back in time through each version until the bug no longer appears. Now from here we can gradually add back in each of the features from the latest version until the bug shows back up. If you keep your schematic well organized into modules then this method will be much easier because it should just be a case of adding a module and then testing. Once the bug shows back up we know the bug is lurking in the last module we added.
If you haven’t been saving versions very often or the bug is very old and your project has changed so much that reverting back to an old version is not an option, then you may have to start from the current version and slowly remove features/modules until the bug no longer shows…
Isolating by removing code/features
This is probably the most common way of isolating a bug in a schematic. Just keep removing stuff one by one and testing until the bug disappears, when the bug is no longer there it is obviously in the last module or bit of code you removed.
There is no reason to be scared of removing large portions of your project while isolating. So hack away remove anything where you think it could be and then re-test.
Isolating by Inspecting values
Sometimes we can locate the source of a bug without removing anything by using readout modules or any other method for inspecting values within the schematic (I go through these methods of inspecting in the next section)
Here is a simple example of using poly readouts to find out the cause of why this simple Synth has no sound.
So here looking at the poly readouts we can see that they do indeed have values and so the Synth is not outputting zero and so surely should have sound? Well one of these modules is outputting a value in a range that the other module does not expect.
If you click on the Multi Osc to highlight it you will see the the first input is labeled “Freq(Hz)” meaning this Oscillator is expecting a frequency in hertz. If you look at the output to the Midi to poly you will see that this is definitely not outputting hertz it is outputting a normalized 0-1 frequency, this can be changed to hertz by clicking on the properties panel.
Now I’m aware that was quite an unlikely bug to face but I just wanted to show how to inspect the outputs of each module to see where the problem arises. For newbies this could be a common problem if using Oscillators found elsewhere because many do not use hertz and so they could be caught out with something like that. Regardless inspecting values in this way is an invaluable method in tracking down where a problem lies.
Inspecting values in a schematic
Flowstone has many different areas where inspecting values requires slightly different methods or techniques, inspecting values in DSP Code is very different to inspecting values in Ruby for instance or even inspecting in “Green” (Green is a common term used by users to describe green triggered components for those unfamiliar with the term.).
So here I will describe how to look at any values of interest in each area of Flowstone development.
Inspecting values in DSP code
To inspect values inside a DSP code component, we can add an extra streamout and name it “debug” , then grab either a poly or mono readout depending which stream type you are working in (these modules can be found in the “Debug” section of the toolbox) and connect that to the new output.
Here is an example where I have modified the stock ADSR modules code…
Now any variable we want to inspect we can just assign to debug like so…
When we start to test by playing some notes on the keyboard, the poly readout will show the value in the variable “adLen”. In the case of mono streams because they are always on and not triggered by midi, the readout will show the value without having to play notes like for poly streams.
You can do this for any variable in your code to check that the values make sense and are correct or within the required ranges.
When you have finished debugging make sure to remove the debug output and delete the readout module because it will eat up CPU if you leave it in place.
Inspecting values in “Green”
When working in green we can look at any values by connecting a component of that type or in the case of arrays we can look at it’s contents by connecting a Text component.
One thing to avoid is placing these inline to look at values for example..
In the case of the arrays they will be converted to String and then converted back to the array type, this is very slow so avoid doing that at all costs. Also the case of inline float or integer components is also bad even though there is no conversion going on. If these values are changing often then they will add a CPU hit and if you are trying to edit your module while the values are changing this can seriously slow editing speed of the schematic in some cases. Also they are harder to remove because components after it may rely on the link order. Link order (the order in which components are linked) effects execution order which in itself can be a major cause of bugs in green. See the “Debugging in green” section where I link to a great PDF detailing link order and triggers.
Inspecting values in Ruby
To inspect values of interest in the Ruby component we have the watch statement, here is a very simple example.
The text “Ramp current value” can be anything you like and is just a label so you can see exactly what the watch value relates to, which is handy if you are using many watch statements.
Again avoid leaving these in place when you have finished your debugging or they will use up unnecessary CPU.
So far I have gone over the best practices for avoiding bugs, isolating problems and inspecting values to help determine where bug lies but what about more specific stuff? There’s a lot more to debugging that just looking at values so here I will cover more specific stuff not covered already.
Debugging in Ruby
Ruby has a window at the bottom which sometimes give us useful information about errors in our code, sadly most of the time it isn’t useful at all so here I will briefly cover how to improve that situation.
Improving the error message
Sometimes we get an error that is very cryptic and doesn’t tell us where the problem is at all. Ruby guru Trogluddite has come up with a little code snippet to improve this situation and give us a back trace of the methods called leading up to the error.
Put this code an the end of any method…
rescue => error
Rather than repeat his words here I will link to the thread where he describes this in detail – Ruby Error – But where?
Line Numbers in Ruby
Code lines in Ruby are not numbered so sometimes you get an error message with a line number but this line can be hard to track down and will require manually counting the lines to find the line with the error. Obviously this is a pain. I started a thread over on the Flowstone forums to see if anyone could help me in improving this situation and Myco came up with a great little module so we can now see the code along with line numbers.
Check it out HERE.
With this method all you need to do is create a String output on your Ruby component and name it “ruby code” this will output the Ruby code which is then passed through the module “Add Line Nr” which adds line numbers to the code.
Debugging in green
One of the most important things to understand when working in green is triggers and link order. I cannot possibly do this topic justice here because this article is meant as more of an overview of debugging techniques and best practices in Flowstone. But I will point you towards some great (again by Trogluddite) work on this subject. HERE you will find a great PDF and an example schematic detailing how triggers work in Flowstone. Note this was written for Synthmaker but it all still applies to Flowstone and also FL Flowstone (FL Studio version).
That’s a wrap
Ok so I am going to leave this article there for now (it is already long but It could be so much longer!) but I might edit it with improvements in future, if you would like to see anything specific added please leave a comment.
This article was mostly aimed at newer users so I hope it was of some help to those people (and even more experienced I hope), if you follow the advice in this article and are still stuck tracking down or fixing the bug then consider opening a thread over on the Flowstone support forum to ask for help.
Failing that I will fix any bugs for a fee so if you are really struggling to fix an issue and cannot get the help you need then get in touch via the Contact page