I’ve taken some leave from developing HourGlass and been updating/rewriting an old Reaper extension plugin (from around 2009) that does pitch and time processing of media items in Reaper. I was prompted to do this when a 64 bit build of the plugin was requested at the Reaper forum a few weeks ago. I had already done a 64 bit build of the plugin quite a long time ago, but I very quickly noticed the code had all kinds of flaws and worse, serious bugs where invalid memory was accessed, threads were writing and reading the same objects at the same time without locking and so on. For some reason, the 32 bit build of the plugin had worked seemingly OK.
The update or rather rewrite has involved the following and more :
- Removal of numerous global variables. (Still not completely eliminated as only one instance of the plugin can run anyway currently and removing the remaining global variables would be a bit labor intensive.)
- Remove almost all explicit uses of C++ new and delete operators and use smart pointers and std::vectors instead. The old code had a very distasteful hodgepodge of std::vectors and allocating buffers via operator new, usually forgetting to release them with delete. Consistency is sanity, all dynamic buffers are now std::vectors. I wonder why I hadn’t thrown a lonely malloc()/free() pair into the old code, too…
- Object ownerships were introduced. For example, in the old code the automation envelopes were for some reason in a global std::vector. Allocated via pointers for no purpose, of course. In the new code the audio processors themselves create and manage the envelope objects. And the envelopes are managed just as values, not pointers. (ie, in the old code there was std::vector<envelope*> as a global variable, in the new code the DSP processor class has a member std::vector<envelope>.)
- Although deep class hierarchies can be problematic, I introduced a new base class that handles common things for the 2 derived DSP processor classes (for resampled pitch processing and for independent pitch/time/formant processing). The GUI code no longer needs to do insane checks about which class and which object instance should be accessed. The deeper class hierarchy was clearly a better design here. Adding new processor types is around 100x more feasible now than it was in the old code.
- State saving/loading to/from disk was added, handled with JSON. This required writing quite a lot of annoying boilerplate code, but on the other hand clarified what the object states really consist of.
The plugin is in a pretty good state at the moment, I suppose I will keep working on it for a week or two. Then I will hopefully return to working on HourGlass 2. (A public release of HG 2 is still far in the future. An optimistic estimate would be around July 2014.)