<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-36882700</id><updated>2012-01-23T19:38:11.203-08:00</updated><title type='text'>FFRend</title><subtitle type='html'>Development notes for the &lt;a href="http://ffrend.sourceforge.net/"&gt;FFRend&lt;/a&gt; Freeframe Renderer.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>39</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-36882700.post-8200804309554100380</id><published>2012-01-23T19:22:00.000-08:00</published><updated>2012-01-23T19:38:11.220-08:00</updated><title type='text'>Important FFRend bug fix; testers needed please!</title><content type='html'>The last released version of FFRend (2.2.1.5) had a bug that caused the entire desktop to flicker whenever a row view was updated. Since just about every command updates one or more row views, the desktop flickered like crazy. You'd think I would have noticed it during testing but I normally run FFRend full-screen. I'm pretty embarrassed about it. Anyway please take the latest version, which fixes this lame bug and some others too.&lt;br /&gt;&lt;br /&gt;Download:&lt;br /&gt;&lt;a href="http://ffrend.sourceforge.net/download.html"&gt;FFRend download&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I would greatly appreciate it if any FFRend users who hang out here would take the new version out for a spin and report back if they see anything weird. I'm especially worried about the row view code, because that's what caused the desktop flicker bug in the first place. The Freeframe Parameter and MIDI Setup row views are now supposed to remember the scroll position separately for each plugin. Try switching back and forth between a plugin that's scrolled and one that isn't. Do you see any painting artifacts, or does the view paint smoothly?&lt;br /&gt;&lt;br /&gt;This version also fixes a bunch of problems related to synchronization of oscillators between plugins, which crept in with V2 as side effects of parallel processing. The earlier versions of V2 would lose sync between plugins at the drop of a hat. It should be a lot better now. The problem was basically that in a pipeline each plugin has its own frame of reference in terms of time, so it's necessary to compensate for that in various places. To debug it I had to make a pair of special Freeframe plugins, one that stamps its parameter directly onto the frame as a number, and another that draws its parameter onto the frame as a waveform, like an oscilloscope. They're pretty handy actually. I can make them available if anyone wants them...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-8200804309554100380?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/8200804309554100380/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=8200804309554100380' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/8200804309554100380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/8200804309554100380'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2012/01/important-ffrend-bug-fix-testers-needed.html' title='Important FFRend bug fix; testers needed please!'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-8713295172706440029</id><published>2011-12-31T14:31:00.001-08:00</published><updated>2011-12-31T14:39:24.086-08:00</updated><title type='text'>time travel: oscillator slippage</title><content type='html'>The V2 parallel-processing rework of FFRend was a huge win overall, but it also introduced subtle bugs, some of which are taking a long time to be discovered. Another one turned up yesterday: oscillator slippage can occur due to time shift between plugins. In a pipeline, the further a given stage is from the output, the further into the future that stage is compared to the output. Any queuing between stages increases the difference even more.&lt;br /&gt;&lt;br /&gt;Suppose a project contains two plugins, A and B, each containing one oscillator. A inputs to B, and B is connected to the output. The two oscillators have exactly the same frequency and appear to be in perfect sync. But if we stop FFRend in the debugger and examine the two oscillators, we'll find that they don't have the same value! A's oscillator is ahead by a small amount. This is because A is working ahead of B, i.e. A is operating on a frame that hasn't arrived at B yet. This unavoidable; it's how pipelines (or assembly lines) increase throughput. We need to careful when we say that A and B appear to be in sync. What we really mean is that A and B are in sync in the output! This the synchronization we care about. A and B should be out of sync when viewed from an external point of view (e.g. the debugger) because that's our proof that parallel processing is occurring.&lt;br /&gt;&lt;br /&gt;However this necessary time shift means that complications can and do occur. For example, suppose we save the project. As currently coded, we're just copying the current values of oscillators to the project file. But the current values aren't all from the same time! In other words, the current value of A's parameter represents a state several frames ahead of B's state, which is several frames ahead of the output's state. Consequently, if we reopen the project, the oscillators won't be in sync in the output, despite the fact that they were in sync when the project was saved. The error occurs because we're violating an implicit assumption that all the values in the project file are from the same frame of reference.&lt;br /&gt;&lt;br /&gt;To solve this problem, the save function needs to compensate the oscillator values for time shift. This should be doable because a) oscillators are periodic functions and can therefore be stepped in either direction with predictable results, and b) each plugin knows exactly how many frames ahead it is relative to the output state.&lt;br /&gt;&lt;br /&gt;Note that this problem is unaffected by pause, i.e. the problem occurs regardless of whether the engine was paused when the project was saved. This is because pausing the engine doesn't reset the frame pipeline (unlike stopping the engine, which does); all the frames are frozen in mid-flight, so however far ahead a given plugin was when the engine was paused, it remains that way.&lt;br /&gt;&lt;br /&gt;An additional, related problem was observed: inserting a plugin while the engine is running also causes oscillators to slip. Here the issue is even more subtle. The engine can only modify the plugin array while stopped, therefore inserting a plugin necessarily involves stopping and restarting the engine. However stopping the engine resets the pipeline, discarding any frames that were in progress but not yet output. Thus when the engine is restarted, all the plugins initially have the same frame of reference. But the oscillators still have the same states they had at the moment the engine stopped, when the plugins all had different frames of reference! Consequently there's now a mismatch between a plugin's oscillator states and what frame it's processing. The further from the output the plugin is, the larger this mismatch is, and the worse the slippage is.&lt;br /&gt;&lt;br /&gt;This problem can be solved similarly to the one described above, by compensating each plugin's oscillators as needed in the case where the engine is restarting.&lt;br /&gt;&lt;br /&gt;As previously mentioned, these problems took a long to show up, and even when they did it wasn't simple to verify them, because of time uncertainty. The most reliable tool for observing them was an invention I should have thought of long ago: a Freeframe plugin that simply writes its parameter to the input frame, as text. If you modulate the parameter with an oscillator, you're now stamping each output frame with an unambiguous record of how that oscillator's state changed over time. Most importantly, you're seeing the value the oscillator had when its parent plugin processed that frame, regardless of any time shifts due to pipeline backlog within the engine.&lt;br /&gt;&lt;br /&gt;The plugin needs extra parameters for controlling the position of the text with the frame, so that different instances don't overwrite each other's text, but other than that it's totally straightforward. I'm thinking of making a similar plugin that draws the parameter as a waveform, like an oscilloscope.&lt;br /&gt;&lt;br /&gt;Tests also show that even within a single plugin, oscillators may slip (become out of phase with each other), though the slippage is of a much lower order of magnitude. Whether they slip or not depends on the numerical relationship between their respective frequencies. For example:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Freq A  Freq B    Slippage&lt;br /&gt;.1      .05       none&lt;br /&gt;.1      .0125     none&lt;br /&gt;.1      .0333333  .0002 after 2 million frames&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This type of slippage is due to the use of floating-point in the oscillator, so there's probably not much to be done about it, but more research is needed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-8713295172706440029?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/8713295172706440029/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=8713295172706440029' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/8713295172706440029'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/8713295172706440029'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2011/12/oscillator-slippage.html' title='time travel: oscillator slippage'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-7036981529917758639</id><published>2011-12-29T22:48:00.000-08:00</published><updated>2011-12-29T22:53:01.595-08:00</updated><title type='text'>Fauve colorizing plugin released</title><content type='html'>Good news everyone! The FFRend project has released an exciting new Freeframe plugin that colorizes video in the style of Fauvism! Some still images demonstrating its effect are shown below.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://whorld.org/ffrend/temp/histoviz.jpg"&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://whorld.org/ffrend/temp/elevatedAB.jpg"&gt;&lt;br /&gt;&lt;br /&gt;The second example is taken from this short (15 second) &lt;a href="http://whorld.org/ffrend/temp/elevated_fauve.mp4"&gt;demo clip&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The Fauve plugin is packaged in ckffplugs-1.0.13, available for download here:&lt;br /&gt;&lt;a href="http://ffrend.sourceforge.net/download.html"&gt;http://ffrend.sourceforge.net/download.html&lt;/a&gt;&lt;br /&gt;(Freeframe Plugins, Binary Release)&lt;br /&gt;And for those who care about such things the source is there also.&lt;br /&gt;&lt;br /&gt;The plugin is a visualization of a histogram but using pseudocolor instead of the customary graph. Pixels are colored according to the popularity of their original colors in the input image, such that more common input colors translate to brighter output colors. The effect enhances edges, adds texture, simplifies and drastically alters the palette, and reduces spatial cohesion. In Luma mode, the plugin:&lt;br /&gt;&lt;br /&gt;1. Calculates the frame's luma histogram.&lt;br /&gt;2. Replaces each pixel with a greyscale value corresponding to that pixel's rank in the luma histogram. The histogram is normalized so that pixels in the top rank are assigned white in the output, while pixels in lower ranks receive proportionally darker values.&lt;br /&gt;&lt;br /&gt;RGB mode is similar, but does the above operations separately for each color channel, resulting in color output instead of greyscale.&lt;br /&gt;can read about it how it works.&lt;br /&gt;&lt;br /&gt;No doubt André Derain is rolling in his grave...&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.sanderhome.com/Fauves/d11.jpg"&gt;&lt;br /&gt;&lt;br /&gt;André Derain, The Houses of Parliament (1906)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-7036981529917758639?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/7036981529917758639/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=7036981529917758639' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/7036981529917758639'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/7036981529917758639'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2011/12/good-news-everyone-ffrend-project-has.html' title='Fauve colorizing plugin released'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-4916375481728250662</id><published>2011-12-27T12:51:00.000-08:00</published><updated>2011-12-27T13:11:05.182-08:00</updated><title type='text'>FFRend adds playlist feature: handy for installations</title><content type='html'>The latest version of FFRend (2.2.01) introduces a playlist, better integrates the load-balancing feature, improves memory management, and fixes a number of bugs.&lt;br /&gt;&lt;br /&gt;FFRend can now automatically open a series of projects, also known as a playlist. This feature is primarily intended to allow unattended use of FFRend, e.g. in an installation or gallery setting, though it's also helpful for VJs who need a break during a show. The user specifies the list of projects, the interval between project changes, whether the list should be played in sequential or random order, and whether it should loop. The playlist can be passed via the command line, in which case FFRend starts up with the playlist playing. This is particularly useful in combination with the new /fullscreen command-line option, which causes FFRend to start up full-screen on whichever monitor contains the output window.&lt;br /&gt;&lt;br /&gt;The Load Balance feature was converted from a modal dialog to a control bar, allowing load to be monitored continuously during normal operation. The command is now View/Load Balance instead of Edit/Load Balance.&lt;br /&gt;&lt;br /&gt;FFRend's handling of low memory conditions was improved, and advanced options were added which allow memory use to be limited in various ways. This can be helpful when working with large frame sizes.&lt;br /&gt;&lt;br /&gt;Download:&lt;br /&gt;http://ffrend.sourceforge.net/download.html&lt;br /&gt;&lt;br /&gt;Release Notes:&lt;br /&gt;http://ffrend.sourceforge.net/relnotes.html&lt;br /&gt;&lt;br /&gt;FFRend (Freeframe Renderer) is a free, open-source renderer for Freeframe V1 plugins. It allows you to chain any number of plugins together in any type of routing, automate their parameters using oscillators, and display the output full-screen and/or record it to a file. FFRend has a modular interface, includes MIDI and dual-monitor support, supports plugin authoring via metaplugins, and leverages multicore CPUs by running each plugin in its own thread.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-4916375481728250662?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/4916375481728250662/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=4916375481728250662' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/4916375481728250662'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/4916375481728250662'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2011/12/ffrend-adds-playlist-feature-handy-for.html' title='FFRend adds playlist feature: handy for installations'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-2352499097667495637</id><published>2011-12-21T13:12:00.000-08:00</published><updated>2011-12-27T20:13:25.870-08:00</updated><title type='text'>Bifurcations: digital emulations of analog video feedback</title><content type='html'>Lately I've been experimenting with digital emulations of analog video feedback, with interesting results. I enclose a link to sample clips below. All the projects in this family share the constraint of having no "content" (i.e. source plugins) other than Radar and WaveGen. No clips or Whorld, just Radar, WaveGen, and feedback (usually multiple luma feedback loops with different effects on each loop). I'm particularly excited about "Starry Night" and "Fireplace".&lt;br /&gt;&lt;br /&gt;&lt;a href="http://ffrend.sourceforge.net/movies.html#glitchgiving"&gt;Bifurcations&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;However there's an unexpected problem. I'm finding that I can't get the kind of results shown in these clips without using some kind of mirror, kaleidoscope, or similar effect. I get the best results by automating the scale parameters of IscHypnotic. This is contrary to what I know about analog feedback. For analog feedback all I typically need is:&lt;br /&gt;&lt;br /&gt;1. Looping: in analog this is created by pointing the video camera at the monitor, but in digital the equivalent is e.g. an alpha mixer, luma key, or chroma key with one of its inputs looped back from the output.&lt;br /&gt;&lt;br /&gt;2. Decay offset: in analog this is usually accomplished with a TBC, but in digital various types of color or luma shifts can be substituted.&lt;br /&gt;&lt;br /&gt;3. Motion: in analog, the motion typically comes from moving the camera, but in digital a simple pan/spin/zoom should in theory work.&lt;br /&gt;&lt;br /&gt;But when I try digital setups this simple, I don't get interesting results unless I make the motion component much more complicated. This isn't necessarily bad, but it does give the output a characteristic look (radial, or at least symmetrical). In the case of IscHypnotic it also introduces significant pixelization, which is one of the main objections to digital feedback.&lt;br /&gt;&lt;br /&gt;Another interesting result is enclosed below. The FFRend project that generated this image always converges on the state shown. Perturb it all you like, and it either breaks completely or converges again. The branches are a perfect demonstration of the role of bifurcation in natural systems. If you ever had any doubts that nature is chaotic, this should dispel them.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://whorld.org/temp/branches800x600.jpg"&gt;&lt;br /&gt;&lt;br /&gt;But why does this particular project do it? I don't have any other projects that create this shape, and I can't get it to work without IscHypnotic either. It's all very puzzling. What is the role of the mirror/kaleidoscope/hypnotic in all this? The "Fireplace" clip suggests that there might be a way around it.&lt;br /&gt;&lt;br /&gt;Examine the texture in the "Etched Chaos" clip. At some points it resembles feathers, or scales. Again it's clearly organic, and reminiscent of Mandelbrot and other fractals. There's a critical tipping point where it starts "budding" like a plant, but then it quickly exhausts itself and the moment slips away. Could it be possible to stabilize it?&lt;br /&gt;&lt;br /&gt;Sensitivity to initial conditions is just the nature of chaos. I remember from the analog days that the feedback setups were absurdly sensitive. It was fussy work that required patience and a steady hand, and some people were better at it than others. There were magical cameras, magical monitors, even magical cables. Sometimes two cameras of the exact same model behaved drastically differently for no obvious reason. Nonetheless people managed to stabilize intense bifurcations for minutes or hours.&lt;br /&gt;&lt;br /&gt;Back in the day, analog feedback purists often told me that I would never get similar results digitally. Electric Sheep was an interesting counter-example, but wasn't directly comparable since it's not even close to being a real-time process. I always held that it was just a question of time, and that parallel processing and Moore's law would eventually catch up. All of these new projects run at 30 FPS at XGA resolution on an i7 PC. The results convince me (and some of my most hard-headed analog purist friends) not only that it's possible to convincingly emulate analog feedback in real time, but that digital feedback has the potential to exceed analog feedback in terms of aesthetic variety.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-2352499097667495637?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/2352499097667495637/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=2352499097667495637' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/2352499097667495637'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/2352499097667495637'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2011/12/lately-ive-been-experimenting-with.html' title='Bifurcations: digital emulations of analog video feedback'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-8876625527057187087</id><published>2011-05-19T13:21:00.000-07:00</published><updated>2011-12-27T13:24:30.140-08:00</updated><title type='text'>Load balancing</title><content type='html'>FFRend 2.1.00 adds an important performance-related feature (load balancing), and fixes a large number of bugs, some of them serious. Issues marked (V2) are specific to version 2.&lt;br /&gt;&lt;br /&gt;For more on how to use load balancing, see the &lt;a href="http://ffrend.sourceforge.net/Help/Loose_Ends/Load_balance.htm"&gt;load balancing manual page&lt;/a&gt;. For the theory behind load balancing, see my article &lt;a href="http://ffrend.sourceforge.net/doc/pipeline_demo/pipelining.html"&gt;Pipelining for Plugin Chains&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;1. A load balancing dialog was added, which allows multiple threads to be assigned to a plugin. Given sufficient cores, load balancing can greatly improve throughput in the common case where some plugins require significantly more CPU time than others (asymmetrical loading). The dialog is accessed via Edit/Load Balance or Shift+L. Load balance settings are stored in the project. Note that load balancing is only effective for stateless filters: assigning multiple threads to a stateful filter may cause output strobing.&lt;br /&gt;&lt;br /&gt;2. Changing the frame rate in the Options dialog caused an incorrect recording length if the record duration was specified in time (as opposed to frames). Fixed.&lt;br /&gt;&lt;br /&gt;3. The single step command wasn't updating the slider positions of modulated parameters. Fixed. (V2)&lt;br /&gt;&lt;br /&gt;4. In the history view, the zoom setting now persists in the registry. (V2)&lt;br /&gt;&lt;br /&gt;5. In the history view, the renderer's display name was changed from Output to Renderer, to be consistent with the other views. (V2)&lt;br /&gt;&lt;br /&gt;6. The file browser's list control had an extra border (in XP and up) which appeared as a thin black outline. Fixed.&lt;br /&gt;&lt;br /&gt;7. In the file browser, some editing keys (Delete, Insert, Escape, Ctrl+Z) behaved unexpectedly during label editing: they triggered app behaviors instead of edit control behaviors. Fixed.&lt;br /&gt;&lt;br /&gt;8. Pressing the Escape key while dragging a plugin tab, patch row, or metaparameter row failed to cancel the drag operation. Fixed. (V2)&lt;br /&gt;&lt;br /&gt;9. Pressing the Escape key failed to cancel a drag operation if a dialog row control had focus. Fixed.&lt;br /&gt;&lt;br /&gt;10. If an error occurred while restoring the job control state, invalid jobs could result and persist. Partial data is now purged, and the user is given the option to delete the potentially corrupt job control file.&lt;br /&gt;&lt;br /&gt;11. Restarting the engine caused frame queues to be destroyed and recreated, incurring needless overhead; the queues are now resized instead. (V2)&lt;br /&gt;&lt;br /&gt;12. The options dialog was converted from a dialog to a property sheet, allowing related options to be grouped into pages for easier comprehension.&lt;br /&gt;&lt;br /&gt;13. Changing the MIDI device can be slow if the CPU is heavily loaded, so a wait cursor is now shown, and the main frame is explicitly updated to ensure that the options dialog erases cleanly.&lt;br /&gt;&lt;br /&gt;14. The sync oscillators command (Edit/Sync Oscillators) was initially removed in V2, but it's been restored. (V2)&lt;br /&gt;&lt;br /&gt;15. The graph view was causing a handle leak, in which each graph update would leak two process information handles. The bug could be demonstrated by resizing the graph view. Fixed. (V2)&lt;br /&gt;&lt;br /&gt;16. Deleting a plugin or opening a new project could cause a serious memory leak, which would occur while shrinking the frame buffer pool. As many as two frames could leak, depending on whether any of the deleted frames were currently assigned to a DirectDraw surface. Repeatedly undoing and redoing a plugin deletion would eventually demonstrate the bug. Fixed. (V2)&lt;br /&gt;&lt;br /&gt;17. Dropping files onto the app from Explorer would leak heap memory, due to OnDropFiles failing to call DragFinish. Fixed.&lt;br /&gt;&lt;br /&gt;18. Left-clicking a parameter slider's thumb without moving it added an undo event, even though the parameter value was unchanged. Fixed.&lt;br /&gt;&lt;br /&gt;19. Opening a recent file via the file menu could cause the file menu to bounce, i.e. redisplay unexpectedly. This occurred after deleting a row in the Parameter, Patch, MIDI Setup, or Metaparameter views, while one its controls had focus, which would cause a hidden form view to receive focus. Fixed. (V2)&lt;br /&gt;&lt;br /&gt;20. If MIDI Setup was showing a plugin-specific page, and one of the page's row controls had focus, attempting to select a main menu command via the Alt key would cause an infinite loop, permanently hanging the app. This is the infamous WM_GETDLGCODE bug, solved by removing the DS_CONTROL style from the MIDI Setup dialog. Fixed.&lt;br /&gt;&lt;br /&gt;21. If a metaparameter was added while the Metaparams view was hidden, and the MIDI Setup view was visible and showing its Metaparam page, the new metaparameter wouldn't immediately appear in MIDI Setup. It would appear when  the MIDI Setup view was next updated, e.g. by hiding and reshowing it or selecting a different page. This could occur when creating a metaparameter via the main view's context menu. Fixed. (V2)&lt;br /&gt;&lt;br /&gt;22. In the MIDI and Metaparameter views, the header columns didn't line up correctly with their corresponding controls, due to a row item coordinate conversion error. Fixed. (V2)&lt;br /&gt;&lt;br /&gt;23. Right-clicking the History view's scroll bars showed the view's context menu, instead of the scroll bar context menu. Fixed. (V2)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-8876625527057187087?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/8876625527057187087/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=8876625527057187087' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/8876625527057187087'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/8876625527057187087'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2011/05/load-balancing.html' title='Load balancing'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-6018066660811415570</id><published>2010-06-20T13:18:00.000-07:00</published><updated>2011-12-27T13:20:20.979-08:00</updated><title type='text'>FFRend V2: multicore version released!</title><content type='html'>FFRend 2.0.00 is a near-total rewrite, not an upgrade. The application was completely redesigned from the ground up to take advantage of the parallel-processing capabilities of today's multi-core CPUs.&lt;br /&gt;&lt;br /&gt;Major differences&lt;br /&gt;&lt;br /&gt;1. Each plugin now runs in its own thread, and given sufficient cores, each plugin runs on its own core, so that throughput is limited only by the slowest plugin (Amdahl's law).&lt;br /&gt;2. The user interface is now much more responsive, even when the CPU is heavily loaded, because rendering no longer occurs in the UI thread.&lt;br /&gt;3. The built-in clip player was replaced by an enhanced version of PlayerFF which allows clips to be opened by path, or by dragging from the Files bar's Clips pane.&lt;br /&gt;4. Monitor quality has been improved and now has two settings (fast or smooth), specified in the options dialog. Even the fast setting is still an improvement over version 1.&lt;br /&gt;5. Multiple instances of the same plugin are now differentiated by decorating their names, e.g. PeteMixer-1, PeterMixer-2, etc.&lt;br /&gt;6. Plugins with more than two inputs are now supported.&lt;br /&gt;7. A Graph view is now available, which shows a dynamically updated graph of your current routing. Note that you must download and install graphviz to use this feature.&lt;br /&gt;8. Two additional new views, History and Queues, provide dynamic information about the rendering engine, allowing you to easily determine which plugins are limiting throughput.&lt;br /&gt;9. The frame rate can now be unlocked, so that the engine renders as fast as possible, or at the monitor refresh rate in full-screen mode. &lt;br /&gt;&lt;br /&gt;Minor differences&lt;br /&gt;&lt;br /&gt;1. The Record command was moved from the View menu to the File menu, and the Options command moved from the View menu to the Edit menu.&lt;br /&gt;2. The Export and Record commands no longer automatically pause the output.&lt;br /&gt;3. The Bypass command no longer alters the routing. This can cause significantly different behavior, particularly when bypassing source plugins.&lt;br /&gt;4. All sizing control bars now have a system menu option to control whether they're dockable.&lt;br /&gt;5. There's no longer a distinction between Full-Screen and Exclusive modes, i.e. Full-Screen mode is always Exclusive. Consequently the app's UI is no longer accessible in Full-Screen mode without using a dual-monitor setup.&lt;br /&gt;6. Metaplugins are still fully supported. Note however that metaplugins are internally single-threaded, i.e. a metaplugin's component plugins do not run in parallel with each other. Consequently, on a multicore machine, a typical metaplugin will run more slowly than the equivalent project.&lt;br /&gt;7. If a plugin can't render because it's not routed to the output, any parameter modulations it has will not automate their corresponding sliders in the UI.&lt;br /&gt;8. The Global Plugin and Monitor Source Selection features were removed.&lt;br /&gt;9. The app now builds in VC++ 9.0.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-6018066660811415570?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/6018066660811415570/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=6018066660811415570' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/6018066660811415570'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/6018066660811415570'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2010/06/ffrend-v2-multicore-version-released.html' title='FFRend V2: multicore version released!'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-5699698746254042420</id><published>2010-04-24T13:56:00.000-07:00</published><updated>2010-04-24T13:59:03.566-07:00</updated><title type='text'>FFRell (FFRend in parallel) coming soon</title><content type='html'>There's been lots of progress on FFRell, the parallel-processing version of FFRend. I'm currently running FFRell at 1024 x 768 on a purpose-built i7 box (8 CPUs with Hyperthreading) and seeing frame rates from 30 to 60 Hz for quite complex patches. FFRend has been completely rebuilt around a multithreaded pipelined rendering engine. Each plugin runs in its own thread, and frames are routed via thread-safe zero-copy pointer queues.&lt;br /&gt;&lt;br /&gt;I started by building a test system called ParaPET (Parallel Plugin Engine Test) which is an interesting project by itself; see the enclosed screen shot. Basically ParaPET is a tool for modeling the problem of optimal parallelism for arbitrary signal routes. The first case I had to deal with was feedback. If plugin A takes input from plugin B, and B also takes input from A, neither plugin can get started and the engine stalls. The solution is to prime one of the plugins, i.e. feed it blank frames until the feedback loop is closed and becomes self-sustaining. But first you need a general way of identifying such cases in all their permutations. ParaPET features a spider object which recursively crawls the plugins looking for feedback.&lt;br /&gt;&lt;br /&gt;The other interesting case is when a plugin's output can arrive at a downstream mixer via multiple routes of different lengths. A simple example would be a source plugin that connects to both inputs of a mixer, one directly and the other via an effect. In such cases you'll get staggering, i.e. the plugins won't execute in parallel despite available CPUs. The solution is to add delay to the shorter route, so that the route lengths become equal again. Delay is added to a route by increasing the size of the corresponding frame queue.&lt;br /&gt;&lt;br /&gt;This turned out to be a pretty hard problem to solve for all possible cases. Again the solution was recursion. The same crawl that detects feedback also gathers the necessary information for route balancing: for each plugin, 1) its maximum distance from the final output, and 2) for each sink mixer it's connected to, its distance from that mixer (distances are measured in hops, just as in network topology). With this information in hand, for each plugin, we can determine its longest route to a sink mixer, and compensate any shorter routes accordingly.&lt;br /&gt;&lt;br /&gt;I came up with dozens of tough asymmetric test cases, including three- and four-input mixers, and the spider handles them all. It works so well I'm considering releasing ParaPET as a separate project. It's not tied to video processing so it would make a good general framework for pipelined parallel execution of interdependent tasks. If you're interested in playing with it let me know...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://ffrend.sourceforge.net/temp/ParaPET.gif"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 1024px; height: 768px;" src="http://ffrend.sourceforge.net/temp/ParaPET.gif" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Once I got the engine working in ParaPET, I started building a new app (ParaFFEn) that used the same thread architecture but with FreeFrame plugins and actual video frames. The goal was to eventually port the engine into FFRend, but after hours of surgery the patient died: FFRend was just too single-thread oriented and couldn't adapt, so I gave up and started rebuilding FFRend from scratch, starting with ParaFFEn's engine.&lt;br /&gt;&lt;br /&gt;After a long hard slog, FFRell can now read FFRend projects and run them in full-screen dual-monitor Exclusive mode. All of FFRend's GUI elements are included except the file browser and monitor bars. FFRell also includes the nifty dynamic graph view from ParaPET (courtesy of GraphViz), plus the scrolling execution history and queue views. What's not working includes recording, clipboard support, MIDI, and undo. Also FFRell can't create metaplugins, though it can load them. Plenty to keep me busy this summer. I hope to have a reasonably stable version by Q3.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-5699698746254042420?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/5699698746254042420/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=5699698746254042420' title='34 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/5699698746254042420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/5699698746254042420'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2010/04/ffrell-ffrend-in-parallel-coming-soon.html' title='FFRell (FFRend in parallel) coming soon'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>34</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-3356499561852444980</id><published>2007-12-08T15:37:00.000-08:00</published><updated>2007-12-18T15:44:24.796-08:00</updated><title type='text'>MIDI control of monitor source</title><content type='html'>These are the changes needed to implement MIDI control of monitor source:&lt;br /&gt;&lt;br /&gt;in MidiInfo.h:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;enum {  // plugin MIDI properties&lt;br /&gt;    MP_BYPASS,&lt;br /&gt;    MP_MONITOR,&lt;br /&gt;    PLUGIN_MIDI_PROPS&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;in MainMidi.cpp:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;const int CMainFrame::m_PluginMidiPropName[PLUGIN_MIDI_PROPS] = {&lt;br /&gt;    IDS_MP_BYPASS,&lt;br /&gt;    IDS_MP_MONITOR&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;case MP_MONITOR:&lt;br /&gt;    if (Toggle)&lt;br /&gt;        Val = (GetMonitorSource() != ParmIdx);&lt;br /&gt;    {&lt;br /&gt;        bool    IsMod = IsModified();&lt;br /&gt;        SetMonitorSource(Val &gt;= .5 ? ParmIdx : -1);&lt;br /&gt;        SetModify(IsMod);   // restore modify flag&lt;br /&gt;    }&lt;br /&gt;    break;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above change also requires a new version of the project file format, otherwise errors will occur in CFFPlugInfo::Serialize due the increased size of m_MidiInfo. This probably could have been avoided if the size of m_MidiInfo had been serialized, but it's too late for that now. The only remaining option is an explicit version test. Note that the version being tested is from the next level up, i.e. it's a CFFProject version, not a CFFPlugInfo version. The CFFPlugInfo version must be increased too, so that the clipboard format changes.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;// this was tested and works fine&lt;br /&gt;int MidiInfoSize = Version &gt; 4 ? sizeof(m_MidiInfo) : sizeof(CMidiInfo);&lt;br /&gt;...&lt;br /&gt;ar.Write(m_MidiInfo, MidiInfoSize);&lt;br /&gt;...&lt;br /&gt;ar.Read(m_MidiInfo, MidiInfoSize);&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-3356499561852444980?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/3356499561852444980/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=3356499561852444980' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/3356499561852444980'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/3356499561852444980'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2007/12/these-are-changes-needed-to-implement.html' title='MIDI control of monitor source'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-5095772901174725743</id><published>2007-09-27T15:36:00.000-07:00</published><updated>2007-12-18T15:37:34.416-08:00</updated><title type='text'>Thumbnail thread exit problem</title><content type='html'>If we're in thumbnail view, the thumbnail thread could be running, and we want it to exit, so we can safely launch another instance. We ask it to exit by incrementing the job ID; the thread checks the job ID after each extraction, and exits if the ID changes. This simple method has a weakness: there's a chance we preempted the thread after it checked the ID, but before it posted the bitmap to us, in which case we'll receive a spurious bitmap message. The thread is almost always busy extracting, so the chance is very small, but just in case, we increment the job ID before doing other work, thereby giving the thread more time to exit.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-5095772901174725743?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/5095772901174725743/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=5095772901174725743' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/5095772901174725743'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/5095772901174725743'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2007/09/thumbnail-thread-exit-problem.html' title='Thumbnail thread exit problem'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-7315796515972726751</id><published>2007-07-29T15:35:00.000-07:00</published><updated>2007-12-18T15:36:40.719-08:00</updated><title type='text'>Projects are affected by changing frame rate</title><content type='html'>Frame rate has turned out to be a major hassle. It probably would have been a good idea for projects to store the frame rate that was in effect which the project was saved, so that if the project is subsequently run at a different frame rate, the oscillator frequencies could then be compensated. Oh well.&lt;br /&gt;&lt;br /&gt;Practically speaking, all of the projects that are currently being prepared for DVD render correctly at 25 FPS ONLY. This includes&lt;br /&gt;&lt;br /&gt;big hex 27%&lt;br /&gt;UltraWhorld 3b&lt;br /&gt;UltraWhorld 4b&lt;br /&gt;&lt;br /&gt;Just to make things even more confusing, there's a problem with PeteKaleidascope on the XP machine: at Divisions = .03 (horizontal mirroring), it creates ghosts. This can be observed clearly with the UltraWhorld 4b patch. The solution is to use a mirror plugin instead.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-7315796515972726751?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/7315796515972726751/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=7315796515972726751' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/7315796515972726751'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/7315796515972726751'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2007/07/projects-are-affected-by-changing-frame.html' title='Projects are affected by changing frame rate'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-2219981660516475594</id><published>2007-07-13T14:32:00.000-07:00</published><updated>2007-07-13T17:55:29.867-07:00</updated><title type='text'>Hidden controls retain focus; child dialogs and DS_CONTROL</title><content type='html'>Version 1.4.03 (and previous versions) crash deterministically if you load (via drag/drop) a plugin with at least one parameter, then load (again via drag/drop) a plugin with NO parameters, and then spin the mouse wheel, or press one of the arrow keys or editing keys. This turns out to be an example of a more general problem: if a control has focus, hiding its parent dialog does NOT take focus away from the control. The control continues to receive mouse and keyboard input. This can cause unexpected behavior (e.g. the wheel moving an invisible control) or even crash the app. But why do we have hidden dialogs? Here's why.&lt;br /&gt;&lt;br /&gt;FFRend makes much use of the row view. This custom UI object is similar to a list view or grid control, but it's implemented as a form view containing a vertical list of child dialogs, one per row. A row dialog is just like any other dialog: it has a resource, contains controls, can be built using the Class Wizard, and can even be tested outside the containing view. The main advantage of this approach is encapsulation: row dialogs derive from a base class which makes it easier to operate on entire rows at once (e.g. for cut/copy/paste). By contrast, in a grid control, everything is contained in a single window, so there's no equivalent to a row object.&lt;br /&gt;&lt;br /&gt;FFRend uses the row view to display plugin parameters, patchbay, MIDI setup, and metaparameters. In the case of plugin parameters, there's a complication: each plugin has different parameters, but only one plugin's parameters are visible at a time. FFRend allows each plugin to have its own set of row dialogs, and then shows and hides entire sets of row dialogs as needed. For example, when a plugin is selected, the previously selected plugin's rows are hidden, and the new plugin's rows are shown. This approach is wasteful in terms of memory, windows, and GDI objects, but efficient in terms of CPU usage: hiding/showing windows is cheap compared to creating and destroying them. The approach has another advantage: since we can assume that while a plugin exists, its parameter row dialogs also exist, we can store the parameter and automation data in the row controls, instead of storing them elsewhere and updating the controls on demand. This is elegant, and simplifies undo handling. So that's why we have hidden dialogs.&lt;br /&gt;&lt;br /&gt;As it turns out, a dialog has to have the DS_CONTROL style in order to behave well as a child of another window. People often encounter this issue when they try to make a home-grown property sheet, i.e. a series of child dialogs that can be overlaid onto a parent container dialog. The usual problem is that without DS_CONTROL, tabbing doesn't work as expected: the entire child dialog is treated as a single tab stop. DS_CONTROL integrates the child dialog's tab layout into the tab layout of the parent window. FFRend used to handle tabbing in row views explicitly, but now that it's using DS_CONTROL, Windows handles the tabbing.&lt;br /&gt;&lt;br /&gt;DS_CONTROL also improves window activation behavior: without DS_CONTROL, showing the parent window unexpectedly focuses the last control in the child dialog, and this can lead to the problem described above (hidden controls with focus). So DS_CONTROL is a very good discovery, and makes the row view UI much more robust, but it's still necessary to test for a hidden control with focus after updating the plugin parameters view. That's not such a big deal.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-2219981660516475594?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/2219981660516475594/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=2219981660516475594' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/2219981660516475594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/2219981660516475594'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2007/07/hidden-controls-retain-focus-child.html' title='Hidden controls retain focus; child dialogs and DS_CONTROL'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-2719384157988963699</id><published>2007-06-18T13:41:00.000-07:00</published><updated>2007-07-13T13:42:09.021-07:00</updated><title type='text'>XP/Uno drops input MIDI running status messages</title><content type='html'>The problem occurs when using WhorldRC to switch video clips quickly in the PlayerFF plugin. The problem first appeared when shortcut keys were added to WhorldRC for triggering recent clips. Before that it wasn't possible to switch clips fast enough to cause the bug. It seems that when MIDI messages are output close together in time, Windows uses MIDI running status, otherwise not. This was verified using the DOS mididump program. The running status messages are NOT received by the MIDI input callback under XP with the M-Audio Uno. This is true using both the driver that shipped with the Uno, and the Windows default driver. Note that with the latest M-Audio driver (MA_CMIDI_WDM_4.2.03v4.exe), the callback DOES receive events for the running status messages, but they are strangely garbled.&lt;br /&gt;&lt;br /&gt;Attempts to reproduce the problem using the X-Session as input were not succesful. Perhaps it's the particular nature of WhorldRC's output (b0 00 xx b0 01 xx) that causes the bug? The most likely suspects are the Uno itself, its driver, or XP's USB MIDI driver. One way to test this would be by using a different MIDI device.&lt;br /&gt;&lt;br /&gt;For the moment the workaround is a hack to WhorldRC: it sends a note off command after each set of bank/clip commands commands. This is a bit wasteful but WhorldRC is a low-bandwidth app and it seems to have no side effects.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-2719384157988963699?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/2719384157988963699/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=2719384157988963699' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/2719384157988963699'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/2719384157988963699'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2007/06/xpuno-drops-input-midi-running-status.html' title='XP/Uno drops input MIDI running status messages'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-7726764170689610254</id><published>2007-02-03T00:02:00.001-08:00</published><updated>2007-02-03T12:37:29.057-08:00</updated><title type='text'>meta-meta-meta-plugins</title><content type='html'>The MetaFFRend beta is available now. We actually had a bit a of a celebration here tonight. Not only does MetaFFRend work, but we proved that nesting is unlimited. It's easy to make a meta-metaplugin, a metaplugin that contains metaplugin(s) which contain plugins. Or even weirder combinations, like a metaplugin which uses a mixer plugin to do automated mixing between two metaplugins. (!!) The level of nesting is arbitrary, and there's essentially no performance penalty for it, because the overhead of the base plugins is always huge compared to the overhead from nesting.&lt;br /&gt;&lt;br /&gt;This is wild stuff, and not so impractical as it might sound. It means if I make a metaplugin that does something you like, and send it to you, you can use it inside one of your own metaplugins, add value to it somehow, and then send it someone else. By its very nature MetaFFRend encourages iterative composition, and distributed creation. It also means that you can simplify your own creative process by using grouping, in other words you can organize your own metaplugins in a hierarchy, with more basic effects at the bottom, e.g. a kaleidescope with automated rotation, and then reuse your building blocks (or other people's) in higher-level metaplugins.&lt;br /&gt;&lt;br /&gt;Not only that, but embedding can be nested too, though ONLY if all the metaplugins at each level are "free", i.e. include the word "copyleft" in their author/license field. So for example if I send you one of my embedded metaplugins, and it's copyleft, you can embed it inside one of your metaplugins, and if you specify copyleft too, your metaplugin can also be embedded by someone else, and so on... And at each level the embedding works as expected, so the final plugin can be loaded into a host like any other plugin, and automatically unzips itself recursively the first time you load it. None of the recipients needs to worry about missing plugins. How about that.&lt;br /&gt;&lt;br /&gt;The real point here is that it gives you, me, all of us a super-compact way to transport compositions. A complicated metaplugin might be 300K bytes, WITH embedding, without, less than 100K. Compare this to the cost of transporting a 30-second movie file, even compressed. The problem I've been trying to solve is that while Whorld operates in vector space, as soon as I apply effects to it, the output is video, which is a huge storage problem. But now I don't need to store anything. Instead of making a movie, I just send you a metaplugin that contains the Whorld plugin, running through a bunch of effects with automated parameters. It looks THE SAME as it did on my machine, but no goddamn gigantic movie file, and no compression either. You can render it to a movie file if you want, at any resolution you like, and if I used randomness in my Whorld patches (or in my automations), it will do something different every time you run it. The static movie file is replaced by an algorithm that's capable of dynamic behavior, user interaction, etc. Visual effects can be made quickly, without programming, even made live, and then easily transported, to be used and/or modified by others.&lt;br /&gt;&lt;br /&gt;What this really does is push Whorld (and any other freeframe visual synths) back into vector space. It's a whole new type of content, all the more because it's N-dimensional (due the nesting capability), and distinct from making videos or coding plugins or VJing. It's metaplugin authoring, I don't know what else to call it, but hey, I'm drunk. Whatever it is, it's wicked object-oriented.&lt;br /&gt;&lt;br /&gt;OK I'll shut up now and go drink some water. My head is starting to hurt and not just from programming.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-7726764170689610254?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/7726764170689610254/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=7726764170689610254' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/7726764170689610254'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/7726764170689610254'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2007/02/meta-meta-meta-plugins.html' title='meta-meta-meta-plugins'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-3767948386330321048</id><published>2007-01-19T14:35:00.000-08:00</published><updated>2007-01-19T20:31:51.734-08:00</updated><title type='text'>RFC: MetaFFRend / FF meta-plugin authoring</title><content type='html'>&lt;span style="font-weight:bold;"&gt;Request for Comments&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;OK, now that FFRend 1.3 is out the door, it's time to get serious about MetaFFRend. I hope to spark a bit of pre-coding discussion here, so that once the coding starts we can get it mostly right the first time. Here are some issues that have been bumping around in my head.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Summary&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is a Request For Comments regarding the VJ Forums proposal to turn FFRend into a plugin-authoring tool, somewhat similar to Pete Warden's FreeChain application. The idea is basically to export a FFRend project as a Freeframe plugin. This "meta-plugin" could be loaded into a Freeframe host software, and would behave just as if you were running the equivalent project in FFRend.&lt;br /&gt;&lt;br /&gt;The meta-plugin may contain links to the plugins it requires, or alternatively, the plugins may be "bundled" into the meta-plugin. In the latter case, it's easier to distribute the meta-plugin, because there's no dependence on external files. Specifically, a meta-plugin will consist of FFRend's rendering engine, links to (or compressed copies of) the necessary plugins, and the project data (parameter settings, automations, etc).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Linked plugins and bundling&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A meta-plugin contains links to other plugins. This works fine as long as the meta-plugin stays on the PC where it was created, but as soon as you distribute it, you have problems. There's very little chance that the absolute paths will happen to be correct on someone else's PC. IMO the solution has two parts. The first part is, the meta-plugin should search for its plugins in an intelligent way, e.g. the following steps, in order:&lt;br /&gt;&lt;br /&gt;1) Try the absolute paths from the project data first.&lt;br /&gt;2) Then look for an INI file, e.g. My Documents\FFRend\MetaFFRend.ini, which could contain a plugin path, e.g. PluginPath=C:\whatever;C:\foo;&lt;br /&gt;3) Next, try My Documents\FFRend\Plugins.&lt;br /&gt;4) Finally, look in the same folder the meta-plugin was loaded from.&lt;br /&gt;5) If none of the above works, add an error message to a log file, e.g. My Documents\FFRend\MetaFFRend.log&lt;br /&gt;&lt;br /&gt;The second part of the solution is, there should be an option to bundle all the plugins that the meta-plugin requires into the meta-plugin. This could make the meta-plugin quite large, so it probably makes sense to compress the plugins, e.g. using zlib which is open-source. The first time you load a bundled meta-plugin, it will unpack itself to the folder specified in MetaFFRend.ini, or if that fails, to My Documents\FFRend\Plugins. On subsequent loads it will detect that the plugins are already there, and skip the unpack. This means the meta-plugin could be slow to load the first time, but subsequent loads will be fast.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Meta-parameters&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Like any other FF plugin, a meta-plugin can expose parameters to the host. These parameters are referred to as "meta-parameters". The consensus on this forum was that each meta-parameter should be able to control multiple things. When I say "things" I mean control targets; the potential targets in FFRend are not only FF parameters, but also modulator settings (frequency, waveform, etc.), bypass, and other properties. The reason why this is such an important capability, is that many hosts severely limit the number of FF parameters a plugin can expose. By allowing "grouping", the meta-plugin can make better use of a limited number of parameters.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Anatomy of a Meta-Plugin&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The base MetaFFRend DLL (i.e. without any project data embedded in it) lives in the same folder as FFRend. It has a tag at the end of the DLL file, consisting of 16 characters: BASEMETAFFREND01&lt;br /&gt;&lt;br /&gt;When FFRend creates a new meta-plugin, it starts with the base plugin. It removes the end-of-DLL tag and replaces it with the project data, followed by a different tag, also 16 bytes, like so:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;char    Id[10];     // must contain characters MetaFFRend&lt;br /&gt;WORD    Version;    // version number&lt;br /&gt;DWORD   DataOfs;    // offset of project data from end of DLL file&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;What's nice about this scheme is it's easy to read the project data from the DLL: you just read the last 16 bytes, and now you know whether it's a valid meta-plugin, and if so, where to find the project data. Project data is a CArchive, and starts with a CMetaPlugin header:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;CString m_PluginName;       // plugin name, 16 characters maximum&lt;br /&gt;CString m_Description;      // a description of the plugin&lt;br /&gt;CString m_AboutText;        // author and license information&lt;br /&gt;int     m_BitDepthMask;     // mask of supported bit depths&lt;br /&gt;int     m_PluginMajorVersion;   // number before decimal point&lt;br /&gt;int     m_PluginMinorVersion;   // number after decimal point&lt;br /&gt;int     m_NumInputFrames;   // number of input frames plugin expects&lt;br /&gt;CDWordArray m_InpTargetIdx; // for each input frame, index of target sub-plugin, or -1 for default&lt;br /&gt;bool    m_IsBundled;        // true if sub-plugins are bundled into meta-plugin&lt;br /&gt;bool    m_IsCompressed;     // true if bundled sub-plugins are compressed&lt;br /&gt;CMetaParamArray m_Param;    // information about each meta-parameter&lt;br /&gt;&lt;br /&gt;class CMetaParam:&lt;br /&gt;&lt;br /&gt;CString m_ParamName;    // parameter name, 16 characters maximum&lt;br /&gt;float   m_Val;          // parameter's initial value&lt;br /&gt;CMetaParamTargetArray   m_Target;   // array of parameter targets&lt;br /&gt;&lt;br /&gt;class CMetaParamTarget:&lt;br /&gt;&lt;br /&gt;int     m_PlugIdx;      // index of destination plugin, or -1 for misc. property&lt;br /&gt;int     m_ParamIdx;     // index of destination parameter, or -1 for plugin property&lt;br /&gt;int     m_PropIdx;      // index of property&lt;br /&gt;float   m_RangeStart;   // start of parameter range&lt;br /&gt;float   m_RangeEnd;     // end of parameter range&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-3767948386330321048?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/3767948386330321048/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=3767948386330321048' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/3767948386330321048'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/3767948386330321048'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2007/01/rfc-metaffrend-ff-meta-plugin-authoring.html' title='RFC: MetaFFRend / FF meta-plugin authoring'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-712467812031083145</id><published>2007-01-13T01:27:00.005-08:00</published><updated>2007-01-13T02:16:21.447-08:00</updated><title type='text'>Heap-trashing bug also in RadialBlur, SpiralBlur &amp; TimeBlur</title><content type='html'>I previously reported finding a bug in Pete Warden's Mixer plugin. As it turns out, this bug also occurs in three other Pete plugins: RadialBlur, SpiralBlur, and TimeBlur. The original bug report for PeteMixer is &lt;a href="http://ffrend.blogspot.com/2006_12_01_archive.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;PeteMixer, PeteRadialBlur, PeteSpiralBlur, and PeteTimeBlur all have the same bug: they use MMX movq (64-bit move) in situations where movd (32-bit move) was intended. In all cases the results are the same: the two bytes immediately following the end of the output buffer get trashed, AKA munged, hosed, stomped, toasted, vaporized, etc.&lt;br /&gt;&lt;br /&gt;Since the output buffer is almost certainly on the heap, the consequences depend entirely on how the host uses the heap. This probably isn't deterministic, so depending on the circumstances the bug could cause strange and wonderful behavior, or crash the host, or have no effect all.&lt;br /&gt;&lt;br /&gt;I searched the plugin sources for other instances of movq, and found no other instances except in a few support modules. I haven't had time to wade through those modules yet, but my guess is they won't have the bug, since they weren't cut from the same cloth, as it were. The support modules that use movq are:&lt;br /&gt;&lt;br /&gt;BoxFilter&lt;br /&gt;Radiant&lt;br /&gt;ImageMath&lt;br /&gt;&lt;br /&gt;I have built UNOFFICIAL patched versions of the buggy plugins. You can download the binaries &lt;a href="http://ffrend.sourceforge.net/plugins/PetesPlugsCKPatches.zip"&gt;here&lt;/a&gt;, and the patched source files are &lt;a href="http://ffrend.sourceforge.net/plugins/PetesPlugsCKPatchesSource.zip"&gt;here&lt;/a&gt;. PeteMixer was patched previously, but I included it in the above downloads for completeness.&lt;br /&gt;&lt;br /&gt;I diffed the code carefully, and found no differences between my versions and the original that aren't "good" differences. For testing, I ran the original and the patched plugin side-by-side in FFRend, sent their outputs into a mixer, and A/B'd them to ensure that their output was identical.&lt;br /&gt;&lt;br /&gt;Here are the relevant MD5 checksums:&lt;br /&gt;&lt;br /&gt;BUGGY VERSIONS:&lt;br /&gt;PeteMixer BUGGY.dll                            5d7f65d48627e065f218bab5ee1d42a4&lt;br /&gt;PeteRadialBlur BUGGY.dll                       04551870addf5b3c8c14740e1aa7d316&lt;br /&gt;PeteSpiralBlur BUGGY.dll                       b1e66597fbebeac46e59a208fd893aba&lt;br /&gt;PeteTimeBlur BUGGY.dll                         c636cb633bc404f050497c4369f70241&lt;br /&gt;&lt;br /&gt;PATCHED VERSIONS:&lt;br /&gt;PeteMixer.dll                                  a4c78bfa1a34f895264c9e20e3c6b035&lt;br /&gt;PeteRadialBlur.dll                             93592d40a4c2b9470f601c0e20042c1b&lt;br /&gt;PeteSpiralBlur.dll                             f2f9b4f8d0740d170f87b173d9b1f83f&lt;br /&gt;PeteTimeBlur.dll                               031cc8426accc21df0989b34fe884f69&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-712467812031083145?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/712467812031083145/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=712467812031083145' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/712467812031083145'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/712467812031083145'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2007/01/heap-trashing-bug-also-in-radialblur_3482.html' title='Heap-trashing bug also in RadialBlur, SpiralBlur &amp; TimeBlur'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-2680461843855378701</id><published>2007-01-09T22:39:00.000-08:00</published><updated>2007-01-09T23:10:02.220-08:00</updated><title type='text'>Adapting CSizingControlBar to work without idle time</title><content type='html'>Since MFC generally relies on the existence of idle time, an MFC app that doesn't have idle time is arguably incorrectly designed. However, the theoretical multithreaded alternative is so difficult to implement correctly, that in practice, timer-driven MFC apps often do real work in their message loops, potentially using up all their idle time. My app (FFRend) is an example of this: since it processes video frames in OnTimer, if the processing becomes complex enough, idle time drops to zero.&lt;br /&gt;&lt;br /&gt;This approach causes serious problems for Cristi Posea's otherwise delightful &lt;a href="http://www.datamekanix.com/"&gt;CSizingControlBar&lt;/a&gt;. It also causes problems elsewhere in the app, but these are minor issues related to the UpdateCmdUI mechanism, or the status bar message line. In an app without idle time, CSizingControlBar exhibits the following undesirable behaviors:&lt;br /&gt;&lt;br /&gt;1. While the bar is docked, resizing it doesn't work: the bar is not repainted. This occurs because the sizing bar's implementation uses DelayRecalcLayout, which helps prevents flicker, but also relies on idle processing.&lt;br /&gt;&lt;br /&gt;2. When the bar is floated, the main frame's layout is not updated. Again, the cause is DelayRecalcLayout. Note that this problem also occurs with other control bars, not only the sizing bar.&lt;br /&gt;&lt;br /&gt;3. When the bar is floating, its Close button doesn't work: the bar remains visible, and left-clicking the edge of its frame causes the bar to shrink to a tiny rectangle.&lt;br /&gt;&lt;br /&gt;4. The docked bar's close button doesn't react to mouse-overs.&lt;br /&gt;&lt;br /&gt;I have found simple solutions for the first three problems. The last problem is still unsolved, but luckily it's the least serious one.&lt;br /&gt;&lt;br /&gt;Problems 1 and 2 can both be solved by conditionally calling RecalcLayout from main frame's OnTimer handler. The condition is a simple test for pending idle layout, specifically, if (m_nIdleFlags &amp; idleLayout) is true. I discovered this technique quite by accident in the "Professional UI Solutions" support forum.&lt;br /&gt;&lt;pre&gt; &lt;br /&gt;void CMainFrame::OnTimer(UINT nIDEvent) &lt;br /&gt;{&lt;br /&gt;    Sleep(40);  // emulate some work that consumes all our idle time&lt;br /&gt;&lt;br /&gt;#if ENABLE_NO_IDLE_FIXES    // ck&lt;br /&gt;    // CSizingControlBar uses DelayRecalcLayout, in order to avoid flicker when&lt;br /&gt;    // resizing docked bars.  DelayRecalcLayout requires idle processing, which&lt;br /&gt;    // normally isn't a problem, but this app typically doesn't have idle time.&lt;br /&gt;    // Our solution is to periodically test the idle flags, and if there's idle&lt;br /&gt;    // layout pending, call RecalcLayout.  This also ensures that the layout is&lt;br /&gt;    // updated when controls bars are floated (any bars, not just sizing ones).&lt;br /&gt;    if (m_nIdleFlags &amp; idleLayout)&lt;br /&gt;        RecalcLayout();&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;    CFrameWnd::OnTimer(nIDEvent);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Problem 3 is solved by customizing CMiniDockFrameWnd to handle WM_SYSMESSAGE. In OnSysMessage, if the ID is SC_CLOSE, hide the dock frame, via ShowWindow(FALSE).&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;void CSizingDockFrame::OnSysCommand(UINT nID, LPARAM lParam)&lt;br /&gt;{&lt;br /&gt;    CMiniDockFrameWnd::OnSysCommand(nID, lParam);&lt;br /&gt;    // in the default implementation, if there's no idle time, the close button&lt;br /&gt;    // doesn't work: the bar remains visible, and left-clicking the edge of its&lt;br /&gt;    // frame causes the bar to shrink to a tiny rectangle&lt;br /&gt;    if (nID == SC_CLOSE)&lt;br /&gt;        ShowWindow(SW_HIDE);    // but this does work&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Note that the derived dock frame must be installed in CMainFrame::OnCreate, by setting the CFrameWnd member m_pFloatingFrameClass, immediately after the call to EnableDocking.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    EnableDocking(CBRS_ALIGN_ANY);&lt;br /&gt;&lt;br /&gt;    // use a custom dock frame that can handle zero idle time&lt;br /&gt;    m_pFloatingFrameClass = RUNTIME_CLASS(CSizingDockFrame);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;With these two simple, lightweight fixes, CSizingControlBar works quite happily in an app without idle time. Ever now and then there's a happy ending. Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-2680461843855378701?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/2680461843855378701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=2680461843855378701' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/2680461843855378701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/2680461843855378701'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2007/01/adapting-csizingcontrolbar-to-work.html' title='Adapting CSizingControlBar to work without idle time'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-2938498620679685490</id><published>2007-01-06T16:55:00.001-08:00</published><updated>2007-01-06T16:55:59.119-08:00</updated><title type='text'>MetaFFRend : FFRend as a plugin authoring tool</title><content type='html'>I plan to re-purpose FFRend, from an effects renderer, to a plugin authoring tool, somewhat like Pete Warden's discontinued FreeChain project. This idea was proposed by Leo Mayberry (AKA KillingFrenzy) on VJ Forums, and seconded by many others. FFRend will be able to output a freeframe "meta-plugin" that behaves identically to a given FFRend project. A meta-plugin contains *links* to other plugins. A meta-plugin is a DLL containing FFRend's rendering engine, plus some project data (which plugins to load, parameter and automation settings, signal routing, etc).&lt;br /&gt;&lt;br /&gt;The project is in development, and about 50% done. I already have proof of concept: I can create a meta-plugin that runs a FFRend project from within any freeframe host. The main limitations are, 1) it's hard-coded which project the meta-plugin loads, and 2) no parameters are exposed to the host.&lt;br /&gt;&lt;br /&gt;The biggest headache is creating the GUI within FFRend for deciding which parameters the meta-plugin should expose to the host (I call these "meta-parameters"). Ideally a meta-parameter should be able to control different types of properties, not only plugin parameters, but also oscillator settings and so forth, as MIDI already does. Also, it would be nice if a single meta-parameter could control multiple properties (i.e. grouping). This is important because many hosts severely limit the number of freeframe parameters.&lt;br /&gt;&lt;br /&gt;The structure of the project data needs to be finalized soon. I'm working on that now. Meanwhile I'm also working on some ease-of-use features for FFRend: a dockable file browser with tabs for Projects, Plugins, and Clips, and a dockable preview window. Both features are commonly found in VJ software.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-2938498620679685490?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/2938498620679685490/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=2938498620679685490' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/2938498620679685490'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/2938498620679685490'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2007/01/metaffrend-ffrend-as-plugin-authoring.html' title='MetaFFRend : FFRend as a plugin authoring tool'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-6282034491515152601</id><published>2006-12-25T02:04:00.000-08:00</published><updated>2007-01-13T02:44:55.294-08:00</updated><title type='text'>PeteMixer trashes 2 bytes beyond output buffer</title><content type='html'>In version 1.15 of the Freeframe plugins, PeteMixer trashes the 2 bytes immediately following the output buffer. Version 1.14 also has the bug. I believe the bug also occurs in the AFX and VJo versions but I can't verify this directly.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[NOTE: this bug also occurs in PeteRadialBlur, PeteSpiralBlur, and PeteTimeBlur. For more info see &lt;a href="http://ffrend.blogspot.com/2007_01_01_archive.html"&gt;here&lt;/a&gt;.]&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The memory violation only occurs with the MMX version of the plugin. Interestingly, the non-MMX version of PeteMixer also fails, but in a different way: it always outputs black.&lt;br /&gt;&lt;br /&gt;In the non-MMX version, the output colors are shifted right 16 when 8 was intended.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;//  nOutputBlue&gt;&gt;=16;   // ck: shifting twice as much as needed&lt;br /&gt;    nOutputBlue&gt;&gt;=8;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The MMX error is the use of movq when movd was intended. The output pointer pCurrentOutput is a 32-bit pointer, and it's being incremented by one (i.e. four bytes) for each iteration, which means that on the last iteration, writing 64 bits to *pCurrentOutput trashes the first two bytes of whatever happens to be above the output buffer in memory.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;//  movq    [esi],mm7   // ck: TRASHES 2 bytes beyond output buffer&lt;br /&gt;    movd    [esi],mm7   // ck: 32-bit move&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The input pointers are also using movq, and while this doesn't overwrite memory it could cause a protection violation.&lt;br /&gt;&lt;br /&gt;Theoretically the MMX version also uses more memory bandwidth than it needs to. I benchmarked it, and found that the corrected version is indeed slightly faster. For the original, 1000 calls to ProcessFrameCopy on a 640 x 480 frame took an average of 15.304 ms per frame, while the corrected version took an average of 14.820 per frame: a gain of 3%. I speculate that the gain is so small because the needless memory operations always hit L2 cache.&lt;br /&gt;&lt;br /&gt;Heap-trashing bugs are notoriously difficult to find, and this one was no exception. They don't always cause a crash, and even when they do, it typically happens much later, in some unrelated component. In fact it was precisely this symptom--bizarre failures in things that never failed before--that pointed me in the right direction.&lt;br /&gt;&lt;br /&gt;One disadvantage of writing such nice free plugins is that they're everywhere. I shudder to think how many mysterious crashes have been unjustly blamed on host applications. Ah, the joys and perils of inline assembler.&lt;br /&gt;&lt;br /&gt;You can download an UNOFFICIAL patched DLL &lt;a href="http://ffrend.sourceforge.net/plugins/PeteMixerCKBugFix.zip"&gt;here&lt;/a&gt;. For more info see the &lt;a href="http://ffrend.sourceforge.net/plugins/Mixer.cpp"&gt;patched source&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-6282034491515152601?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/6282034491515152601/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=6282034491515152601' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/6282034491515152601'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/6282034491515152601'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/12/petemixer-trashes-2-bytes-beyond-output.html' title='PeteMixer trashes 2 bytes beyond output buffer'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-7293107072616566691</id><published>2006-11-27T22:46:00.000-08:00</published><updated>2006-11-27T23:28:22.830-08:00</updated><title type='text'>SetSurfaceDesc memory leak</title><content type='html'>The CVideo object is leaking memory badly, and I'm surprised I never noticed it before. It leaks the entire DirectSurface every time a new video is opened. At 640 x 480 that's around 1 MB per open, which adds up fast. This could explain why Whorld misbehaves after many hours of triggering video clips.&lt;br /&gt;&lt;br /&gt;Initially I suspected VfW, but then I verified that VfW definitely cleans up after itself. The problem turns out to be with DirectDraw, specifically with SetSurfaceDesc.&lt;br /&gt;&lt;br /&gt;CVideo's constructor creates a default 1 x 1 memory surface. When a video is opened, CVideo attaches this surface to the video frame, using SetSurfaceDesc. This is a major optimization: it allows CVideo to avoid using GDI to blit each video frame to the DirectDraw surface, because the video frame IS the DirectDraw surface. In practice SetSurfaceDesc only needs to be called once, when the video opens, because VfW doesn't change the address of video frame after that. In fact it only changes the address if you open a video with a different frame size or pixel format, sensibly enough. CVideo checks for a change in frame buffer address, and if one occurs, it reattaches its surface to the new address.&lt;br /&gt;&lt;br /&gt;According to the MSDN on SetSurface, "The DirectDrawSurface object will not deallocate surface memory that it didn't allocate. Therefore, when the surface memory is no longer needed, it is your responsibility to deallocate it. However, when SetSurfaceDesc is called, DirectDraw frees the original surface memory that it implicitly allocated when creating the surface."&lt;br /&gt;&lt;br /&gt;I interpreted this to mean that once you've done at least one SetSurfaceDesc for a surface, you're on your own, as far as memory management. But what happens is, when the video is closed, DirectDraw leaves some object the same size as the frame buffer object allocated. It can't be VfW's frame buffer, because VfW destroys that when you call AVIStreamGetFrameClose. I can't imagine how or why this happens, but it sure isn't documented.&lt;br /&gt;&lt;br /&gt;I only found two ways to make DirectDraw release this mysterious hidden frame buffer. The obvious way is to destroy the surface, but I'd prefer not to do this, because it means destroying and re-creating the surface every time a video is opened, which seems wasteful. The other way is to call SetSurfaceDesc again, passing it a 1 x 1 dummy surface. This works fine, and only takes about 50 microseconds. The surface description never changes, so it can even be a static array.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;DDSURFACEDESC CVideo::m_DefSurf = {&lt;br /&gt;    sizeof(DDSURFACEDESC),  // dwSize&lt;br /&gt;    DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_LPSURFACE | DDSD_PIXELFORMAT,  // dwFlags&lt;br /&gt;    1,  // dwHeight&lt;br /&gt;    1,  // dwWidth&lt;br /&gt;    4,  // lPitch (Width * BitCount / 8)&lt;br /&gt;    0, 0, 0, 0, // dwBackBufferCount, dwMipMapCount, dwAlphaBitDepth, dwReserved&lt;br /&gt;    &amp;m_DefSurfMem, // lpSurface&lt;br /&gt;    {0, 0}, {0, 0}, {0, 0}, {0, 0}, // color keys&lt;br /&gt;    {&lt;br /&gt;        sizeof(DDPIXELFORMAT),  // dwSize&lt;br /&gt;        DDPF_RGB,   // dwFlags&lt;br /&gt;        0,          // dwFourCC&lt;br /&gt;        32,         // dwRGBBitCount&lt;br /&gt;        0xff0000,   // dwRBitMask&lt;br /&gt;        0x00ff00,   // dwGBitMask&lt;br /&gt;        0x0000ff    // dwBBitMask&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;DWORD CVideo::m_DefSurfMem; // pointed to by m_DefSurf.lpSurface&lt;br /&gt;...&lt;br /&gt;void CVideo::Close()&lt;br /&gt;{&lt;br /&gt;    // if surface exists, we must attach it to a default 1 x 1 memory surface,&lt;br /&gt;    // otherwise DirectDraw leaves a mysterious hidden frame buffer allocated&lt;br /&gt;    if (m_Surface != NULL)&lt;br /&gt;        m_Surface-&gt;SetSurfaceDesc(&amp;m_DefSurf, 0);   // prevents a major leak&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-7293107072616566691?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/7293107072616566691/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=7293107072616566691' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/7293107072616566691'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/7293107072616566691'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/11/setsurfacedesc-memory-leak.html' title='SetSurfaceDesc memory leak'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116439537874583101</id><published>2006-11-24T11:08:00.000-08:00</published><updated>2006-11-24T14:37:11.257-08:00</updated><title type='text'>Undo performance</title><content type='html'>The undo manager uses CArray to implement the undo history. As a result, the performance of undo notification varies significantly depending on whether undo is limited, or unlimited. Performance was measured using a test function that repeatedly generates the same undo event, as shown below. To simulate realistic conditions, the test function was called from the timer hook, and the results were stored in an array and written after the test, avoiding potential interference from file I/O.&lt;br /&gt;&lt;br /&gt;If undo is unlimited, notification time is mostly constant, except when the CArray has to grow. Since growing entails copying the entire array to a new memory location, the time required to grow the CArray increases linearly with the number of undoable edits. In a test of 10000 iterations, undo notification took an average of 50 microseconds. The actual samples were nearly indistinguishable from the average, except when the array grew, resulting in peaks which increased linearly, up to 1.6 milliseconds by the end of the test. The time between peaks also increased linearly as expected, due to MFC's heuristic method of computing the grow size. There were also a few seemingly random, unexplained spikes of nearly 2.5 milliseconds.&lt;br /&gt;&lt;br /&gt;If undo is limited, notification time is constant. This is because once the limit is reached, adding a new notification deletes the oldest event from the history. Deleting from the front of a CArray requires copying the entire array down one element, but the array size is constant, so there's no memory reallocation, and the time required to do the copy doesn't change. In a test of 10000 iterations, undo notification took an average of 60 microseconds, only 10 microseconds more than the unlimited case. The actual samples were similar to the average, with randomly-spaced peaks up to around 150 microseconds. Again there were some unexplained spikes, though they were an order of magnitude lower, around 250 microseconds.&lt;br /&gt;&lt;br /&gt;Note that OnPlugBypass with undo notification commented out takes an average of 38 microseconds, so in all  cases undo notification takes longer than other work performed by OnPlugBypass.&lt;br /&gt;&lt;br /&gt;Conclusion: undo performance is suboptimal, due to the use of CArray. An implementation based on CList would almost certainly perform better for unlimited undo, and probably the same or slightly better for limited undo. This optimization needs to be weighed against substantially increased complexity in the undo manager, e.g. array indexing would have to be replaced by iteration.&lt;br /&gt;&lt;br /&gt;This hypothesis was tested by slapping together a minimally functional CList-based implementation and repeating the test. The result: for unlimited undo, the average time was 48 microseconds, and the actual samples showed only minor deviations, e.g. 80 or 150 microseconds, except for the occasional unexplained 2.5 millisecond spike. On the other hand, the undo manager complications look pretty formidable.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;static  const   MAX_SAMPS = 10000;&lt;br /&gt;float   samp[MAX_SAMPS];&lt;br /&gt;int samps = 0;&lt;br /&gt;void CMainFrame::OnTimer(UINT nIDEvent)&lt;br /&gt;{&lt;br /&gt;    if (m_Plugin[0].IsCreated()) {&lt;br /&gt;#if 0   // zero for unlimited undo&lt;br /&gt;        if (!samps)&lt;br /&gt;            m_UndoMgr.SetLevels(100);&lt;br /&gt;#endif&lt;br /&gt;        OnPlugBypass();&lt;br /&gt;        if (samps == MAX_SAMPS) {&lt;br /&gt;            FILE *fp = fopen("undo bench.txt", "wc");&lt;br /&gt;            for (int i = 0; i &lt; samps; i++)&lt;br /&gt;                fprintf(fp, "%d\t%f\n", i, samp[i]);&lt;br /&gt;            fclose(fp);&lt;br /&gt;            exit(0);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;#include "benchmark.h"&lt;br /&gt;extern float samp[];&lt;br /&gt;extern int samps;&lt;br /&gt;void CFFPlugsDlg::OnPlugBypass() &lt;br /&gt;{&lt;br /&gt;    int sel = GetCurSel();&lt;br /&gt;    if (sel &gt;= 0) {&lt;br /&gt;CBenchmark  b;&lt;br /&gt;        NotifyUndoableEdit(UCODE_BYPASS);&lt;br /&gt;samp[samps++] = float(b.Elapsed());&lt;br /&gt;        BypassPlugin(sel, !IsPluginBypassed(sel));&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116439537874583101?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116439537874583101/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116439537874583101' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116439537874583101'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116439537874583101'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/11/undo-performance.html' title='Undo performance'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116313690583021407</id><published>2006-11-09T21:34:00.000-08:00</published><updated>2006-11-09T21:35:05.836-08:00</updated><title type='text'>Synchronizing automations to clip length</title><content type='html'>The manual method is pretty straightforward, though it does require a calculator. Take FFRend's ideal frame rate (NOT the video clip's frame rate, that doesn't matter), and divide it by the video clip's frame count. Now multiply the result by 100. Enter that number in the Master speed toolbar, and you're all set, though you might also want to pause, rewind the clip, and sync the oscillators.&lt;br /&gt;&lt;br /&gt;This scheme redefines the frequency unit, from Hertz to clip passes. A frequency of 1 will repeat once per clip pass, 2 will repeat twice per clip pass, .5 will repeat every other clip pass, etc.&lt;br /&gt;&lt;br /&gt;The X 100 accounts for the fact that master speed is a percentage.&lt;br /&gt;&lt;br /&gt;For example, if the clip is 1859 frames long, and it's playing at 25 FPS:&lt;br /&gt;&lt;br /&gt;Master Speed = 25 / 1859 * 100 =  1.3448&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116313690583021407?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116313690583021407/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116313690583021407' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116313690583021407'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116313690583021407'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/11/synchronizing-automations-to-clip.html' title='Synchronizing automations to clip length'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116284427422830429</id><published>2006-11-06T12:13:00.000-08:00</published><updated>2006-11-06T13:20:42.690-08:00</updated><title type='text'>frame buffer bit counts</title><content type='html'>PlayerFF works in Resolume and Flowmotion, but not in OpenTZT, because OpenTZT passes 24-bit frames to the plugin, even though the screen resolution is 32-bit. The underlying problem is that you can't use DirectDraw to blit between surfaces with different bit counts. I tell my AVI reader (AviToBmp) to uncompress the video into the best format for the display (by passing AVIStreamGetFrameOpen AVIGETFRAMEF_BESTDISPLAYFMT). I use SetSurfaceDesc to turn the video frame into a DirectDraw surface, which means if my display is set for 32 bits, my video frame is also 32 bits, regardless of the actual color depth of the video. That's optimal if the host frame buffers also have the display's bit count, which you would think they would, but in OpenTZT, they don't for some reason, so the blit fails with error E_NOTIMPL.&lt;br /&gt;&lt;br /&gt;AVIStreamGetFrameOpen can be also passed a BITMAPINFO that tells it what format to decompress to. This allows me force the the video format to match the host's format, as follows:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;BITMAPINFOHEADER bih;&lt;br /&gt;ZeroMemory(&amp;bih, sizeof(bih));&lt;br /&gt;bih.biSize = sizeof(bih);&lt;br /&gt;bih.biWidth = m_pBmpInfo-&gt;bmiHeader.biWidth;&lt;br /&gt;bih.biHeight = m_pBmpInfo-&gt;bmiHeader.biHeight;&lt;br /&gt;bih.biPlanes = 1;&lt;br /&gt;bih.biBitCount = 24; // or whatever host wants&lt;br /&gt;m_pGetFrame = AVIStreamGetFrameOpen(m_pStream, &amp;bih);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Another solution is to just accept that PlayerFF won't work in OpenTZT. Most VJ softwares don't need a player plugin anyway, because they already have elaborate media players built into them. Let's not forget that PlayerFF is primarily designed for use in FFRend!&lt;br /&gt;&lt;br /&gt;Another problem: OpenTZT and Flowmotion display PlayerFF's output upside-down, but it looks fine in Resolume and FFRend. Something's pretty wrong there...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116284427422830429?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116284427422830429/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116284427422830429' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116284427422830429'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116284427422830429'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/11/frame-buffer-bit-counts.html' title='frame buffer bit counts'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116284401330855616</id><published>2006-11-06T12:05:00.000-08:00</published><updated>2006-11-06T12:13:33.323-08:00</updated><title type='text'>plugin ID must be unique in Resolume</title><content type='html'>It appears that Resolume uses the plugin ID to keep track of its freeframe plugins. It came up because PlayerFF was using FFDemoSrc's plugin ID, and since FFDemoSrc happened to also be in Resolume's plugin folder, selecting PlayerFF actually selected FFDemoSrc instead. Flowmotion doesn't exhibit this behavior. So the freeframe documentation doesn't lie: plugin ID really does need to be unique! One wonders what non-authority is responsible for coordinating this...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116284401330855616?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116284401330855616/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116284401330855616' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116284401330855616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116284401330855616'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/11/plugin-id-must-be-unique-in-resolume.html' title='plugin ID must be unique in Resolume'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116283618937809750</id><published>2006-11-06T10:02:00.000-08:00</published><updated>2006-11-06T10:03:09.380-08:00</updated><title type='text'>PlayerFF: freeframe clip player</title><content type='html'>I got my standalone freeframe clip player up last night. It's called PlayerFF (OK maybe it needs a better name). It handles AVI/BMP/JPG/GIF, and has three parameters so far:&lt;br /&gt;&lt;br /&gt;Clip Select (which clip you're playing)&lt;br /&gt;Pause (0 is play, any other value is pause)&lt;br /&gt;Position (0 is the start of the clip, 1 is the end)&lt;br /&gt;&lt;br /&gt;The clips are hard-coded at the moment. :(&lt;br /&gt;&lt;br /&gt;Here's what I propose for clip management. The plugin should have both a "Clip Select" and a "Bank Select" parameter. It will look in the magical folder "\My Documents\PlayerFF". Any clips it finds there will wind up in bank zero, UNLESS the magical folder contains an optional playlist file. The playlist file must be called playlist.txt, and it contains the paths of the clips to load, one per line, with optional bank separators. Clips are loaded in the order they appear in the playlist, or if there's no playlist, in alphabetical order.&lt;br /&gt;&lt;br /&gt;:0&lt;br /&gt;C:\temp\avi files\Night Traffic.avi&lt;br /&gt;C:\temp\avi files\earth1.avi&lt;br /&gt;C:\temp\avi files\Boat Ride to Punta Sal (xvid).avi&lt;br /&gt;C:\temp\avi files\01_24_04-med.avi&lt;br /&gt;:1&lt;br /&gt;C:\temp\avi files\tint.avi&lt;br /&gt;C:\temp\avi files\kissinggirls.avi&lt;br /&gt;C:\Chris\images\debbie\DSC_0080.jpg&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116283618937809750?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116283618937809750/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116283618937809750' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116283618937809750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116283618937809750'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/11/playerff-freeframe-clip-player.html' title='PlayerFF: freeframe clip player'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116283611709671994</id><published>2006-11-06T09:59:00.000-08:00</published><updated>2006-11-06T10:01:57.103-08:00</updated><title type='text'>plugin and project info can have different parameter counts</title><content type='html'>I just found a neat bug. I added some parameters to my new PlayerFF plugin, and when I loaded up a FFRend project that uses it, there was garbage in the modulation settings for the new parameters.&lt;br /&gt;&lt;br /&gt;It turns out I was assuming that the plugin's number of parameters, and the number of parameters I have information about in the project file, are always the same. That's normally the case of course, but a new version of the plugin with more (or less) parameters violates that assumption. Oops.&lt;br /&gt;&lt;br /&gt;And the solution:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;// the plugin's number of parameters might not match our info's parameter count,&lt;br /&gt;// for example if it's a different version of the plugin; take whichever is less&lt;br /&gt;int rows = min(GetPluginRows(PlugIdx), Info.m_Parm.GetSize());&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116283611709671994?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116283611709671994/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116283611709671994' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116283611709671994'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116283611709671994'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/11/plugin-and-project-info-can-have.html' title='plugin and project info can have different parameter counts'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116228684381588353</id><published>2006-10-28T01:27:00.000-07:00</published><updated>2006-10-31T01:27:23.816-08:00</updated><title type='text'>how to keep frame counter from clobbering toolbar hints</title><content type='html'>in CMainFrame::OnNotify:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;case AFX_IDW_TOOLBAR:&lt;br /&gt;    if (nmh-&gt;code == TBN_HOTITEMCHANGE) {&lt;br /&gt;        LPNMTBHOTITEM   lpnmhi = (LPNMTBHOTITEM)nmh;&lt;br /&gt;        if (lpnmhi-&gt;dwFlags &amp; HICF_ENTERING)    // if entering toolbar&lt;br /&gt;            m_HideFrameCounter = TRUE;  // hide frame counter&lt;br /&gt;        else if (lpnmhi-&gt;dwFlags &amp; HICF_LEAVING)    // if leaving toolbar&lt;br /&gt;            m_HideFrameCounter = FALSE; // show frame counter&lt;br /&gt;    }&lt;br /&gt;    break;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116228684381588353?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116228684381588353/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116228684381588353' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228684381588353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228684381588353'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/10/how-to-keep-frame-counter-from.html' title='how to keep frame counter from clobbering toolbar hints'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116228681106831752</id><published>2006-10-28T01:26:00.000-07:00</published><updated>2006-10-31T01:26:51.066-08:00</updated><title type='text'>How to get a huge file size</title><content type='html'>&lt;pre&gt;&lt;br /&gt;static bool GetFileSizeEx(LPCSTR Path, LARGE_INTEGER&amp; Size)&lt;br /&gt;{&lt;br /&gt;    HANDLE hFile = CreateFile(Path, GENERIC_READ, FILE_SHARE_READ, &lt;br /&gt;        NULL, OPEN_EXISTING, 0, NULL);&lt;br /&gt;    if (hFile == INVALID_HANDLE_VALUE)&lt;br /&gt;        return(FALSE);&lt;br /&gt;    Size.LowPart = GetFileSize(hFile, (PULONG)&amp;Size.HighPart);&lt;br /&gt;    CloseHandle(hFile);&lt;br /&gt;    return(Size.LowPart != 0xFFFFFFFF || GetLastError() != NO_ERROR);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116228681106831752?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116228681106831752/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116228681106831752' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228681106831752'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228681106831752'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/10/how-to-get-huge-file-size.html' title='How to get a huge file size'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116228675223939672</id><published>2006-10-20T01:25:00.000-07:00</published><updated>2006-10-31T01:26:22.186-08:00</updated><title type='text'>More on matching original big hex</title><content type='html'>Considerable progress has been made, using a special version of WhorldFF that reads jumps times from a list, i.e. a file containing a list of the frame numbers at which to do random jumps. The frame numbers were determined by painstaking experimentation.&lt;br /&gt;&lt;br /&gt;The key concept is that in the version of FFRend that created original big hex, all of WhorldFF's parameters were initially set by the host. By comparison, in the current version of FFRend, parameters are only set if they differ from their defaults. So for example, number of rings defaults to .5. If it's .5 in the preset, it won't be sent to WhorldFF, so WhorldFF will use the patch's value (1000) instead of 154 (what .5 denormalizes to). The corrected preset uses a value of .500001 rather than .5, because this tricks FFRend into sending WhorldFF the parameter, but is also close enough to the desired number (.5) so that it makes no difference.&lt;br /&gt;&lt;br /&gt;Another thing: Tile's Cell Width and Cell height have to start at .54, not .5! No idea why but it's crucial. With this change we get exact matching at 640 x 480, except for very minor variations near the jump points.&lt;br /&gt;&lt;br /&gt;Oh and one more thing: original big hex's initial frame offset turns out to 65, not 67. This was obscured by the Tile Cell parameter error.&lt;br /&gt;&lt;br /&gt;Minor detail: still # 4454 was mislabeled, it's actually 4554.&lt;br /&gt;&lt;br /&gt;Iages 2288 and 2297 aren't correct even at 640 x 480, and since they're suspiciously close to the jump at 2283, it's likely that 2283 is misplaced. The 1105 image is also off (the jump is at 1104, a single frame before!).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116228675223939672?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116228675223939672/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116228675223939672' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228675223939672'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228675223939672'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/10/more-on-matching-original-big-hex.html' title='More on matching original big hex'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116228564943482804</id><published>2006-10-17T01:06:00.000-07:00</published><updated>2006-10-31T01:08:16.770-08:00</updated><title type='text'>qsort-based template class for sorting arrays</title><content type='html'>&lt;pre&gt;&lt;br /&gt;template&lt;class T&gt; class CSortArray {&lt;br /&gt;public:&lt;br /&gt;    static  void    Sort(T *a, int Size, bool Desc = FALSE) {&lt;br /&gt;        qsort(a, Size, sizeof(T), Desc ? CmpDesc : CmpAsc);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;private:&lt;br /&gt;    static  int CmpAsc(const void *arg1, const void *arg2) {&lt;br /&gt;        if (*(T *)arg1 &lt; *(T *)arg2)&lt;br /&gt;            return(-1);&lt;br /&gt;        if (*(T *)arg1 &gt; *(T *)arg2)&lt;br /&gt;            return(1);&lt;br /&gt;        return(0);&lt;br /&gt;    }&lt;br /&gt;    static  int CmpDesc(const void *arg1, const void *arg2) {&lt;br /&gt;        if (*(T *)arg1 &gt; *(T *)arg2)&lt;br /&gt;            return(-1);&lt;br /&gt;        if (*(T *)arg1 &lt; *(T *)arg2)&lt;br /&gt;            return(1);&lt;br /&gt;        return(0);&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116228564943482804?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116228564943482804/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116228564943482804' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228564943482804'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228564943482804'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/10/qsort-based-template-class-for-sorting.html' title='qsort-based template class for sorting arrays'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116228560348780845</id><published>2006-10-15T01:05:00.000-07:00</published><updated>2006-10-31T01:09:08.866-08:00</updated><title type='text'>SetTimer granularity problem, and multimedia alternative</title><content type='html'>SetTimer's granularity is 10 ms in w2k, and 15.625 ms in XP. As the following data shows, w2k can achieve exactly 25 Hz, but in XP the best fit is 21.33 Hz. Neither OS can achieve 30 Hz, and worse yet, they fail differently: a period of 33 ms gets you 25 Hz in w2k, and 21.33 Hz in XP.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;available fequencies (w2k):&lt;br /&gt;period  1..10   11..20  21..30  31..40  41..50  51..60&lt;br /&gt;freq    100     50      33.33   25      20      16.67&lt;br /&gt;&lt;br /&gt;available fequencies (XP):&lt;br /&gt;period  1..15   16..31  32..46  47..62  63..78  79..93&lt;br /&gt;freq    64      32      21.33   16      12.8    10.67&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Note: in XP, weird behavior occurs near the above boundaries, e.g. at period = 31, freq oscillates between 31.03 and 30.52.&lt;br /&gt;&lt;br /&gt;Multimedia timers appear to have 1 ms granularity, but are significantly more expensive in terms of CPU load. Note that that the callback runs in a system thread and must not post timer messages while OnTimer is running; otherwise if OnTimer consumes more than one timer period's worth of CPU time, the GUI will be non-responsive.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;volatile BOOL   m_InTimer;  // true if we're in OnTimer&lt;br /&gt;static void CALLBACK MMTimeProc(UINT uID, UINT uMsg, DWORD dwUser,  DWORD dw1, DWORD dw2)&lt;br /&gt;{&lt;br /&gt;    if (!m_InTimer)&lt;br /&gt;        PostMessage((HWND)dwUser, WM_TIMER, 0, 0);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116228560348780845?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116228560348780845/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116228560348780845' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228560348780845'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228560348780845'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/10/settimer-granularity-problem-and.html' title='SetTimer granularity problem, and multimedia alternative'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116228549943757064</id><published>2006-10-14T01:03:00.000-07:00</published><updated>2006-10-31T01:09:22.036-08:00</updated><title type='text'>Matching big hex at HD high-res</title><content type='html'>At 1920 x 1440, Zoom FF param should be (log(0.997395 * 3) + 1) / 2 = .737994&lt;br /&gt;Must also compensate line width! Should be 3 * 6 = 18&lt;br /&gt;Perfect match with WhorldFF, Kaleidascope and Tile. Problem lies further down the signal chain.&lt;br /&gt;Timeblur is also a perfect match, Solarize is also fine, the problem is with Glow.&lt;br /&gt;Hypothesis: if resolution is doubled, inner and outer radius must both be doubled also.&lt;br /&gt;Result: It works fine up to 1280 x 960. At 1600 x 1200 and above, Glow exhibits unexpected behavior.&lt;br /&gt;Bummer. Looks like we're limited to 1280 x 960.&lt;br /&gt;&lt;br /&gt;NOTE that you can't change the desired frame rate in the options dialog without also compensating master speed, otherwise all the automations will be off, e.g. if you double the frame rate you must also double master speed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116228549943757064?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116228549943757064/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116228549943757064' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228549943757064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228549943757064'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/10/matching-big-hex-at-hd-high-res.html' title='Matching big hex at HD high-res'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116228541899725369</id><published>2006-10-13T01:03:00.000-07:00</published><updated>2006-10-31T01:09:46.936-08:00</updated><title type='text'>Resolume plugins that aren’t compatible with FFRend</title><content type='html'>Invalid bit depth (24-bit only):&lt;br /&gt;iua_RectField.dll&lt;br /&gt;resAsciiArt.dll&lt;br /&gt;resCaptureScreen.dll&lt;br /&gt;resChristmasBalls.dll&lt;br /&gt;resLumaImage.dll&lt;br /&gt;resPuzzle.dll&lt;br /&gt;resResolumeBlocks.dll&lt;br /&gt;resTracker.dll&lt;br /&gt;resZxSpectrum.dll&lt;br /&gt;&lt;br /&gt;Crashes:&lt;br /&gt;resDelay.dll&lt;br /&gt;&lt;br /&gt;Doesn’t work?&lt;br /&gt;resFeedback.dll&lt;br /&gt;resDelayBlend.dll&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116228541899725369?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116228541899725369/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116228541899725369' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228541899725369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228541899725369'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/10/resolume-plugins-that-arent-compatible.html' title='Resolume plugins that aren’t compatible with FFRend'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116228538603270947</id><published>2006-10-13T01:02:00.000-07:00</published><updated>2006-10-31T01:24:04.720-08:00</updated><title type='text'>Making big images</title><content type='html'>Recording at 1920 x 1080 (HD) works fine. On the hot rod, I get almost 2 FPS uncompressed and around 1 FPS using XVID. That seems pretty damn slow, but it's about 3000 times faster than Electric Sheep. The question is whether 1080 is good enough for generating poster-sized images, e.g. 11 x 17 at 300 DPI. HD 1080 is only 6.4 x 3.6 at 300 DPI. I tried 5100 x 3300 and it didn't seem to work even on the hot rod. There was memory to spare, so I'm guessing that the exponential increase in compute time would mean render times on the order of an hour per frame, like Electric Sheep's. It would be interesting to see whether it eventually coughs up some frames.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116228538603270947?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116228538603270947/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116228538603270947' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228538603270947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228538603270947'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/10/making-big-images.html' title='Making big images'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116228536467001128</id><published>2006-10-10T01:02:00.000-07:00</published><updated>2006-10-31T01:24:19.416-08:00</updated><title type='text'>Matching the original big hex recording</title><content type='html'>Hue parameter must be .50000001 which fools "don't set parm needlessly" test, so that hue gets set.&lt;br /&gt;&lt;br /&gt;Since origin motion is random, WhorldFF does an initial jump even though the tempo is zero. It takes a while to settle down because of damping. The final location is:&lt;br /&gt;&lt;br /&gt;x = .001251258888516&lt;br /&gt;y = .563585314493240&lt;br /&gt;&lt;br /&gt;After the initial jump it appears to stay put, but NO, it jumps again at around frame 5000. Why? Looks like a divide by zero problem somewhere, maybe CRealTimer::SetFreq isn't handling zero correctly.&lt;br /&gt;&lt;br /&gt;It's hopeless, because the illustrated curves patch uses a random oscillator for poly sides. The random jumps are being triggered asynchronously by CRealTimer's thread, which causes both the origin sequence and the poly sides sequence to be unpredictable.&lt;br /&gt;&lt;br /&gt;So the original can't be matched. Sorry! One option is to just live with big hex being different every time it'srecorded. That's either a cool feature or a pain in the ass, depending on your point view. Another option is to disable random jumps in the illustrated curves patch. That should make big hex deterministic, though this needs to be proved. (Yes, it's deterministic, provided you remember to restart the app before each recording).&lt;br /&gt;&lt;br /&gt;Disabling random jumps also fixes the occasional inconsistencies in big hex's origin motion. Since whorld and the kaleidescope effect both have origin motion, they're adding or subtracting, and sometimes canceling each other out, which causes the origin to lurch, hesitate, or reverse. But is this good or bad behavior? Again it's subjective: it could be interesting, or annoying. I generally like the smooth origin motion better.&lt;br /&gt;&lt;br /&gt;Experiment: big hex 66% with Al Fasawz. The animation moves too fast and spoils the mood of the music. Try a master pitch of 27%. That's the maximum speed reduction possible without losing some time blur (the original had time blur = .27, and .27 / .27 = 1.0, which is the maximum Freeframe parameter). Slow enough?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116228536467001128?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116228536467001128/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116228536467001128' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228536467001128'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228536467001128'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/10/matching-original-big-hex-recording.html' title='Matching the original big hex recording'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116228533755111408</id><published>2006-09-25T01:01:00.000-07:00</published><updated>2006-10-31T01:24:33.120-08:00</updated><title type='text'>Artifact along right edge</title><content type='html'>It's a narrow vertical strip at the far right edge, spanning the entire height of the image, that's shifted vertically by a few a pixels. It appears to come from Pete's glow effect and possibly from other effects as well. Check this and notify him. To remove it from frame captures, crop to 560 x 480 via PS Canvas Size.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116228533755111408?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116228533755111408/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116228533755111408' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228533755111408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228533755111408'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/09/artifact-along-right-edge.html' title='Artifact along right edge'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116228531590684506</id><published>2006-09-19T01:01:00.000-07:00</published><updated>2006-10-31T01:24:47.370-08:00</updated><title type='text'>Move bug</title><content type='html'>After repeated drag moves, plugins weren't matching their titles and parameter rows. Inserting source first was a bad idea. The correct method is: copy source to a temp, delete source, insert destination, copy temp to destination. This also gets rid of the bump source/dest kludge.&lt;br /&gt;&lt;br /&gt;Useful debug code that helped solve it:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;void CFFPluginArray::Dump()&lt;br /&gt;{&lt;br /&gt;    printf("\n");&lt;br /&gt;    printf("Count = %d, LastLoadedIdx = %d\n", m_Count, m_LastLoadedIdx);&lt;br /&gt;    for (int i = 0; i &lt; m_Count; i++) {&lt;br /&gt;        CString s;&lt;br /&gt;        if (m_Plugin[i].IsLoaded()) {&lt;br /&gt;            CFFPlugin   *pp = &amp;m_Plugin[i].m_Plugin;&lt;br /&gt;            pp-&gt;GetPluginName(s);&lt;br /&gt;            printf("%d: '%s' %s\n", i, s, m_Plugin[i].IsBypassed() ? "[BYPASS]" : "");&lt;br /&gt;            for (int j = 0; j &lt; pp-&gt;GetNumParams(); j++) {&lt;br /&gt;                pp-&gt;GetParamName(j, s);&lt;br /&gt;                if (m_Plugin[i].IsCreated()) {&lt;br /&gt;                    printf("\t'%s' = %g\n", s, m_Plugin[i].m_Instance.GetParam(j));&lt;br /&gt;                } else&lt;br /&gt;                    printf("\t'%s'\n", s);&lt;br /&gt;            }&lt;br /&gt;        } else&lt;br /&gt;            printf("%d: (empty)\n", i);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116228531590684506?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116228531590684506/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116228531590684506' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228531590684506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228531590684506'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/09/move-bug.html' title='Move bug'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116228527737814624</id><published>2006-08-13T01:00:00.000-07:00</published><updated>2006-10-31T01:25:01.466-08:00</updated><title type='text'>master pitch problems</title><content type='html'>Whorld's Master Speed parameter must be compensated for master pitch changes. This is non-trivial because it's a logarithmic value mapped to a linear normalized parameter. The formula to determine the correct Master Speed parameter for a given pitch is:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ff_speed = ((log(whorld_speed) / log(20)) + 1) / 2&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;where the nominal pitch is 1.0 (100%), half-speed is 0.5 (50%), double-speed is 2.0 (200%), etc.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Some examples:&lt;br /&gt;whorld  FF&lt;br /&gt;1.0     .5&lt;br /&gt;0.5     .384311&lt;br /&gt;2.0     .615689&lt;br /&gt;.6666   .432326211&lt;br /&gt;.27     .281466900&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Time Blur must also be compensated. The solution turns out to be trivial: just divide the Time Blur by the pitch, i.e. if Time Blur is .27, and pitch is .5, Time Blur should be .54. The idea is that if you're creating half-speed data, you want to blur twice as many frames to achieve the same effect.&lt;br /&gt;&lt;br /&gt;Other Whorld parameters:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ff_zoom = (log(whorld_zoom) + 1) / 2&lt;br /&gt;ff_hue = (whorld_hue / 360)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116228527737814624?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116228527737814624/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116228527737814624' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228527737814624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228527737814624'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/08/master-pitch-problems.html' title='master pitch problems'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-36882700.post-116228520968007070</id><published>2006-08-13T00:59:00.000-07:00</published><updated>2006-10-31T01:25:14.373-08:00</updated><title type='text'>CNumEdit bug</title><content type='html'>A CNumEdit bug was discovered While attempting to compensate Time Blur's parameter for master pitch: CNumEdit notifies the parent before the aux window (aux is a CEditSlider in this case). The parent (a row dialog) sends a notification via SendMessage instead of PostMessage, and since the recipient (main frame) reads the value from the slider, the value is stale, because the slider hasn't been updated yet. The symptom: if a parameter is edited by typing text in the edit control and pressing tab, the slider moves to correct position, but the plugin doesn't respond to the change. The solution: CNumEdit should notify the aux window first, then the parent.&lt;br /&gt;&lt;br /&gt;This is also a problem in Whorld, but it's masked because CMasterDlg::OnNotify uses PostMessage. Using SendMessage causes the same bug to appear. With the corrected CNumEdit, CMasterDlg::OnNotify can use SendMessage without problems. This is preferrable since SendMessage is theoretically more efficient.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36882700-116228520968007070?l=ffrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ffrend.blogspot.com/feeds/116228520968007070/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=36882700&amp;postID=116228520968007070' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228520968007070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/36882700/posts/default/116228520968007070'/><link rel='alternate' type='text/html' href='http://ffrend.blogspot.com/2006/08/cnumedit-bug.html' title='CNumEdit bug'/><author><name>Chris Korda</name><uri>http://www.blogger.com/profile/01929043998111578392</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://1.bp.blogspot.com/_M1A03HK39aM/S1QN04LDYpI/AAAAAAAAAAM/D-jzPBLUQzo/S220/ck-head-shot-psych2b.jpg'/></author><thr:total>0</thr:total></entry></feed>
