| « First dragon-year post! | Welcome to 2012! » |
Busy boy
I'm a busy boy. How busy?
https://github.com/jamshark70/hadron/commits/master
(See January 8-10.)
Just today, I cracked the make-or-break problem for this entire project: driving a plugin called HrPresetMorph by external signals (where previously, you could drive it by the mouse only). Why is it critical? This plugin lets you put "presets" (sets of values taken from other plugins) on an x-y grid. Moving around in the grid calculates new presets exist in between the given ones, making a concrete relationship between two-dimensional position and sound.
The other part of the project is to get x-y coordinate data from webcam analysis and control sound by it. What could be more obvious than using the webcam coordinates to set the HrPresetMorph position? That's why, immediately after trying HrPresetMorph for the first time, I put this, "OMG!" and all, into my org-mode file:
****** TODO OMG! HrPresetMorph needs to be video-drivable!!!
That turned out to be several days' worth of work. First, the original plug-in couldn't be driven from outside, because the original design was to tweak every available parameter based on grid position. If the grid position itself is a tweakable parameter, then you fall into the computing black hole known as "infinite recursion" where the grid position makes a new grid position, which makes a..... So I had to prevent that and, for good measure, let the user decide which parameters to control instead of assuming all of them. The method to calculate the new values was a mess (inefficient, and the result depends on factors not directly related to the math). Then the result sounded choppy because it sent several momentary updates every second, and didn't generate smooth curves. That called for a thorough rework of the connection between the new data and the audio processing.
At the end of all that, I can say confidently:
- It was worth it -- it's working beautifully.
- I now know the pain of every IT consultant in the world.
The bread-and-butter of IT consulting is to come into a company and fix up somebody else's code. Invariably, the code is not written the way you would have done it, leading to a number of "what were they thinking?" moments. (TheDailyWTF is an extensive compendium.) I'll spare the details, except for my usual sermon (probably familiar to readers of the SuperCollider mailing list) about separating data storage and processing from interface objects.
Hadron (the original project) doesn't maintain this separation, and it's caused me no end of trouble. Just one recent example, from a plug-in that uses text to generate a synthesis function for control signals When loading a patch from disk, the function text is set by sticking it into the graphic interface and then calling an action function in the interface. No problem, right? We put the text into the TextView, so, asking the TextView what it's holding should give you the same text back.
Except, in the interface framework that the students will be using for this project, that doesn't happen. So the patch initializes incorrectly and doesn't sound like it did before saving.
The solution is that the text should be kept in a variable, apart from the interface. But isn't that too much trouble? No, it's sensible design. Variables are intended for data storage. They don't do anything else, and what they do, they do extremely well. Interface objects have to do a whole lot else, and the additional complexity means that a slight change in circumstances, timing etc. could produce a different result. It's not acceptable to get different results based on a butterfly flapping its wings close to your mouse.
In short, this kind of thing:
{ |somethingGottenFromDisk|
anInterfaceObject.valueAction = somethingGottenFromDisk;
}
... is a bad idea. DON'T DO IT.
I should add, though, that Batuhan Bozkurt, the original author, displayed a level of patience in creating the user interaction that I would simply not have had. My complaints diminish neither his achievement, nor my gratitude that there is this code to fix up in the first place. I intend this as a cautionary tale for future work, not as an indictment.
Whew! After all of that, I think I might need another one of these:
For over a year in Guangzhou, I have been looking for anything resembling a porter, without success. Then, in the Olé Food Halls in Taikoo Hui mall ("Food Halls" -- ha! you're not Harrod's): some half-liter cans of Fuller's London Porter. You'd have needed a forklift to pry my jaw off the floor.
For those who don't know my predilection: Porter is The Best Ale I Know. Guinness Stout is widely available here, but it's one-dimensional by comparison -- too bitter, too heavy. Porter has the heft of a stout, but with an extra note of sweetness giving it a more complex character.
The Fuller's does not disappoint. Unfortunately, it's priced to remain nothing more than an occasional, very special treat. But even the one taste... ah! Civilization.
No feedback yet
Comments are not allowed from anonymous visitors. Please use the Contact link at the top or bottom of this page to email me for a user account. This is just an antispam measure.

