Developer's Corner


In this Developer's Corner, we reveal the internal structures of the MIDI player program elements and how they were implemented. If you have not read the Introduction section of this manual, please do so now and come back here after you know what this program does from a user's point of view. We will start out by showing an extension to the Program Elements in the previous section.

Program Elements

Generate/developers.gif

 

The diagram depicts a little more in-depth view of the MIDI Player utility program than the one from the user's point of view. The primary difference is that, from a developer's point of view, the MIDI player program contains two separately compiled modules:

The external process program is a data producer, pumping out MIDI channel numbers and data whenever a MIDI event is processed. Through Win32 shared memory, the in-process DLL is a data consumer that reads in the MIDI channel numbers and data and distributes it to the channel components (parts) according to the channel numbers. In fact, it is the class functions associated with the individual channel component (part) that fetches the data when the channel number in the MIDI events matches its own in each sampling cycle.

The Invocation Script is a batch command file under Windows environment. It is, by default, SG_xProc.bat in the bin subdirectory of the SansGUI installation directory. When the user clicks on the Run External button, this script file is called with necessary parameters, including the Model File name and current working directory, passed in. Please consult the Understanding the Invocation Script section in Chapter 5 Developing External Process Simulators of the SansGUI Developer's Guide for customization details.

Inside External Process MIDI Player

The External Process MIDI Player is a console-based program currently written in Visual C++. The project workspace can be found in the samples\MIDIplay\MIDIplay_1_0X subdirectory under the SansGUI installation directory. There are four code sections in this program, described in the following:

Processing Model File

The program processes the command line arguments to obtain the name of the Model File. We use the Tabular Data Blocks format (type 0) in this application. It looks for the following information from the Model File in the readModelFile function in MIDIplay.cpp:

These two pieces of information are located in an object derived from the Collection.MIDI class. We simply find the class label in the Model File and fetch the information from the first object. When you load in the Piano.sgp Project Model and play the music, a Model File named Piano.txt, by default, is created in the same directory. Please examine the contents of the file, using your favorite text editor. Except the two pieces of information, all other contents of the Model File are ignored in this application.

Processing MIDI File

The second code segment is located in the readMidiFile function in MIDIplay.cpp. It opens the MIDI file and reads its contents into a dynamically allocated memory area. Because the working directory is handled within the invocation script, there is no need to find out in which directory the MIDI file is located. We can simply open the file with the name string passed in from SansGUI, whether it contains a full directory path or not.

Setting up Shared Memory

The shared memory contains only two integers in this application, one for the channel number and the other for the channel data. The name of the shared memory is indicated in the Model File and is also known to the in-process MIDI Player because it is located in the Collection.MIDI reference object. The code to setup the shared memory is in the createSharedMemory function in MIDIplay.cpp. Two global pointers, g_pChannel and g_pData are initialized to the two integer memory space.

Playing MIDI Stream and Processing Events

The primary MIDI playing mechanism is contained in the CMIDI class library, created by Jörg König (J.Koenig@adg.de). We have made some modifications to his original MIDI.h and MIDI.cpp source files so that the class library can be used with any type of applications, rather than being Microsoft Foundation Class (MFC) specific.

In order to handle the MIDI events, we created a CMidiExt extension class from the CMIDI class and overrode its OnMidiOutClose and OnMidiOutDone functions:

When the user press Ctrl+C, the program detects it and stops. The code is located in a while loop in the main program.

Inside In-Process MIDI Player

To understand the structure of the in-process MIDI Player, let's examine its Schema Definition file. You need to have a proper license key to activate the SansGUI Development Environment in order to load the MIDIplay.sgs Schema Definition file. To find out if the development environment is activated on your computer, simply run SansGUI and select File>New. You will see the New dialog being displayed as following:

generate/devnew.jpg

As it comes out, the Project Model (.sgp) is selected. If you don't have the development environment, the Schema Definition (.sgs) is disabled, and you cannot create or load any Schema Definition file. If you would like to try out the SansGUI Development Environment, you can register your computer to obtain a 30-day evaluation license for the full-feature SansGUI Professional Edition. To register, select Help>About SansGUI... and then click on the Register... button in the About SansGUI dialog while your computer is on-line with Internet access. Please click on the Cancel button above to close the New dialog for now.

Once you are sure that you have the SansGUI Development Environment, you can load the MIDIplay.sgs file from the samples\MIDIplay subdirectory of your SansGUI installation directory.

Simulation Control Classes

From the first Simulator tab in the Left Pane, you can see there are MIDIplay classes created under Cycle and XProc simulation control classes. These classes indicate that we will have both in-process (Cycle) and external process (XProc) programs implemented. There is no additional attribute introduced in these two classes; all are inherited from the parent intrinsic classes.

Unit Objects

Also from the Simulator tab, you can see a Time unit object and four other unit objects with the names Strip-n. We created these four units because SansGUI merges data curves into the same plot when their measuring unit is the same. With different unit objects, the user can control which data channels are to be plotted together and which are separate. We created four units for up to four plotting strips. You can create more if your project requires more strips.

Component Classes

The component classes in MIDI Player for SansGUI are quite simple and all are derived from the Base component class. There are three attributes needed:

We could have created only one Base.Channel class that contains all three attributes above and that's it. Instead, we created a Base.Channel class that includes the first two attributes and derived four subclasses, S-1 through S-4, from it. With the four S-n subclasses, we have the last attribute, MIDI Data (iData), defined with different unit objects, Strip-1 through Strip-4, respectively, in order to allow multiple strip charts.

Reference Class

The last class we created for this utility program is the Collection.MIDI class under the Reference tab in the Left Pane. This class defines the MIDI file, sampling interval and the shared memory data for inter-process communication (IPC). The reason why we cannot define all these attributes in a simulation control class is because they are shared by both the in-process and external process programs. Please see class MIDI in the reference section for more details.

Class Behavior

When the in-process program module is invoked via the Run In-Process button in the Run toolbar, it detects if the shared memory for IPC has been established. If not, it simply displays a message and quits.

During each sampling cycle, the Pre-Evaluation function in the MIDI message reference object is called to fetch the MIDI event data from the shared memory. After that, the Evaluation function in each of the MIDI channel parts is called to update the MIDI data when the channel number in the part matches that of the current MIDI event.

The in-process program implements data pulling from the shared memory with a user settable delay in the MIDI message reference object. It simply calls the Sleep system function during the Post-Evaluation cycle. This is not an implementation of a genuine real-time system.

Please consult the class references in the next few pages and the source files that are in the distribution for all the implementation details.

 



Welcome to MIDI Player for SansGUI Introduction MIDI

MIDI Player for SansGUI Version 1.0

Copyright © 2002-2003 ProtoDesign, Inc. All rights reserved.

http://protodesign-inc.com