It’s so easy to connect components together in SynthMaker that it is also very easy to make messy, unreadable modules. This page will show a few of the ways I’ve found to make your OSMs readable to others and to yourself when you look back months later. Part 2 is a collection of more miscellaneous readability tips. First we’ll start with making sense out of someone else’s mess.
Let’s say you want to make your synth’s velocity control non-linear. That is, you want some control over how the 128 levels of velocity info actually map to single float values for, say, a volume control.
So you go on the forum and ask if anybody has such a thing. You get a favourable response and the following OSM.
Looking inside you find this:
You discover that it does just what you want, but you still want to understand what it’s doing and be sure it’s an efficient method of doing it (or you just can’t stand the thought of dropping that mess into your neat schematic).
The best way to really understand it and improve it where needed is to organize the file properly. I’m going to show you my style; it’s not necessarily the best and certainly not the only possible choice but it is preferable to chaos. You’ll develop your own style with time.
The first step is to start looking for obvious groupings of components to turn into modules based on their function. You can subdivide these up at a later time.
Look for groups of components tied together with many connections but tied to other areas with few.
This is not a hard and fast rule, but it usually indicates a logical connection between the components. It does mean you can leave some things out that belong with them just because t In our schematic, starting from the control output we can see the following section meets this criteria.
Whatever this part is doing, it’s doing it to a float input and it results in a single float value being calculated. Before we make it into a module, note the precedence order of the connections coming off the ‘Power’ primitive. Sometimes this matters and other times it does not but it’s best to assume it does for now.
Select these components and choose ‘make module’ from the Action Panel.
There are now two outputs on the resulting module. But we know there was only one source for these outputs so we’ll want to get rid of one as it is clearly redundant.
Since we noted the connection to the Power primitive had precedence over the one to the Loop primitive, we’ll hook the loop up from the one going to the Array so that this precedence order is replicated.
Remove the connector coming from the new module which leads to the Loop. Drag a replacement connection from the other output. You should see something like this:
Now enter the module and delete the now unused output.
The other components will have the same positions in the new module as they had in the old. This usually means you need to move things around a bit so everything is as clear as is possible.
The next obvious groupings are these:
Follwing the above steps you will get this:
With what’s left we’ll make two more modules.
We leave out the MGUI and any connectors (including the wireless) to avoid changing the way the schematic works. Once we figure everything else out we can rewire this as needed.
The result of dividing into main modules should is this:
Now we’ll take a look at each module and figure out what they’re doing and then name them and their inputs and outputs.
A funcion of it’s only input: ((1-x)*2)^2. As the input ratio approaches 1 the (1-x) term goes to zero and whole thing goes to zero. The slope diminishes as x approaches 1. It’s a non-linear scaling of the control ratio. We’ll see what it means later.
Here the Loop is generating a series of 128 integer values from 0 to 127 and this same series is used both as the index for the Array and (coerced to a float) as the base raised to the exponent coming from the output of Module 1. Then the array’s output is normalized (scaled to between 0 and 1) and is then sent to a Shift Array module with no shift value. Since there is no shift, this would be acting as a Float Array Sample & Hold. Since this was a recent addition to the S|M toolbox we conclude it can be changed to the new primitive. Also, the normalization primitive has to re-normalize with each new element in the array. So a better solution for this module would look like this:
Here’s module 3 with just bit of reorganizing the layout:
It’s pretty clearly a MIDI filter for processing the velocity events and passing everything else.
But we can make it a little easier to read if we consolidate the control portions into two small modules.
We had to flip the boolean outputs from the top one and consolidate the integer and trigger inputs in the second as both come from the ‘data 2’ output of the MIDI splitter. The insides needed only a little touch up.
Here we can infer that (constant) integer value must be the status value for ‘note on’ messages - since velocity data is tied to the note message. So this little unit is giving boolean output based on whether a specific MIDI message is a ‘note’ on message or not.
Since this module is fed from the ‘Data 2’ output of the MIDI splitter then this module is manipulating the actual incoming velocity data. We can see that it is being used as an index integer to extract a value from the float array. Since the overall behaviour of the schematic is to remap MIDI velocity values we can be pretty sure that this is where that remapping is occurring. Also, since the float array come from module 2, and we noted it’s values were normalized to the rage [0,1], we can be pretty sure multiplying by 127 is done to return the values to the range [0,127].
In the parent module this output connects to an integer value. So we can have this module coerce it’s output to be an integer so that it will match the input type it is being fed to. This gives better clarity as to the intent of this module. (To coerce a data change on a module output just right-click on the output and select the data type you want to convert to.)
In performing this coercion, however, we should realize we are loosing resolution from the float array that contains the mapping data. The output is going to have 128 possible values but as the source also had 128 possible values – and we are remapping – there will be [many] fewer values that are actually possible. We will reconsider this loss of data a little later.
Module 4 outputs and Area data type and therefore seems to be used in the positioning of the visual output. A little cleanup will give you this:
The number of constant integer values that are not labelled and not defined as properties within an area definition module tends to indicate ad hoc positioning of an element. Typically it’s best to leave positioning to the user in the front panel or to use labelled property values.
The value being fed to the ‘x offset’ of the area primitive looks like it is there to offset around the slider control. Fixing this will require making the graph output something that can be arranged in the front panel. We’ll come back to this a little later.
This module is clearly doing the drawing of the graph. It only needed a little clean up and labelling and making properties out of the graph line thickness and colour values.
So far all the changes we’ve made have not altered the workings of the module itself; that is they have all been functionally equivalent. Now it’s time to make some real improvements.
We noted in looking at Module 4 that positioning was not handled via properties nor through a front panel. Lets make it use the front panel so that it can be easily altered for different uses.
These are the pieces concerned with graphing the array. The wireless V connector is allowing the slider to be included – but we can delete this and use the front panel instead.
Make the remaining parts into a module, add a wireless receiver to the MGUI and make a front panel for the parent module. Now you can go back to Module 4 and remove some of the area definition parts that were less than ideal.
Here’s the result:velocityCurve.osm
It’s now in a state that could be used to make a MIDI-only VST that re-maps velocity values. But if you want to include it within a SynthMaker creation you have a chance of figuring out how to do it without the loss of resolution that we noted while talking about Module 3. Explaining how isn’t the intent of this tutorial but if you’re interested here’s a schematic that does just that: velocityCurvePoly.osm
There are far more tips in part 2.