Metering with history
by RRSounds on Fri Dec 17, 2010 2:35 pm
Hi Gang!
Well, now that I'm a registered SM user, and starting to familiarize myself with the system, I have embarked upon a compressor project. I am really racing along in DSP, and having a blast! Graphics is another matter, however...
I have an idea for a gain meter that is pretty specific, but I have not figured out how to do it using the graphics elements. Here is the idea:
There are four things that have to be indicated:
1) AGC Gain [small rectangle that moves up and down with instantaneous gain value];
2) AGC Mode [indicated by changing the color of the above rectangle];
3) Peak Limiter Gain Reduction [thinner rectangle, also moving dynamically];
4) History of the past few seconds [trails to the left of AGC and peak values];
5) labelled grid overlay/underlay scales to indicate time and gain.
In detail, I want to create a vertical meter that indicates AGC gain using a small, horizontally-oriented moving solid rectangle (actually a thick line) whose color can switch dynamically (set externally). Along with that, I want to show, superimposed, a smaller (thinner) rectangle (thinner line) that indicates peak control gain referenced to the AGC gain. To the left side of the meter, I want to illustrate the history of the last five seconds or so of the indications, so the user can see at a glance the gain trends over a short time span of the process. The range of gain indicated on the vertical scale will be from +20 (top) to -20 (bottom).
That part of the concept is similar to moving dot with trails/'phosphors' that others here have implemented, except my 'dot' (rectangles/lines in my case) indicating the current values moves up and down on a non-moving vertical axis, and the 'trails' move away from it over time, to the left.
Ultimately, I want to use eight of these in my compressor project, so in order to keep CPU usage to a minimum it would be nice if we can do everything possible in green. Timing accuracy is not as important as level indication. For flexibility, it would be useful if the entire meter could be scalable so smaller or larger versions can be implemented, like the Oscilloscope.
I'm not looking for someone to do all the work, but I really, REALLY have trouble grasping the graphics aspect of SM, and could use all the hints anyone is willing to offer. Offering examples is nice, but at this point in my knowledge of SM, clear explanations of technique are MUCH more important to me!
And of course, when I'm done, I'll share the project and any rights to its use with the forum.
Here is a YouTube of some AGC indicators I have made without the trailing history, or the peak indicators. Made with a modified Oscilloscope (whose operation I understand only enough to figure out how to change the color and thickness of the trace.)
http://www.youtube.com/watch?v=_fEyVAdelfY
And here is a Photoshop mockup that illustrates a static view of what I envision:
http://img131.imagevenue.com/img.php?image=93066_AGC_meter_project_1a_122_35lo.jpg
Any help is appreciated in advance!
Kind Regards,
David
by trogluddite on Fri Dec 17, 2010 3:36 pm
Yes, you're right, the GUI part of SM is certainly counterintuitive!
I'll try to put a the fundamentals in this first post - apologies if it is a little too 'for dummies'
Firstly, I'd concentrate on simply being able to place GUI parts where you want them on screen - the animated display you're after is actually quite tricky as it involves manipulating bitmaps (more couter-intuitive still!)
Here's a little schematic to put a bar across a view at in reponse to a 'height' input.

Bar Example.osm
The MGUI (top left) handles screen positioning and display for the module it is inside. The unlabelled wireless input links the GUI to 'higher level' modules, so that the graphics can appear as a component part of a bigger front panel (without this you'll only see the GUI when navigating your schematic)
Along the top you can see a row of GUI primitives (Redraw, Rectange and Line). The data flow in GUI's is kind of 'backwards' - the chain of elements feeds into the GUI from right to left - with the furthest element (The line) appearing on top of the nearest (the Rectangle).
The View Area (connected to MGUI) finds the size and position of the GUI (for this module only) on screen - making the module aware of your positioning and re-sizing of the module when you place it on your front panel. The data from this is used as a reference when working out all of the other co-ordinates used.
Taking the chain of other GUI primitives in order...
1) Redraw Area
Whenever this sees a trigger it will re-draw the graphics. Its area is fed directly from the View Area - so that only the area covered by this graphic is redrawn (not the whole screen). The trigger coming from the 'Float Changed' makes sure that ReDraws are only done when the input changes (unnecessary ReDraws suck up CPU!)
2) Rectangle
Again, our background wants to cover the whole GUI, even if we decide to re-size it - so its area input comes direct from the View Area primitive.
3) Line
As you correctly pointed out - a line of given thickness is the same as a rectangle (but uses less CPU to draw!)
The line primitive uses a view area input in a slighly odd way - the area specifies the position and size of an imaginary rectangle, with the resulting line spanning the diagonal of that rectangle.
To work out the coordinates for the line, we need to do some calculation based on the view area - the Area to Float gives us a simple numeric output of the view position, width and height - Area to Float does the reverse, it takes our calculated co-ordinates and turns them into an Area for feeding to other GUI primitives.
The X-position and Width are easy - we want the line to span the full width of the GUI - so those float values copy straight across from the Area>Float to the Float>Area.
The Float>Area height is also easy - the line is horizontal (no shift in height between the two ends) - so the Float>Area height input just gets a big fat zero.
The Y position needs a little maths...
Firstly, I've subtracted the input from 1 - SMs GUI co-ordinates count from top to bottom (opposite to the graphs most of us are used to), so this operation reverses the input so that the line moves upwards as the input value rises.
The position is then multiplied by the height (from the Area>Float), so that an input range of 0-1 is scaled to the full height of the GUI regardless of how it might be re-sized)
Hopefully, that's more helpful than confusing!
by RRSounds on Fri Dec 17, 2010 4:54 pm
Thanks for the quick reply, trogluddite!
You've given me a lot of food for thought.
Wireless links are another concept I am having a tough time grasping. I see these all over the place in other people's modules! I especially wondered about that wireless link to no-where in the upper left of your example. How exactly does that link to something else, and how can I know what it is linking to (if anything?)? It's not lableled...
David
by trogluddite on Fri Dec 17, 2010 5:30 pm
Wireless links are very handy but there are several rules to watch out for...
1) The type of data must match between transmitter and receiver - e.g. an integer transmitter will not be received by a float receiver etc. The best way to be sure is to right click the wireless icon's connector circle, and then select the data type from the popup. (this works for regular input/output connectors too). Leaving SM to decide the data type automatically can sometimes lead to problems re-loading schematics.
2) The receiver and transmiatter name must match - the name checking is case-sensitive, and aware of spaces in names, so you need to be very accurate! Transmitters with the same name, but different data types, can co-exist because of rule 1, and they will remain unaware of each other.
3) A transmitter connects to all receivers (that meet conditions 1 & 2), that are at a lower level of the schematic. So if a module contains a transmitter, it will be received within any 'child' modules, but not by it's 'parent' module.
The way I think of it, is that the module containing the transmitter also 'contains' the 'radio-waves' that send the message - they do not 'leak-out' into the wider schematic, but can be received by any sub-module (no matter how deep they are buried).
This is the real power of wireless connections - you can have module nested within module nested within module...etc., but still send data to the deepest levels without needing endless inputs/outputs/links to carry the data there.
The unlabelled MGUI receiver is a special case. The transmitter that it connects to is not explicit - you will never see it.
What is does is to connect the GUI of your module (a knob or slider, for example) to any 'master' GUI (the front panel where your controls are all arranged, for example).
If you look at the stock filter/oscillator modules etc., you see a front panel with several controls - if you go inside, you will see the individual controls as sub-modules - the unlabelled wireless handles the placing of the controls on the main panel. (that's why the wireless in my example shows up as 'unlinked' - because it is not yet placed within a larger 'mother' module)
If you were to give that connector a name, then it would behave just like a regular wireless link, and seek out a matching transmitter to link to.
by RRSounds on Fri Dec 17, 2010 8:56 pm
Can you tell me where to find the "Float Changed" block? I don't see it in the Toolbox. Or is it something you made yourself?
Thanks!
David
by trogluddite on Fri Dec 17, 2010 9:13 pm
It was originally a design from the forum - but the new SM2 upgrade has it as a module in the 'Flow' category.
You can also add any module you like to your toolbox.
1) Give the module a name.
2) Open the toolbox category where you would like to keep it.
3) Drag the module into the toolbox.
by RRSounds on Fri Dec 17, 2010 10:57 pm
- trogluddite wrote:It was originally a design from the forum - but the new SM2 upgrade has it as a module in the 'Flow' category.
- You can also add any module you like to your toolbox.
- 1) Give the module a name.
- 2) Open the toolbox category where you would like to keep it.
- 3) Drag the module into the toolbox.
Yeah I figured out module renaming and saving in the toolbox a few days ago but thanks!
I have not opened SM2 yet, since I'm just now getting used to the version I just bought. I'll do it over the weekend.
Oh, by the way, I put together your drawing (using a 100 trigger instead of the 'float change') and with a little duplication, got my meter up and running with the two independent lines, working fine, switching colors and everything!
Now to figure out the history part. I think I may need to use arrays and some kind of circular buffer for this, and I can see I'm in for an adventure!
Thanks again, trogluddite; your graphics tutorial was incredibly useful!
-David
Re: Metering with history
by RRSounds on Wed Jan 26, 2011 5:31 pm
Dear Friends:
I have gotten my feet wetter in SM.
The "Draw Graph" primitive does an amazing job of almost exactly what I am looking for, described above. It spits out a trace from the right side of its rectangle indicator box, and multiple data streams appear to move left over time. Perfect.
But there's one huge problem (isn't that the way it always is? LOL!).
For any more than a few tens of milliseconds of data display, the graphics demand is just overpowering.
And if I want to display several seconds' history, and use relatively wide pens to draw one or more of the traces, the whole program slows to molasses speed. Certainly can't use one, never mind eight or ten of these as indicators!
slow meter trace test 1-26-2011.osm
So I'm thinking there must be a better way.
I recognize that what is happening is that the data for a few seconds is a huge amount to process. But in reality, the display needs far less to create the visual picture I am looking for.
In the attached file, the display is ten blocks wide, which is 80 pixels. So every refresh needs to display 80 stored values per stream displayed.
Since the vertical resolution is 60 boxes (representing the top 60 dB of RMS input range in this case) that's 480 pixels tall, a vertical resolution requirement of of less than 9 bits. Therefore every refresh frame needs to display, worst case, 480x80 bits (4800 bytes) of data.
Refreshed at a rate of 25 Hz (using the admittedly sloppy tick 25 timing), for two seconds that's a total memory requirement of 80x480x25x2, or 1,929,000 bits; 240,000 bytes for the entire rectangular area. But we don't need to refresh the whole rectangle, just what's changed, so the idealized refresh CPU demand should be far smaller than that.
Contrast that to what the machine is (apparently) actually having to deal with: If I want to display two seconds worth of input history, that would be (at 44.1 kb SR) 88,200 32-bit samples:
Processing 44,100x2x32 or 2,822,400 bits per stream ( of which there will be at least 2 streams per indicator).
Big diff.
Any thoughts on how I can make this thing work without so much CPU overhead? Am I overlooking something really simple? Or is this just reality I have to deal with? Maybe my math sucks? LOL!
Kind Regards,
David
Re: Metering with history
by trogluddite on Wed Jan 26, 2011 6:40 pm
You might find these threads useful...
Light Trails, New Oscilloscope, Goniometer
...they're all little projects that used a similar method to display graphics with a 'history'.
Basically, the 'historical' data is written into a temporary bitmap, over which new data is written. Writing a btmap to the screen is far less CPU intensive than plotting vector graphics, especially if you want scrolling or fading animations. Without it (not my invention BTW) these schematics never would have been viable.
For more general hints on lower graphics CPU load, there's a good thread Lower GUI CPU Load - a collaboration between several of us to pool the techniques we've discovered.
Unfortunately though, if you want to plot an area of that size, it will have a major impact on your CPU - SM just seems to have a particularly inefficient screen refresh routine. (Watch your Task Manager CPU meter while quickly wiggling one of the stock knobs and you'll see what I mean!).
I had my fingers crossed that SM2 would see an improvement, but sadly not
by infuzion on Thu Jan 27, 2011 6:33 am
Use a Trigger Divide on the tick25 by 2; animators say it is OK for ~15FPS.
link
link
link
|