Click here to Skip to main content

Leslie Sanford - Professional Profile

Summary

53,371
Author
2,514
Authority
3,866
Debator
118
Enquirer
231
Organiser
1,864
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.
Member since Monday, August 5, 2002 (10 years, 9 months)

Contributions

Articles 18 (Legend)
Tech Blogs 0
Messages 1,531 (Master)
Q&A Questions 0
Q&A Answers 0
Tips/Tricks 0
Comments 0

Links

Reputation

For more 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, and the given member types also gain the privilege regardless of their reputation level.

ActionAuthorAuthorityDebatorEditorEnquirerOrganiserParticipantIf OwnerMember Types
Have no restrictions on voting frequencysilversilversilversilverAdmin
Store personal files in your account areaplatinumplatinumSitebuilder, Subeditor, Supporter, Editor, Staff
Have live hyperlinks in your biographybronzebronzebronzebronzebronzebronzesilverSubeditor, Protector, Editor, Staff, Admin
Edit a Question in Q&AsilversilversilversilverYesSubeditor, Protector, Editor, Admin
Edit an Answer in Q&AsilversilversilversilverYesSubeditor, Protector, Editor, Admin
Delete a Question in Q&AYesSubeditor, Protector, Editor, Admin
Delete an Answer in Q&AYesSubeditor, Protector, Editor, Admin
Report an Articlesilversilversilversilver
Approve/Disapprove a pending ArticlegoldgoldgoldgoldSubeditor, Mentor, Protector, Editor, Staff, Admin
Edit other members' articlesSubeditor, Protector, Editor, Admin
Create an article without requiring moderationplatinumSubeditor, Mentor, Protector, Editor, Staff, Admin
Report a forum messagesilversilverbronzeProtector, Editor, Admin
Create a new tagsilversilversilversilverAdmin
Modify a tagsilversilversilversilverAdmin

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


 
You must Sign In to use this message board.
Search this forum  
GeneralApplying Generic Programming to Runtime Polymorphism Pin
Monday, February 22, 2010 10:28 AM by Leslie Sanford
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
Saturday, July 19, 2008 5:53 AM by Leslie Sanford
Generic programming has become a bit of an obsession of mine lately. I've been studying this website:
 
Generic Programming[^]
 
And I've been intrigued by applying generic programming techiniques to DSP programming. I've posted about this in the past with a generic example of a delay line as well as a small parameter handling toolkit.
 
A key concept of generic programming is called Lifting[^]. It's where you examine a concrete algorithm and look for ways to make it generic. For example, here is a concrete copy algorithm:
 
void Copy(float *first, float *last, float *out) 
{ 
    while(first != last) 
    { 
        *out = *first; 
 
        first++; 
        out++; 
    }    
} 
 
Fair enough. But what if we wanted a copy algorithm for integers? We'd have to do this:
 
void Copy(int *first, int *last, int *out) 
{ 
    while(first != last) 
    { 
        *out = *first; 
 
        first++; 
        out++; 
    }    
} 
 
In examining the two algorithms we see they are exactly the same except for the type. So we can "lift" the algorithm up by making it type independent:
 
template<typename InputIterator, typename OutputIterator> 
void Copy(InputIterator *first, 
          InputIterator *last, 
          OutputIterator *out) 
{ 
    while(first != last) 
    { 
        *out = *first; 
 
        first++; 
        out++; 
    }    
} 
 
Now we have a Copy function that can work on any type provided that the iterators meet the requirement of the algorithm. This is an important point. It's usually impossible to lift an algorithm to the point that it is so generic it can work on anything. There are usually some requirements. The above algorithm requires that the InputIterator support the postfix increment operator as well as the * operator for reading its value. The OutputIterator must also support the postfix increment operator and the * operator for writing to its value.
 
So how about applying this to DSP? Can we "lift" some of the algorithms used in DSP and VST programming?
 
Take a basic sine oscillator function:
 
float SineOscillator(float *first, 
                     float *last, 
                     float phase, 
                     float increment) 
{ 
    while(first != last) 
    { 
        phase += increment; 
 
        while(phase > PI2) 
        { 
            phase -= PI2; 
        } 
 
        *first = sin(phase); 
 
        first++; 
    } 
 
    return phase; 
} 
 
What can we do to "lift" this algorithm?
 
We can make it type independent for one. That's easy enough. But it would also be cool to make it waveform independent as well. And it would also be nice to pack up the phase and increment values into one object instead of passing them in seperately.
 
So applying the above, we come up with this:
 
template<typename OutputIterator, 
         typename Oscillator, 
         typename Waveform> 
Oscillator Oscillate(OutputIterator first, 
                     OutputIterator last, 
                     Oscillator osc, 
                     Waveform wave) 
{ 
    while(first != last) 
    { 
        osc.phase += osc.increment; 
 
        while(osc.phase >= osc.length) 
        { 
            osc.phase -= osc.length; 
        } 
 
        *first = wave(osc.phase); 
 
        first++; 
    } 
 
    return osc; 
} 
 
The algorithm has several requirements. Oscillator must have a phase, increment, and length values. Waveform must provide a () operator that takes the current phase and returns a result.
 
One challenge with this kind of approach is maintaining state after each function call. If we call the above function like this:
 
Oscillate(&buffer[0], &buffer[BUFFER_SIZE], myOsc, sin); 
 
Both the oscillator and waveform objects are passed in by value. We can update our oscillator object by assigning the return value to it:
 
myOsc = Oscillate(&buffer[0], 
                  &buffer[BUFFER_SIZE], 
                  myOsc, 
                  sin);

 
That's fine but may not be very efficient if the oscillator is very large.
 
Instead we can pass the oscillator object in as a reference so whatever state changes that take place within the function persist afterwards:
 
Oscillate<float *, MyOscillator &, Sine>(&buffer[0], 
                                         &buffer[BUFFER_SIZE], 
                                         myOsc, 
                                         Sine());
 
If we need to persist changes in state to our waveform, we can use the same technique:
 
Oscillate<float *, MyOscillator &, Sine &>(&buffer[0], 
                                           &buffer[BUFFER_SIZE], 
                                           myOsc, 
                                           mySine);
 
This just scratches the surface. But the idea is to abstract algorithms to make them generic so that they can be reused in many different contexts.
 
modified on Sunday, July 20, 2008 9:14 PM

GeneralOff-topic PinmvpRajesh R Subramanian19 Jun '09 - 12:48 
GeneralRe: Off-topic PinmemberLeslie Sanford19 Jun '09 - 19:06 
 
GeneralEnsuring Object State [modified] Pin
Wednesday, June 27, 2007 8:00 AM by Leslie Sanford
Many times a method needs to perform a series of steps. The problem is that one of these steps can fail. Usually, this results in an exception being thrown from the source of the failure. When this happens, it's important that the object whose method is being invoked is left in a valid state.
 
Here is an example of the problem:
 
public class MyClass
{
    private SomeObject obj;
 
    private int a;
 
    private int b;
 
    public MyClass(SomeObject obj)
    {
        #region Require
 
        if(obj == null)
        {
            throw new ArgumentNullException("obj");
        }
  
        #endregion
 
        this.obj = obj;
        this.a = obj.CalculateSomething();
        this.b = obj.CalculateSomethingElse();
    }
 
    public void DoSomething()
    {
        a = obj.CalculateSomething();
 
        b = obj.CalculateSomethingElse();
    }
}
 
Now in the above example, suppose that the call in DoSomething to the CalculateSomething method succeeds but that the call following it to CalculateSomethingElse fails and an exception is thrown. Also suppose that a and b should always be updated together. If one is updated successfully and the other is not, the object is no longer in a valid state. It's not hard to think of "real" examples of this type of situation, e.g. updating values in an object by loading data from a file (suppose a read operation fails?), but here we'll just have to assume this is the case.
 
A way to circumvent this is to cache the results from each step temporarily and update the object at the end of the method. At this point, all of the steps have been completed successfully and we can update our object while ensuring that its invariants are maintained.
 
public class MyClass
{
    private SomeObject obj;
 
    private int a;
 
    private int b;
 
    public MyClass(SomeObject obj)
    {
        #region Require
 
        if(obj == null)
        {
            throw new ArgumentNullException("obj");
        }
  
        #endregion
 
        this.obj = obj;
        this.a = obj.CalculateSomething();
        this.b = obj.CalculateSomethingElse();
    }
 
    public void DoSomething()
    {
        int tempA = obj.CalculateSomething();
 
        int tempB = obj.CalculateSomethingElse();
 
        // Now we can update the object's fields.
        a = tempA;
        b = tempB;
    }
}
 
In the second example, the calls to CalculateSomething or CalcualteSomethingElse can fail without our object being left in an invalid state.
 
When it's necessary to perform many steps in a method, caching the results can get complicated. My current approach is view this as an opportunity to refactor. What I do is take the values that need updating and put them into a seperate class. The previous example then looks like this:
 
public class RefactoredValues
{
    private int a;
 
    private int b;
 
    public RefactoredValues(SomeObject obj)
    {
        #region Require
 
        if(obj == null)
        {
            throw new ArgumentNullException("obj");
        }
  
        #endregion
 
        this.a = obj.CalculateSomething();
        this.b = obj.CalculateSomethingElse();
    }
 
    public int A
    {
        get
        {
            return a;
        }
    }
 
    public int B
    {
        get
        {
            return b;
        }
    }
}
 
public class MyClass
{
    SomeObject obj;
 
    RefactoredValues v;
  
    public MyClass(SomeObject obj)
    {
        #region Require
 
        if(obj == null)
        {
            throw new ArgumentNullException("obj");
        }
  
        #endregion
 
        this.obj = obj;
 
        v = new RefactoredValues(obj);
    }
 
    public void DoSomething()
    {
        v = new RefactoredValues(obj);
    }
}
 
Any time DoSomething is called, it creates a new object representing the updated values. If an exception is thrown, the MyClass's values are left intact.
 

 
-- modified at 14:09 Wednesday 27th June, 2007
 
GeneralEvolution of Messaging Pin
Thursday, October 19, 2006 5:15 AM by Leslie Sanford
This is a post[^] I made to the Lounge. I wanted to give a basic overview of the concept of messaging in object oriented programming. Specifically, I wanted to show how anonymous methods help facilitate passing one message from one object to another in a decoupled way. This is similar to my "Anonymous Methods as Glue"[^] entry.
 
The post got a little long; I really enjoy talking about these concepts. So I thought I would repost it here:

 
From a theoretical point of view, invoking a method on an object can be considered sending it a message:
 
SomeObject obj = new SomeObject();
 
// Sending object message to do something.
obj.DoSomething();
The challenge becomes implementing this in such a way as to make it extensible and flexible to change. Polymorphism helps by lowering the coupling between objects:
 
public interface ISomeInterface
{    
    void DoSomething();
}
ISomeInterface obj = new SomeObject();
 
// Sending object message to do something.
obj.DoSomething();
Now we can substitute types that implement ISomeInterface and it won't break the rest of our code. Just basic polymorphism.
 
It would be nice to have objects communicate peer-to-peer through a more explicit messaging system:
 
public interface ISink
{    
    void Send(Message msg);
}
Then we can set up relationships between objects when they are created and allow them to send messages directly to each other via the ISink interface:
 
// SomeObject implements the ISink interface.
ISink obj1 = new SomeObject();
 
AnotherObject obj2 = new AnotherObject(obj1);
 
obj2.Go();
obj2 can send messages directly to obj1 and does so through the ISink interface.
 
The problem with this approach is that we have to straightjacket objects into the ISink interface in order to allow our messaging system to work. We can use .NET events to decouple objects even further and use anonymous methods as a means of facilitating communication. Take your typical .NET class that raises an event:
 
public class ClassWithEvents
{    
    public event EventHandler SomethingHappened;    
    // ...
}
Take a class with a method that returns void and takes no parameters:
 
public class SomeObject
{    
    public void DoSomething()    
    {        
        // ...    
    }
}
Anonymous methods glue the objects together allowing them to communicate:
 
ClassWithEvents obj1 = new ClassWithEvents();
 
SomeObject obj2 = new SomeObject();
 
ob1.SomethingHappened += delegate(object sender, EventArgs e)
{    
    ob2.DoSomething();
};
The objects are completely decoupled. The anonymous method provides a way for events raised by one object to be delegated to another object. Things can get fancier if our anonymous method adapts the event raised by one object by transforming the message into something the receiving object can understand.
 
From my point of view, since taking up C#, messaging has become a ubiquitous to my programming. And I think it's improved as a result.

 
GeneralEnumerators as Synthesizer Components Pin
Wednesday, September 20, 2006 8:53 PM by Leslie Sanford
Consider an oscillator in your standard analog synthesizer. It cycles through its waveform endlessly. Let's say you want to model this using C#. Why not use the IEnumerator interface? The MoveNext method moves the oscillator to the next sample of the waveform. The Reset method resets the oscillator to the beginning of the cycle of its waveform. And the Current property represents the current output of the oscillator.
 
In addition to implementing the IEnumerator interface, an Oscillator class could implement methods allowing you to modulate it's amplitude and frequency; it could have ModulateAmplitude and ModulateFrequency methods that take a double value.
 
In the case of ModulateAmplitude, the Oscillator would multiply the specified value to its current amplitude. In the case of ModulateFrequency, the Oscillator would add the specified value to its current index into the waveform buffer. When MoveNext is called, it calculates its current value based on the modulated amplitude value and modulated frequency value.
 
Since this is an oscillator, MoveNext would never return false. However, we could model other synth components using the IEnumerator interface, such as an ADSR envelope. It this case, MoveNext would eventually return false when the envelope has reached the end of its release segment.
 
I've written code to implement the above descriptions, and I've liked the results. Hopefully, I'll post an article with an accompanying demo project sometime before the end of the year.
 
GeneralAnonymous Methods as Glue Pin
Sunday, September 17, 2006 2:30 PM by Leslie Sanford
I've posted a lot here about flow-based programming. I've studied this from a lot of different viewpoints: Messages can flow between object synchronously or asynchronously. Messages can be pushed from one object to another or pulled to one object from another.
 
For my MIDI toolkit, I settled on a synchronous push architecture using a Source/Sink metaphor. Delegates representing a method in the Sink are connected to a Source. When the Source creates a message, it pushes the message to all Sinks connected to it.
 
This is fine, but the implementation of this approach has felt to me to be non-standard. If you were looking at my libraries for the first time, it might not be obvious what's going on. So I've been thinking of going back to designing my classes in a more traditional .NET framework style.
 
What this means is that the Source infrastructure is done away with. In its place are .NET style events. So instead of a Source pushing messages to its Sinks, it simply raises an event. Sources look just like any other .NET class that raises an event.
 
But this leaves the problem of how to connect objects together. With the Source infrastructure no longer in place, how can sources and sinks be connected?
 
The answer is anonymous methods. Anonymous methods provide a glue that sticks objects together. Let me give you an example:
 
public delegate void MessageReceivedEventHandler(object sender, MessageReceivedEventArgs e); 
 
public class Device 
{ 
    public event MessageReceivedEventHandler MessageReceived; 
 
    // ... 
} 
 
public class Client 
{ 
    public void Send(Message msg) 
    { 
        // Do stuff... 
    } 
} 
 
public class Application 
{ 
    public static void Main() 
    { 
        Device dev = new Device(); 
        Client c = new Client(); 
 
        // An anonymous method connected to the 
        // MessageReceived event. 
        dev.MessageReceived += delegate(object sender, MessageReceivedEventArgs e) 
        { 
            // Delegate the message to the client class. 
            c.Send(e.Message); 
        }; 
 

        // Other stuff... 
    }
} 
 
The Application class creates instances of Device and Client and creates
an anonymous method that delegate events raised by Device to Client. The
anonymous method acts as glue connecting the two objects together.
 
I think this is a form of the Adapter pattern from GoF, but someone pointed out to me on comp.object that it may be the Mediator pattern instead. Regardless, anonymous methods provide a clean way to connect objects together. The beauty is that the classes are completely decoupled. There's no need to provide any special infrastructure for connecting objects; anonymous methods do it for us.

 
GeneralRefining the approach Pin
Sunday, January 22, 2006 7:52 AM by Leslie Sanford
In my last post I definied an IChannelSink interface. What I have since found useful is to distinquish between sinks and sources. A link in a chain of objects can be a source of messages, a sink for messages, or both. So...
 
public interface IChannelSink
{
    void ProcessMessage(IChannelMessage message);
}
 
And...
 
public interface IChannelSource
{
    IChannelSink ChannelSink
    {
        get;
        set;
    }
}
 
An IChannelSource contains the next sink in the chain. Typically, the first link in a chain of objects only implements the IChannelSource interface. And the last object only implements the IChannelSink interface. The intermediate objects implement both.
 
GeneralFlowing down the Sink Pin
Saturday, January 21, 2006 4:45 PM by Leslie Sanford
Well, I've been all over the place on how to implement flow-based programming in C#. I've discovered several ways of doing it, a couple of which you can read about in my previous blog entry.
 
What I've settled on is an approach inspired by the System.Runtime.Remoting.Channels namespace. This namespace uses the concept of sinks and sink chains. You have a chain of objects that process messages. Well, that's very much like what I'm trying to accomplish with my MIDI toolkit!
 
So I've created a set of sink interfaces, one for each message type. Classes that implement these interfaces can be placed in a chain of objects which process MIDI messages. For example, take the IChannelSink from the MIDI toolkit:
 
public interface IChannelSink
{
    void ProcessMessage(ChannelMessage message);
 
    IChannelSink NextChannelSink
    {
        get;
        set;
    }
}
 
This represents the basic functionality for an object to serve in a sink chain. An example of chaining objects together:
 
InputDevice inDevice = new InputDevice(0);
UserSink userSink = new UserSink();    // Some user defined channel sink.
ChannelStopper stopper = new ChannelStopper();
OutputDevice outDevice = new OutputDevice(0);
 
inDevice.ChannelSink = userSink;
 
userSink.NextChannelSink = stopper;
 
stopper.NextChannelSink = outDevice;
 
// Start processing messages.
inDevice.StartRecording();
 
The chain begins with an InputDevice class. This class doesn't actually implement the IChannelSink interface since it is the first link in the chain. It simply receives messages and does not process them.
 
The second object in the chain is a hypothetical user defined sink. This sink processes messages in a user defined way.
 
The ChannelStopper sink keeps track of any sounding notes. When the flow of messages stop, the stopper's AllSoundsOff method can be called to stop any sounding notes so that they are not left hanging.
 
And finally, the output device serves as the last link in the chain. It simply sends the messages to an output device.
 
So after much consideration, I think I've settled on the way in which I want to implement flow-based programming in C#.
 
BTW, this implementation looks a lot like the Chain of Responsibility design pattern. The main difference is that this approach is about processing messages rather than handling requests, but they are very similar.
 

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


Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 23 May 2013
Copyright © CodeProject, 1999-2013
All Rights Reserved. Terms of Use
Layout: fixed | fluid