Click here to Skip to main content
15,881,172 members

Leslie Sanford - Professional Profile



Summary

    Blog RSS
105,744
Author
2,562
Authority
3,913
Debator
121
Enquirer
252
Organiser
2,232
Participant
0
Editor
Aside from dabbling in BASIC on his old Atari 1040ST years ago, Leslie's programming experience didn't really begin until he discovered the Internet in the late 90s. There he found a treasure trove of information about two of his favorite interests: MIDI and sound synthesis.

After spending a good deal of time calculating formulas he found on the Internet for creating new sounds by hand, he decided that an easier way would be to program the computer to do the work for him. This led him to learn C. He discovered that beyond using programming as a tool for synthesizing sound, he loved programming in and of itself.

Eventually he taught himself C++ and C#, and along the way he immersed himself in the ideas of object oriented programming. Like many of us, he gotten bitten by the design patterns bug and a copy of GOF is never far from his hands.

Now his primary interest is in creating a complete MIDI toolkit using the C# language. He hopes to create something that will become an indispensable tool for those wanting to write MIDI applications for the .NET framework.

Besides programming, his other interests are photography and playing his Les Paul guitars.

Reputation

Weekly Data. Recent events may not appear immediately. For information on Reputation please see the FAQ.

Privileges

Members need to achieve at least one of the given member levels in the given reputation categories in order to perform a given action. For example, to store personal files in your account area you will need to achieve Platinum level in either the Author or Authority category. The "If Owner" column means that owners of an item automatically have the privilege. The member types column lists member types who gain the privilege regardless of their reputation level.

ActionAuthorAuthorityDebatorEditorEnquirerOrganiserParticipantIf OwnerMember Types
Have no restrictions on voting frequencysilversilversilversilver
Bypass spam checks when posting contentsilversilversilversilversilversilvergoldSubEditor, Mentor, Protector, Editor
Store personal files in your account areaplatinumplatinumSubEditor, Editor
Have live hyperlinks in your profilebronzebronzebronzebronzebronzebronzesilverSubEditor, Protector, Editor
Have the ability to include a biography in your profilebronzebronzebronzebronzebronzebronzesilverSubEditor, Protector, Editor
Edit a Question in Q&AsilversilversilversilverYesSubEditor, Protector, Editor
Edit an Answer in Q&AsilversilversilversilverYesSubEditor, Protector, Editor
Delete a Question in Q&AYesSubEditor, Protector, Editor
Delete an Answer in Q&AYesSubEditor, Protector, Editor
Report an ArticlesilversilversilversilverSubEditor, Mentor, Protector, Editor
Approve/Disapprove a pending ArticlegoldgoldgoldgoldSubEditor, Mentor, Protector, Editor
Edit other members' articlesSubEditor, Protector, Editor
Create an article without requiring moderationplatinumSubEditor, Mentor, Protector, Editor
Approve/Disapprove a pending QuestionProtector
Approve/Disapprove a pending AnswerProtector
Report a forum messagesilversilverbronzeProtector, Editor
Approve/Disapprove a pending Forum MessageProtector
Have the ability to send direct emails to members in the forumsProtector
Create a new tagsilversilversilversilver
Modify a tagsilversilversilversilver

Actions with a green tick can be performed by this member.


 
GeneralApplying Generic Programming to Runtime Polymorphism Pin
Leslie Sanford22-Feb-10 10:28
Leslie Sanford22-Feb-10 10:28 
One thing that's been a stumbling block to me in C++ is the tension between compile time polymorphism (or static polymorphism) and runtime polymorphism (or dynamic polymorphism).

Compile time polymorphism is done via templates; the decision about which type to use is decided when the program is compiled. Runtime polymorphism is done via virtual methods. The decision about which type to use is decided as the program is running.

These two approaches seem to be orthagonal(?) to each other.

I was (re)watching a video[^] on YouTube. It's a presentation by Sean Parent of Adobe. He's "a principal scientist at Adobe Systems and engineering manager of the Adobe Software Technology Lab." The entire video is interesting. He talks about generic programming and also designing software components that are connected together to form a directed acyclic graph.

There's a point in the video that has intrigued me ever since I first saw it. There's a bullet point (which unfortunately Sean doesn't elaborate on) that says: "Extend generic programming to apply to runtime polymorphism."

Ah, this seems to be getting at that tension I mentioned early between compile time and runtime polymorphism.

So I did some googling and found an interesting paper[^] describing a design pattern called External Polymorphism. This seems to provide a structure for merging generic programming with runtime polymorphism.

I won't describe the pattern, but I can describe how I applied it to writing VST plugins. The following assumes a basic knowledge of the VST v2.4 SDK, but hopefully you'll be able to follow along without being familiar with it.

Say you have a bunch of objects that you've created on the heap, e.g. you created them in createEffectInstance and then passed them to other objects that interact with them. The lifetime of these objects is the same as that of the plugin. You'd like a reuseable, generic way to dispose of them. Here's an approach using External Polymorphism:

class DisposableInterface
{
public:
    virtual ~DisposableInterface()
    {
    }
};

template<class T>
class Disposable : public DisposableInterface
{
public:
    Disposable(T *target)
    {
        this->target = target;
    }

    ~Disposable()
    {
        delete target;
    }

private:
    T *target;
};


Ok, in our base Plugin class we have a method for passing any object that will be garbage collected when the Plugin itself is destroyed:

class PluginBase : public AudioEffectX
{
public:
    virtual ~PluginBase()
    {
        std::list<DisposableInterface *>::iterator it;

        for(it = objects.begin(); it != objects.end(); it++)
        {
            delete *it;
        }
    }

    // Stuff...

    template<class T>
    void AddToGarbageCollector(T *object)
    {
        objects.push_back(new Disposable<T>(object));
    }
};


AudioEffect *createEffectInstance(audioMasterCallback audioMaster)
{
    Plugin *plugin = new MyPlugin();

    Lfo *lfo = new Lfo();
    AdsrEnvelope *env = new AdsrEnvelope();
    Oscillator *osc = new Oscillator(lfo, env);

    plugin->AddToGarbageCollector(lfo);
    plugin->AddToGarbageCollector(env);
    plugin->AddtoGarbageCollector(osc);

    // Stuff...

    return plugin;
}


Now, you may never need this kind of memory management, so don't get tripped up on the example. The main point is that we can treat "concrete types" polymorphically. We don't have to make sure that they implement a particular base class.

I'm not recommending using this approach to replace virtual methods in all classes, but I prefer to write my low-level classes without them. And I occasionally need to iterate over a collection of these concrete objects for one reason or another, e.g. updating the sample rate or whatever. As long as they meet the requirements of the algorithm that's being applied to them, e.g. provide a method or operators with specific signatures, this technique can be applied to fascilitate this.

Like...

class PluginBase : public AudioEffectX
{
public:

    template<class T>
    void AddTempoTarget(T *object)
    {
        tempoTargets.push_back(new TempoTarget(object));
    }
};


Then when the tempo changes, we could do this:

std::list<TempoTargetInterface *>::iterator it;

for(it = tempoTargets.begin(); it != tempoTargets.end(); it++)
{
    (*it)->Tempo(newTempo);
}


As long as the target objects have a method called Tempo that takes a double (or whatever) they can be notified when the tempo changes, they don't have to inherit from a specific class.

Anyway, this was a puzzle that had been in the back of my mind ever since I became interested in generic programming, and especially after seeing that bullet point in Sean's video. Just something else to add to my bag of tricks.
GeneralGeneric Programming [modified] Pin
Leslie Sanford19-Jul-08 5:53
Leslie Sanford19-Jul-08 5:53 
GeneralOff-topic Pin
Rajesh R Subramanian19-Jun-09 12:48
professionalRajesh R Subramanian19-Jun-09 12:48 
GeneralRe: Off-topic Pin
Leslie Sanford19-Jun-09 19:06
Leslie Sanford19-Jun-09 19:06 
GeneralEnsuring Object State [modified] Pin
Leslie Sanford27-Jun-07 8:00
Leslie Sanford27-Jun-07 8:00 
GeneralEvolution of Messaging Pin
Leslie Sanford19-Oct-06 5:15
Leslie Sanford19-Oct-06 5:15 
GeneralEnumerators as Synthesizer Components Pin
Leslie Sanford20-Sep-06 20:53
Leslie Sanford20-Sep-06 20:53 
GeneralAnonymous Methods as Glue Pin
Leslie Sanford17-Sep-06 14:30
Leslie Sanford17-Sep-06 14:30 
GeneralRefining the approach Pin
Leslie Sanford22-Jan-06 7:52
Leslie Sanford22-Jan-06 7:52 
GeneralFlowing down the Sink Pin
Leslie Sanford21-Jan-06 16:45
Leslie Sanford21-Jan-06 16:45 
GeneralFlow-Based Programming in C# Pin
Leslie Sanford29-Dec-05 13:07
Leslie Sanford29-Dec-05 13:07 
GeneralCombining Visitor, Observer, and Iterator Pin
Leslie Sanford25-Dec-05 21:29
Leslie Sanford25-Dec-05 21:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.