Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ProjectMIDI: an extensible set of small MIDI .NET programs

0.00/5 (No votes)
24 Jan 2006 1  
This article describes how multiple .NET assemblies work together to control MIDI devices in a live performance environment.

Image of ProjectMIDI PDF Dialog

Introduction

MIDI provides a common interface that allows interconnecting a vast array of electronic devices. Getting those devices working cooperatively is an entirely different story. This project aims to provide a solution to that specific problem.

This article describes ProjectMIDI, a set of small, cooperative MIDI applications. I'll try to explain how the code works and give a high level description of how it is implemented. To keep the size of this article manageable, I'll refer you to the actual source files instead of copying the code into this article. I apologize that this means that you may need to flip back and forth between this article and the source code.

One of my reasons for writing this article is to solicit your feedback. So please email me with your suggestions.

ProjectMIDI is a non-commercial software project designed to provide extensible control of MIDI devices in a live performance environment. The purpose of this project is to build software which will integrate the latest, readily available technologies into a leading edge MIDI setup for live performance.

Some of this code is still being extended. I have tried to clean it up, but I apologize for any loose ends I may have left laying about in the code.

Image of ProjectMIDI Task Bar icon menu

I'm hoping that other programming hobbyists will be interested in writing their own assemblies to extend the project. That is why I am making it open and extensible, and documenting how the pieces work and interact with each other. I'm working primarily in C#, but I believe that any .NET language could be used. I am also providing a VB .NET sample assembly.

One of my key design points is to provide an architecture and function in the core assemblies that makes it very simple to create additional functional assemblies.

Quick Start

To play with the code, download and unzip the executables file. This file contains a set of directories and sample files. Then launch the ProjectMidi.exe file. It will prompt you for the path to your files. Simply select the same directory.

Background

I am a musician and a programmer. I love doing both. Frankly, I probably enjoy the technology more than just the musical aspects of playing. Ah, give me a control panel with a whole bunch of knobs that make sound...

That said, I've never found any software that really allows me to use much of the capability of my MIDI equipment in a live performance environment. Sure, some things can be done using programs like Cakewalk Sonar or Tascam Gigastudio. But whenever I use one of these programs I am always left wanting to do more. I am very familiar with what MIDI hardware can do, and I want to be able to exploit that capability. I am writing this software to allow really taking advantage of the MIDI hardware that I own.

I also want others to participate if they feel so inclined. I am making the source code openly available. I have also created this website to serve as the meeting place for anyone interested in ProjectMIDI.

What can you do with ProjectMIDI?

A tutorial on using ProjectMIDI is available on the ProjectMIDI website.

I'm using ProjectMIDI each Sunday drumming and playing keyboards for my church band. Here are some of the things that the software currently does for me:

  1. It displays sheet music or lyric sheets during live performance

    I scan my music and use this software to display it during performance. I have a small tablet PC that mounts to my drum kit, and a laptop that sits above my MIDI keyboard. I use MIDI to flip pages and advance songs. I can program the cow bell pad to do this, but usually use the TD8's Inc/Dec buttons or a foot switch.

  2. I organize my songs into "sets"

    This allows me to easily advance from song to song during a gig. The SongSet dialog is shown to the right. The song listing on the right side helps me remember the order of songs in the set. The left side shows all of the sets I've created. I organize these by date.

    Picture of SongSet dialog

  3. Set patches for each song and/or page

    When 'flipping pages' as described above, set the voicing of each of my MIDI instruments for each song and page. I can set different drum sounds to my pads based on song and page.

  4. Annotate my music using the Tablet PC's Stylus

    This is way cool. I simply write on the tablet over the displayed music to make performance notes. The software then saves this and displays it each time I display that page.

    Picture of Connections dialog

  5. Play an associated MP3 file

    Sometimes during practice we need to hear the original recording to get a part down. I can record an MP3 file of the song and associate it with the music. All I need to do is hit a play button while displaying that song. I can also use this to practice with the song.

  6. Quickly assign drum sounds to any drum pad and patches to the keyboard

    Although I tend to use the same drum kits for most songs, I often want to reassign one or two pads for a unique sound. I can use the TD8's controls to do this, but it is complicated and slow, and changes get easily lost. Using this program makes it quick and easy, and my changes will be remembered for the next time I display the song.

ProjectMIDI Modular Approach

What I've realized (and the subject of a lot of programming books) is that since there is "so" much that one can do with MIDI, it becomes extremely important to break the programming up into small manageable pieces.

  • ProjectMIDI Application

    This is the main program. It is responsible for locating and loading all of the other pieces. These other pieces are implemented as .NET assemblies. The technical details of these assemblies, including instructions for creating new assemblies is discussed on the ProjectMIDI website and will be discussed later in these articles.

  • Connections Assembly

    Connections between events and actions between assemblies are established dynamically. The Connections assembly provides the controls for making and remembering these connections.

  • Songset Assembly

    Songset provides the functionality to organize songs into sets. It communicates with other modules using events to keep them in sync. Each module typically operates based on the song and page currently selected.

  • SubMenu Assembly

    This assembly implements multiple level custom menus.

  • PDF Assembly

    The PDF Applet displays sheet music (or anything for that matter) from PDF files. This would typically be the primary user interface used during live performance.

  • TIFF Assembly

    Alternatively, the TIFF Applet can be used to display the sheet music from TIFF files.

  • Ink Assembly

    The Ink Applet allows writing on top of the sheet music displayed by PDF or TIFF using a tablet PC's stylus. This requires Windows XP Tablet PC Edition. This is a really great way to annotate and mark up your music for live performance.

  • MIDI Assembly

    This assembly will connect to all of the MIDI ports present on the system and other assemblies to connect to them.

  • MIDI Device Assemblies

    Support for a specific MIDI device is provided by a "device assembly". The device assembly can implement whatever device specific functionality is desired. Typically it will contain a dialog to allow specific voices (patches) to be associated with specific songs and even pages. Dialogs can be implemented to allow programming new voices if desired. This of course depends on the capabilities of the particular device.

    Input controls present on a MIDI device are named and identified to ProjectMIDI by the device assembly. These can then be connected by the user to appropriate "actions".

ProjectMIDI Connections

ProjectMIDI allows you to control the way that the different input "events" on your system are connected to output "actions".

Each assembly publishes the "events" that it generates and the "actions" that it can respond to. This is done in a manner that does not requires "a priori" knowledge of other modules. ProjectMIDI then provides several mechanisms to connect "events" to "actions".

Events include such things as:

  • MIDI Events: These includes keys, drum pads, knobs, foot pedals, and buttons
  • Windows dialog controls: These include sliders and pushbuttons
  • Custom menus: ProjectMIDI provides the ability to create your own menus

For example, you may wish to use a MIDI keyboard's foot switch to change the displayed music page. Or you may wish to launch a frequently used MIDI device editor from one or more convenient custom menus. This can be done easily by mapping the particular event to the desired action.

ProjectMidi Events

Events are things which are caused by user interaction. This includes MIDI events which result when you operate your MIDI equipment, and events caused by interacting with the software.

ProjectMidi Actions

Actions which things that can be controlled or triggered by events. This includes selecting songs, pages, or patches and launching a MIDI device voice editor.

Connections

You can make "connections" between "events" and "actions". Some connections will have been created by default when you installed the program. Other connections will be specific to your setup and depend on the MIDI equipment that you use.

Image of Connections Dialog

The "Connections Editor" pictured here allows you to change or create new connections.

Sorting Connections

The connections list can be sorted by clicking on the column headings. Clicking on the "ID" column heading will sort the connections by ID number.

Clicking on the "Source" or "Event" column heading will sort the connections by the Source Assembly name and Event.

Likewise, clicking on the "Dest" or "Actions" column heading will sort the connections list by the Destination Assembly and Action.

Adding a Connection

You can add new connections by right-clicking anywhere in the list, and selecting the 1st menu item 'Add New Connection'. A new connection will be created at the end of the list. You will then need to select a source event and destination action for the new connection.

Deleting a Connection

You can delete unused or unwanted connections by selecting the connection, then right-clicking on it and selecting the 'Delete Selected Connection' menu item.

Changing a Connections Source Assembly or Event

You can change the Source Assembly or Event by selecting the connection, then right-clicking on the Source or Event field. The context menu displayed will contain a list of assembly names or event names.

Changing a Connections Destination Assembly or Action

You can change the Destination Assembly or Action by selecting the connection, then right-clicking on the Destination or Action field. The context menu displayed will contain a list of assembly names or event names.

ProjectMIDI Customizable Menus

Picture of menu editor dialog

ProjectMIDI allows you to customize any of its menus. Menus are defined by the "connections" made between a menu event and an action. By default, the name appearing on the menu will be the name of the action.

You can use the menu editor dialog to rearrange the items in a menu, as well as to change the text that appears on the menu.

You can directly edit the text of each menu item.

Right-clicking on a menu item displays a context menu allowing you to add or remove a separator line, or move the menu item up or down.

Song Sets, Songs, Pages, and Patches

ProjectMIDI organizes music into Song Sets, Songs, Pages, and Patches.

Song Sets

Song sets are a collection of songs. You can group songs together any way you like. Typically this would be a set of songs to be played at a particular gig. Alternatively, it can be songs of a particular theme, or by an artist, etc.

Songs

A song is the basic unit of organization. Each of the assemblies in ProjectMIDI typically associate a group of settings with each song. This could be for example a mapping of sounds to keyboard zones or drum pads.

Pages

Songs can be divided up into pages. Each page can have its own sounds and settings associated with it.

Patches

Pages can be further divided up into Patches. This would be done for example if you wanted to have different sounds associated with a verse and a chorus, but both of those appeared on the same sheet music page.

Saving Your Sets

Song sets are saved in files in the SongSets folder. These can then be reloaded at a later time for reuse. Use the 'Files' menu item in the SongSets assembly dialog to load and save your sets.

Using the code

In this section I will describe how ProjectMIDI is implemented and how you can extend it with your own code. I will provide source code examples to allow you to create your own MIDI applets or device modules.

What you will need

You will need Visual Studio .NET. ProjectMIDI is implemented as a set of .NET assemblies. Creating a new Applet or Device Module involves creating a new .NET assembly which contains a class which implements particular interfaces defined by ProjectMIDI. It also uses custom attributes to allow ProjectMIDI to interconnect events and actions (special event handlers) using reflection.

ProjectMIDI implements "late binding" of .NET assemblies. Therefore, new assemblies can be created, and ProjectMIDI will work with them without having to know about them.

Architecture

ProjectMIDI works by dividing its functionality up into multiple DLL .NET assemblies. These assemblies are "late binding" meaning that ProjectMIDI will search for and load any assemblies which contain a class that implements an interface known to it. I'll refer to these DLL files simply as "assemblies" within these pages.

The primary executable is ProjectMIDI.exe. This is the core program which in turn locates and loads all other assemblies.

Sets, Songs, Pages and Patches Data Model

ProjectMidi.exe implements the basic structure which organizes data into Song Sets, Songs, Pages and Patches.

Song Sets

A group of 1 or more song names can be organized into a collection referred to as a "Song Set". This can be the set of songs played for a particular gig, or maybe a set of songs related by theme or style. In fact, it doesn't even really need to be a collection of songs at all, but could be a set of MIDI setups.

Songs

These are the "names" which are passed to each assembly. The existing PDF and TIFF applets assume that this is the name of a PDF or TIFF file (minus the file extension). All of the other existing assemblies treat this strictly as a filename used to its data.

Pages

Songs can be broken down into multiple pieces referred to as pages. The PDF, TIFF and Ink assemblies will use this to display a different music page and notes. Device modules can select a separate patch or other settings.

Patches

Patches allow breaking a page into multiple sections, each with a different set of patches. PDF, TIFF and Ink assemblies ignore this parameter. However, a device module should allow selecting a different patch or group of settings for each patch.

Response to Song, Page or Patch changes

Assemblies can choose to be notified whenever the song, page or patch changes. How the assembly responds is left to each assembly to decide and implement.

Events and Actions Model

ProjectMIDI attempts to provide a very high degree of flexibility and extensibility. One of the ways that it does this is by "generalizing" the way that user inputs or events are associated with the resultant action.

Events

Each assembly can define and publish a set of events that it supports. For an Applet this might be a menu or pushbutton, while for a Device Assembly it could be a hardware control (slider or knob) or foot pedal or MIDI trigger.

Events are exposed to ProjectMIDI by giving them predefined "custom attributes". These attributes specify the name to display to the user as well as the number of values that the input provides.

The name given by the attribute is important in order to make using them easy and intuitive. For example, I've worked with MIDI software in the past which allows connecting a particular MIDI data type (eg. program change) to an action. It isn't at all clear though what this means. I'd much rather be able to specify that the "TD8 Inc/Dec Buttons" will cause an action instead of having to look up and specify the MIDI data type and value.

In addition to providing a name to an input, the custom attribute also specifies the number of possible input values. This allows better matching of inputs to outputs. For example, connecting a 128 position knob to a simple on/off type action might require interpreting values 0-63 as "off" and 64-127 as "on".

Events can have an "autoconnect" name associated with them. ProjectMIDI will automatically connect events and actions with matching autoconnect names at startup.

Actions

Each assembly also defines and publishes a set of actions which it implements. These are things like "Next page", "Display TD8 Patch Editor", and so forth. This is limited only by our imaginations.

Actions are methods with a signature that matches that needed for handling the events described above. A custom attribute is used to specify the friendly name and number of values the action can handle.

The data passed to actions from events is passed in an EventArgs or a class derived from it.

Connection lists

Inputs can be connected to actions in a couple of ways:

  1. Using matching autoconnect names
  2. By using the Connections dialog
    A dialog is provided to allow the user to manually specify additional connections, or to disable autoconnections.

Assembly defined Event/Action Associations

In addition the 2 methods described above, different assemblies can communicate with each other in a couple other ways:

  1. Expose Events, Actions, Methods, or Properties
    ProjectMIDI provides a mechanism for assemblies to view and connect with other assemblies provided they have flagged these using ProjectMIDI's custom attributes.
  2. Use multiple interface derivation
    In addition to deriving from IProjectMidi, an assembly's ProjectMIDI class can derive from additional interfaces. Another assembly can search the list of ProjectMIDI loaded assemblies using a mechanism provided by ProjectMIDI. Each can be tested to see if it derives from the desired interface. Once found, the custom interface can be used directly.

Persistence

User specified connections are persisted to an XML file actions.xml in the ProjectMIDI root folder. These will be restored each time ProjectMIDI starts.

ProjectMIDI Main Executable

ProjectMIDI dialog image

ProjectMIDI.exe is the primary application file. When it is started, it in turn loads all of the other ProjectMIDI assemblies.

It loads as a TaskBar icon. It displays a list of the assemblies that it has loaded in the 'Assemblies' submenu. Assemblies which can display a dialog can be shown or hidden by clicking on its name in the 'Assemblies' submenu.

ProjectMIDI.exe provides startup sequencing to allow assemblies to start in an orderly fashion. For example, it may be necessary for an assembly to perform some startup initialization after all assemblies have been loaded. Or it may need to wait even further until all connections have been established between assemblies.

All ProjectMIDI assemblies derive from the IProjectMidi interface. This fact is used by ProjectMIDI.exe to identify ProjectMIDI assemblies.

   // All ProjectMIDI Assemblies must include a class which derives

   // from this interface.

   // The IProjectMidi interface is used to allow polymorphic access

   // to each assembly.

   // It is the mother of all ProjectMIDI APIs.

   public interface IProjectMidi
   {
      IProjectMidiParent ProjectMidiParent { set; }
      void PerformStartProcessing( StartPhase phase );
   }

   public enum StartPhase {
      AfterLoading,           // After assembly is loaded

      AllAssembliesLoaded,    // After all assemblies have been loaded

      StartConnecting,        // Connections are starting to be connected

      FirstTimeEver,          // Only called the first time the assembly

                              // is loaded

      AllAssembliesConnected, // After all assemblies have been loaded

                              // and connections made

      InitDone,               // All initialization has completed

      Terminating             // ProjectMIDI is beginning to exit

    };

ProjectMIDI provides the following interface to assist assemblies in performing startup sequencing and connecting with other assemblies:

   public interface IProjectMidiParent : IProjectMidi
   {
      // The directory where all ProjectMIDI folders are placed.

      string ProjectMidiPath { get; }

      // The registry key for all other ProjectMIDI subkeys.

      RegistryKey ProjectMidiKey { get; }

      // Collection of all assemblies

      IIProjectMidiCollection IProjectMidis { get; }

     // This method is used by an assembly to manually create a connection

     // This should only be done the first time the assembly is loaded.

     void CreateAConnection(string eventAsmName, string eventName,
         string actionAsmName, string actionName,
         string connType, string connIntData,
         string connEnabled, string connFollowsSeparator,
         string connStringData);
   }

This interface is passed to the ProjectMidiParent property of each assembly immediately after it is loaded.

ProjectMidiPath indicates the file path to the root ProjectMIDI folder. Any folders created and used by ProjectMIDI assemblies should be created beneath this folder.

Likewise any registry information created and used should be located under the ProjectMidiKey.

IProjectMidis provides a standard collection of IProjectMidi interface pointers allowing all other loaded assemblies to be accessed. Note that other assemblies may not have been loaded at the time that the constructor is run. In order to ensure that the other assembly has been loaded, wait for PerformStartProcessing to be called with the phase parameter set to AllAssembliesLoaded.

The CreateAConnection method is used by an assembly to create connections. This will typically be done only the first time that it is loaded. Connections are persisted by the Connections assembly.

SongSet Assembly

This assembly manages the song set collection. Other assemblies can connect to this assembly in order to control or receive notifications regarding changes to the current song set, song number, or patch.

ProjectMIDI Song Parameter Persistence

Most assemblies will need to persist settings related to each song. The SongSet assembly provides a set of persistence methods which can be used to do this.

In order to use the ISongSet interface, an assembly must wait until all assemblies are loaded, then search the list of assemblies for one that implements the ISongSet interface. You can find an example of this is the PDF.cs file. PerformStartProcessing is called, and when passed the AllAssembliesLoaded parameter it in turn calls the AllAssembliesLoaded() method. This method then searches the IProjectMidis collection for the assembly which implements ISongSet.

The ISongSet interface can be used to determine the current song, page, and patch. It also provides methods to save and restore custom song parameters. These parameters will be saved by the SongSet assembly in a songdata.xml file.

   public interface ISongSet
   {
      string    CurrentSongName { get; }
      int       CurrentSongNum { get; set; }
      int       CurrentPageNum { get; set; }
      int       CurrentPatchNum { get; set; }

      // These next methods provide persistence of song related parameters.

      // Assemblies can use these to persist per-song data

      string    GetSongParameter( string name, string defaultdata );
      void      SetSongParameter( string name, string data );

      ISongCollection Songs { get; }

        // Note: the following methods are placeholders at this time.

//    string    GetPageParameter( string name, string defaultdata );

//    void      SetPageParameter( string name, string data );

//    string    GetPatchParameter( string name, string defaultdata );

//    void      SetPatchParameter( string name, string data );

   }

Once you have the ISongSet interface pointer, it can be used to call the SetSongParameter() and GetSongParameter() methods.

Since all assemblies can use the persistence methods, select the name parameter such that it will not conflict another assembly's parameters. This can be done by using the assembly name as part of the parameter name.

Connections Assembly

The Connections assembly provides late-binding of connections between assembly events and event handlers (actions).

Reflection is used to identify those events and actions that are intended to be used for this purpose.

ProjectMidi Events

Events which happen within an assembly can be exposed to the rest of the assemblies by giving them the [ProjectMidiEventAttribute] attribute. This attribute informs ProjectMIDI that this event can be connected to "ProjectMidi Actions". This event must conform to the following signature:

   public delegate void ProjectMidiEventHandler(object sender, EventArgs e);

   public event ProjectMidiEventHandler EventName;

Refer to the ProjectMidiInterfaces.cs file for the definition of classes derived from EventArgs which may be used within ProjectMIDI.

ProjectMidiEventAttribute

This attribute identifies an event as a ProjectMIDI event. It can optionally specify the following parameters:

  • Name

    Gives a name to the event. This name will be displayed in the Connections dialog.

  • Number of values

    Specifies the number of different values which this event can generate. For menu item, this would be 1. For a device slider this could be 128.

  • Auto-Connection Name

    The first time that ProjectMIDI loads an assembly, it will search for events and actions with matching "Auto-Connect" names and automatically connect them.

  • Connection Type

    This identifies the "type" of connection. This information is used internally by ProjectMIDI. For most connections this should be ConnectionType.Normal.

  • Tooltip string

    This string will be displayed in the "Connections Dialog" when the mouse hovers over this event.

Dynamic Events

Some events may need to be created dynamically. For example, Midi Input Port events will be created depending on the particular MIDI hardware installed.

Classes which need to implement "dynamic events" must implement the IProjectMidiDynamicEvent interface.

To create a dynamic event, use the IProjectMidiConnection interface to add a new PMEventInfo object to the IProjectMidiConnection.AllEvents collection.

Refer to the IProjectMidiDynamicEvent code in MidiPort.cs.

ProjectMidi Actions

Actions which are implemented within an assembly are exposed to the rest of the assemblies by giving them the [ProjectMidiActionAttribute] attribute. This attribute informs ProjectMIDI that ProjectMidi Events can be connected to them. These actions must conform to the following signature:

   public void HandlerName(object sender, EventArgs e);

As you can see, this signature matches the ProjectMidiEventHandler delegate signature listed above it.

Refer to the sample source code for actual code listings and comments.

Dynamic Actions

Some actions may need to be created dynamically. For example, Midi Output Port actions will be created depending on the particular MIDI hardware installed.

Classes which need to implement "dynamic actions" must implement the IProjectMidiDynamicActions interface.

To create a dynamic action, use the IProjectMidiConnection interface to add a new PMActionInfo object to the IProjectMidiConnection.AllActions collection.

Refer to the IProjectMidiDynamicAction code in MidiPort.cs.

Automatic Connections

Some connections will need to be connected automatically when ProjectMIDI starts. For example, connecting a source of trace messages to the Trace Message assembly, which then displays the messages. This is accomplished by specifying a common connection name in the attributes for both the events and the actions.

The first time that ProjectMIDI loads an assembly, it will search for events and actions that specify the same "autoconnect" name. When found, they will be automatically connected.

Existing connections will be saved to connections.xml. When ProjectMIDI starts, it will load connections.xml and reconnect events and actions previously connected.

SubMenu Assembly

This assembly implements multilevel context menus. A action is exposed which can be connected to an assembly's menu event.

Midi Assembly

The Midi assembly provides connections to and from the MIDI ports present on the system. It opens all MIDI ports and dynamically creates events and actions to each of them.

GMSynth Assembly

This assembly provides support for a GM synth. It interfaces with the songset assembly's ISongSet interface to provide a program change for each song selected.

This assembly provides a good starting point for creating your own MIDI device assembly.

PDF Assembly

This assembly interfaces with Adobe Acrobat to display a PDF file based on the currently selected song and page.

TIFF Assembly

This assembly is similar to the PDF assembly. It displays a TIFF file based on the currently selected song and page.

Sample Assembly

This assembly is provided as an example of how to expose events and actions. It is a good starting point for writing your own ProjectMIDI assembly.

TD8 Assembly

This assembly interfaces with a Roland TD8 drum module. It allows specifying the drum pad patches for each song and page.

This module is fairly large. I don't recommend using to create your own assembly. It does provide an example of how to generate system exclusive messages though.

XP30 Assembly

This assembly interfaces with a Roland XP30 MIDI keyboard. It selects an XP30 voice based on the currently selected song.

Ink Assembly

This assembly uses and requires the Microsoft Tablet PC SDK. It will connect itself to the PDF or TIFF assembly to "collect ink". It allows drawing notes on the displayed PDF or TIFF. The ink will then be displayed along with PDF or TIFF associated with the currently selected song and page.

It searches all assemblies looking for one which implements the IHasDisplaySurfaces interface. When found, it will use this interface to hook its OnDisplayResize event and get its display handle for use by the Microsoft Table PC SDK InkOverlay object.

Building and running the code

Building the code should be very straight forward if you do not rearrange the folders. Building might become a bit tricky if you do because there are multiple executables with some interdependencies. These dependencies are as follows:

  • All assemblies derive from IProjectMidi which is defined in ProjectMidiInterfaces.dll. If you rearrange the location of the various directories, this reference may become invalid. If this happens then you will need to correct the reference to ProjectMidiInterfaces.dll in order to resolve this.
  • MP3 requires the Quartz library: This should be included with Windows XP
  • Ink requires that the Microsoft Tablet PC SDK be installed: This can be obtained from the Microsoft MSDN site.

After downloading and extracting the files, open either the ProjectMidiAll.sln or the ProjectMidiCore.sln file. This should launch Visual Studio .NET and display the solution containing all or just the required project files. I recommend that you copy the ProjectMidiAll.sln file, and remove the projects that you do not want from it.

Note that you will probably not want to include and build every project. Only include those that are applicable to your system.

Project Name Executable Created Description Notes
ProjectMIDI ProjectMidi.exe Main executable Required
Connections Connections.dll Manages connections between assemblies Required
GMSynth GMSynth.dll Example MIDI device assembly Include for sample purposes, or to interface with a General MIDI device
Ink Ink.dll Adds ability to scribble notes over displayed PDFs or TIFFs. Include if you have a Tablet PC or digitizer pad and have installed the MS Tablet PC SDK.
Midi Midi.dll Provides communication with MIDI ports. Required if MIDI will be used
MP3 MP3.dll Provides MP3 playback functions Include if MP3 playback is desired. Requires Quartzlib.
PDF PDF.dll Provides the PDF display functions Requires the full version of Acrobat be installed.
ProjectMidiInterfaces ProjectMidiInterfaces.dll Provides several key interface implementations Required. Used by most other DLLs
SampleAssembly SampleAssembly.dll This is a sample assembly that you can use to rename and start your own assembly Optional
SongSet SongSet.dll Provides the song Set, Song, and Patch functions. Required
SubMenu SubMenu.dll Provides the customizable menu functions. Required
TD8 TD8.dll Provides interface to Roland TD8 MIDI drum device Include if you own a Roland TD8 drum module
TIFF TIFF.dll Provides .tif display functions. This is provided as an alternative to PDF Include if you do not have PDF installed
TraceWindow TraceWindow.dll Provides a window to display trace messages from ProjectMIDI.exe and other assemblies. Optional
us428 us428.dll Provides interface with Tascam US-428 control surface Include if you own a Tascam US-428 control surface
VBAssembly VBAssembly.dll This is a sample VB assembly Include as a sample if you plan on working in VB
XP30 XP30.dll Provides interface to Roland XP30 MIDI keyboard Include if you own a Roland XP30 keyboard

Running the code the first time

Before running ProjectMIDI, you will need to copy all of the created assemblies (.DLLs) to the Assemblies folder. I've setup a post-build batch file to perform this copy automatically to the Runtime/Assemblies folder. If you move this folder then you will need to either update each of these batch files, or else copy the files manually before launching ProjectMidi.exe.

When the ProjectMIDI.exe executable is run the first time, it will search for its environment variables. In particular, it needs to know the FoldersPath. It will prompt the user for this path if not found. If the full installer is used, this path will be created. If you are building the code from scratch without having run the installer, then you will need to create these folders and copy your files to them. Be sure to copy all of the .DLLs created to the /Assemblies folder. When ProjectMIDI.exe is run the first time, it will ask where the ProjectMidi folder is located. Select the folder which contains all of these other folders. This variable points to the path which contains the following folders:

Folder Name Folder Contains Used by Assembly
Assemblies All ProjectMIDI assembly DLLs ProjectMIDI.exe
Ink Tablet PC Ink files Ink.dll
PDFs All PDF files PDF.dll
Sets All .set song set files SongSet.dll
TD8 All .td8 drum voice files TD8.dll
TIFFs All .tif files TIFF.dll

Which of these folders you need will depend on which of the DLLs you include on your system. You probably will not want to include both PDFs and TIFFs. Choose PDFs if you have Acrobat installed on your system, otherwise use TIFFs.

Likewise, include Ink and the Ink.dll if you have a Tablet PC and have installed the Table PC SDK.

Points of Interest

I learned a lot about .NET executable files during this project. I think it was worth it though. The platform I've created allows very quick creation of MIDI applets which I will use to fully exploit the capability of my existing and future MIDI hardware.

History

Date Description
8 Jan 2006 Initial document creation using combined content from www.ProjectMIDI.com pages

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here