Copyright © 2013-2014 MultiMedia Soft

How to synchronize the container application with the control

Previous pageReturn to chapter overviewNext page

In order to allow managing feedback coming from the component's code to the container application code, Active MIDI DJ Console for .NET gives the possibility to setup a certain number of callback delegates that inform about events occurring between the component and external MIDI devices; the list of supported events is available on the table below:

 

Situations

Corresponding callback delegate

Method for initializing the delegate

 

 

 

The configuration of MIDI devices is changed

CallbackMidiDevicesConfigChanged

CallbackMidiDevicesConfigChangedSet

A MIDI device, previously opened through the MidiDevices.Open method, is disconnected from the system after a manual removal

CallbackMidiDevicesOpenRemoved

CallbackMidiDevicesOpenRemovedSet

A short MIDI event is received from a MIDI input device

CallbackMidiDevicesEventShortReceived

CallbackMidiDevicesEventShortReceivedSet

A raw MIDI event is received from a MIDI input device

CallbackMidiDevicesEventRawReceived

CallbackMidiDevicesEventRawReceivedSet

A physical button mapped into the DJ Console profile has been pressed

CallbackMidiDjConsoleEventButtonPressed

CallbackMidiDjConsoleEventButtonPressedSet

A physical button mapped into the DJ Console profile has been released.

CallbackMidiDjConsoleEventButtonReleased

CallbackMidiDjConsoleEventButtonReleasedSet

A physical range control (sliders, jog wheels, rotary knobs, etc.) mapped into the DJ Console profile has been moved

CallbackMidiDjConsoleEventRangeMoved

CallbackMidiDjConsoleEventRangeMovedSet

A manual action (for example the pressing of a button, the movement of a slider or of a jog wheel) is performed on a console's physical control which has not been mapped into the DJ Console profile loaded inside the instance of the component or when the reception of events specific for mapped controls has been disabled through a call to the MidiDjConsole.EnableMappedEvents method.

CallbackMidiDjConsoleEventUnmapped

CallbackMidiDjConsoleEventUnmappedSet

One of the keys on the virtual piano keyboard, previously created through the MidiVirtualKeyboard.Create method, is pressed or released

CallbackMidiKeyboardNotification

CallbackMidiKeyboardNotificationSet

 

Events monitoring is performed inside secondary working threads of the component so, when a delegate is needed to update user interface elements of your application, for example changing the status of a checkbox or filling a combo box, the multi-threading situation must be considered: the relationship between threads and delegates is secondary threads cannot just call methods like the application's primary thread, so a function pointer is needed and delegates act as function pointers.

 

Let's see a couple of code snippets that clarify how a callback delegate can be instantiated and managed.

 

 

Visual Basic .NET

 

// import the component's namespace

Imports ActiveDjConsoleNetApi

 

Namespace ProfileEditor

 Public Partial Class FormMain

         Inherits Form

         Public Sub New()

                 InitializeComponent()

         End Sub

 

         ' instance the component

         Dim m_djConsole As ActiveDjConsoleNetApi.ActiveDjConsoleNetApi = New ActiveDjConsoleNetApi.ActiveDjConsoleNetApi()

 

         ' predispose the delegate and the callback

         Private Delegate Sub ConfigChangedCallbackDelegate(ByVal nChangeType As enumMidiDevicesConfigChanges, ByVal nUserData As Int32)

         Private addrCallbackMidiDevicesConfigChanged As CallbackMidiDevicesConfigChanged

 

         ' the subroutine that manages the callback

         Private Sub MidiDevicesConfigChangedCallback(ByVal nChangeType As enumMidiDevicesConfigChanges, ByVal nUserData As Int32)

                 ' check if we are being invoked from a secondary thread

                 If Me.InvokeRequired Then

                         ' this callback is being called from a secondary thread so, in order to access eventual controls on the form, we must

                         ' call Invoke using this same function as a delegate

                         Me.Invoke(New ConfigChangedCallbackDelegate(AddressOf MidiDevicesConfigChangedCallback), nChangeType, nUserData)

                         Return

                 End If

 

                 ' display a debug message about the occurred event

                 System.Diagnostics.Debug.WriteLine("MidiDevicesConfigChanged: " & nChangeType.ToString())

 

                 ' we can now safely access controls on the user interface

                 ...

 

         End Sub

 

         Private Sub PredisposeCallbacks()

                 ' predispose the callback that will notify about a change within the configuration of MIDI devices

                 addrCallbackMidiDevicesConfigChanged = New CallbackMidiDevicesConfigChanged(AddressOf MidiDevicesConfigChangedCallback)

                 m_djConsole.CallbackMidiDevicesConfigChangedSet(addrCallbackMidiDevicesConfigChanged, 0)

         End Sub

 

         Private Sub FormMain_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load

 

                 ' initialize the component

                 m_djConsole.Init()

 

                 ' predispose the callbacks

                 PredisposeCallbacks()

 

         End Sub

 End Class

End Namespace

 

 

Visual C#

 

// add the component's namespace

using ActiveDjConsoleNetApi;

 

namespace ProfileEditor

{

 public partial class FormMain : Form

 {

         public FormMain()

         {

                 InitializeComponent();

         }

 

         // instance the component

         ActiveDjConsoleNetApi.ActiveDjConsoleNetApi m_djConsole = new ActiveDjConsoleNetApi.ActiveDjConsoleNetApi();

 

 

         // predispose the delegate and the callback

         delegate void ConfigChangedCallbackDelegate(enumMidiDevicesConfigChanges nChangeType, Int32 nUserData);

         CallbackMidiDevicesConfigChanged addrCallbackMidiDevicesConfigChanged;

 

         // the function that manages the callback

         void MidiDevicesConfigChangedCallback(enumMidiDevicesConfigChanges nChangeType, Int32 nUserData)

         {

                 // check if we are being invoked from a secondary thread

                 if (this.InvokeRequired)

                 {

                         // this callback is being called from a secondary thread so, in order to access controls on the form, we must

                         // call Invoke using this same function as a delegate

                         this.Invoke(new ConfigChangedCallbackDelegate(MidiDevicesConfigChangedCallback), nChangeType, nUserData);

                         return;

                 }

 

                 // display a debug message about the occurred event

                 System.Diagnostics.Debug.WriteLine("MidiDevicesConfigChanged: " + nChangeType.ToString());

 

                 // we can now safely access controls on the user interface

                 ...

         }

 

         private void PredisposeCallbacks()

         {

                 // predispose the callback that will notify about a change within the configuration of MIDI devices

                 addrCallbackMidiDevicesConfigChanged = new CallbackMidiDevicesConfigChanged(MidiDevicesConfigChangedCallback);

                 m_djConsole.CallbackMidiDevicesConfigChangedSet(addrCallbackMidiDevicesConfigChanged, 0);

         }

 

         private void FormMain_Load(object sender, EventArgs e)

         {

                 // initialize the component

                 m_djConsole.Init();

 

                 // predispose the callbacks

                 PredisposeCallbacks()

 

         }

 }

}

 

 

IMPORTANT NOTE ABOUT DELEGATES AND THEIR SCOPE: When an instance of a callback delegate is passed to one of the API functions, the delegate object is not reference counted. This means that the .NET framework would not know that it might still being used by the API so the Garbage Collector might remove the delegate instance if the variable holding the delegate is not declared as global. As a general rule, make sure to always keep your delegate instance in a variable which lives as long as the API needs it by using a global variable or member.