My OS X Programming Blog
Mac OS X Cocoa and CoreMIDI Programming
About Andrew Choi


MIDI Programs

MIDI File Player (External Device)

MIDI Destination Pop-Up Button

MIDI File Player (Internal Synth)

MusicSequence Sample Code

MIDI File Writer

MIDI Name Document Parser

NameConfigSetup

Fish Creek MIDI Framework

MidnamUtility

SysExSenderX

Other Programs

FCBlogEditor

FCBlog and Patch

Chinese Checkers Program

jyut6 ping3 Cantonese Input Method

Cocoa Sample Programs

Syntax Coloring Using Flex

NSTextField and Undo

NSToolbar

Implementing File Import

Launch Application and Open URL

Saving Uncommitted Text Field Edits

Algorithms

Jazz Chord Analysis as Optimization

Optimal Line Breaking for Music

Optimal Chord Spacing

   

A blog where I will write mostly about programming in Cocoa and CoreMIDI, and experiences from my ports of Emacs and XEmacs to the Mac OS.

Graphical User Interfaces for Dynamic Data
Saturday September 25, 2004

It took a bit of programming and testing to get the user interface for patch selection to work correctly. The challenge comes from keeping the data presented by the interface current and consistent, while its value may change due to operations occurring outside our application. If one hasn’t written something like this before, it’s really quite a good programming exercise. This is a programming problem that one encounters more often than one may think: the same techniques may be used for implementing file browsers, real-time database system GUI’s, and in fact any GUI representing “live” data. I’m quite surprised that not more has been written about it.

The following screenshots illustrate the external changes that may occur for our patch selection test program. Before an external MIDI device is specified in Audio MIDI Setup, the MIDI interface name appears in the “MIDI Device” menu. Of course no MIDI name document can be associated with the MIDI interface. So only the “Bank and Patch Numbers” selection method is enabled.

When an external device (a JD-990) is added in Audio MIDI Setup, the “MIDI Device” menu automatically updates to show its name. Note that no MIDI name document is associated with the device yet.

Using NameConfigSetup, a MIDI name document is associated the JD-990. Now the “Patch Name” selection method automatically becomes available.

Apart from the code for maintaining a GUI for dynamic data, I also worked on using patch names for choosing General MIDI sounds for the internal synthesizer. The “[Internal Synth]” item always appear in the “MIDI Device” menu.

Here is the menu.

Self References
Thursday September 23, 2004

The links that were listed on the left-hand column of this page were getting a little out-of-date. So I added some new links and organized them by category. Also added some links on the right. Hopefully older entries in my blog will be easier to find now.

Patch Names
Wednesday September 22, 2004

A while ago I posted a NameConfigSetup utility for associating patch name lists stored in MIDI name documents with MIDI devices. Since I now also have a GUI test program for selecting patches, I can more easily explain the use of that utility.

First we specify all the external MIDI devices connected in Audio MIDI Setup. In this example the setup consists of a single Yamaha DX-7 II.

When an external MIDI device has just been added in Audio MIDI Setup, no master name document is associated with it, as can be verified in NameConfigSetup.

This means that MIDI applications cannot refer to patches by name yet. To enable this a master name document needs to be chosen for the MIDI device. When the “Choose...” button in NameConfigSetup is clicked, a open file panel appears where we can choose a MIDI name document. In this example we choose the file “Yamaha DX7 II.midnam.xml” which contains the names of factory default patches.

We can verify that patch names are now associated with the MIDI device in my patch selection test program. The patch names appear in the menu of the “patch” pop-up button.

The design of the “name config” property of a device in CoreMIDI allows each of its patch banks to be overriden by a patch bank in MIDI name documents other than the master name document. One way to use this mechanism is to have a patch librarian application fetch patch names by exchanging sysex messages with a MIDI device, write out the MIDI name document that represents these patch names, and override the factory default patch names with these current ones. I wrote a utility called MidnamUtility that does exactly this (with embedded Python, I might add). After generating the MIDI name document (called DX7II-studio-names.xml in the example), I override the factory default performance names with those in it in NameConfigSetup.

Once this is done, the new patch names appear in the “patch” pop-up button in the patch selection test program.

Controller (in Model-View-Controller) for Dynamic Data
Tuesday September 21, 2004

Let’s try to present the design of the user interface for selecting patches described yesterday as a design pattern. This is just a draft at the moment.

Controller (in Model-View-Controller) for Dynamic Data

Intent
We consider the design of the controller in a Model-View-Controller (MVC) implementation of a user interface that represents data that may change “spontaneously” under certain external influences.

Motivation
Consider the implementation of a pop-up button for selecting one of the destination endpoints in a MIDI setup. The contents of the menu of the pop-up button change when the MIDI setup changes due to operations occuring outside our application (being modified in Audio/MIDI Setup, e.g.). Such a change may invalidate the current state of our user interface (such as the current selection, menus, etc.). E.g., the current selection may no longer be present. The change may also invalidate the state of or change other parts of the user interface. E.g., the contents of a bank and patch pop-up button should change when a different destination endpoint is selected. A mechanism needs to be provided for notifying the relevant objects to allow them to return to a valid state.

Applicability
Use Controllers for Dynamic Data to control different parts of a complex user interface when each of these parts represent data that may change under external influences, and such changes influence other parts of the user interface in some way.

Structure
@interface ControllerForDynamicData : NSObject {
   ...
}
- (ControllerForDynamicData *)initWithControl:(id)control
   stateChangedTarget:(id)target stateChangedSelector:(SEL)selector;
- (void)fill;
- (NSDictionary *)state;
- (void)setState:(NSDictionary *)newState;
@end
A ControllerForDynamicData object is associated with its set of controls in the user interface when it is initialized. A callback function is also registered, which will be called when the state of the controller changes, either due to external influences, or interactions at the user interface. The method fill is used to initialized the set of controls associated with the controller (such as populating the menu of a pop-up button). The method state returns the current state of the part of the user interface represented by the controller (e.g., the currently selected destination endpoint). The method setState sets this state (e.g., selecting the destination endpoint using stored preferences). Internally the controller carries out the operations to keep the controls in sync with the changing date represented (e.g., the menu of the pop-up button is updated whenever the MIDI Setup changes).

Participants and Collaborations
A top-level ControllerForDynamicData object may contain a number of ControllerForDynamicData objects. E.g., a “patch selection” controller may contain a destination endpoint selection controller, a bank and patch name selection controller, and a bank and patch number selection controller. Parent ControllerForDynamicData objects call the initialization, fill, and setState methods of its child ControllerForDynamicData objects, and listen to their call backs. These call backs may cause the fill and/or setState of sibling ControllerForDynamicData objects to be called. E.g., when the destination endpoint selection controller issues a call back to the top-level ControllerForDynamicData object to notify it of a state change, the latter calls the fill method of the bank and patch name selection controller to cause it to update the list of names in pop-up buttons under its control.

Consequences
The design of a complex user interface representing dynamic data can be broken down into a number of controllers, with well-defined interactions.

Implementation
Call back functions are easier to do in a language such as Objective C.

Sample Code and Usage
Some of this is implemented in EndpointPopUpTest.

Known Uses
My sample code. Don’t know if there are other uses.

Related Patterns
Model-View-Controller.

Patch Selection Controller
Monday September 20, 2004

Here’s a pretty clean design for an interface that supports all the different methods for selecting patches on a MIDI device. The “mode” of the device is set elsewhere (cf. last week’s discussion). Therefore we are left with pop-up buttons for choosing the MIDI device, channel, bank, and patch.

The “Patch” pop-up button lets the user select a patch by name.

But what if the device isn’t associated with a MIDI name document? That’s what the “Selection Method” pop-up button is for: in addition to “Patch Name”, a patch can be selected by “Bank and Patch Numbers”.

When this item is selected, the controls below that pop-up button changes to ones for entering bank and patch numbers.

But since different synthesizers have different methods of specifying banks and patches, the “Device Selects Patch By:” pop-up button allows the user to choose the appropriate method. The possible choices are:
  • Program Change;
  • Bank Select 0, Bank Select 32, Program Change;
  • Bank Select 0, Program Change;
  • Bank Select 32, Program Change; or
  • Program Change, Program Change.

For example, when “Bank Select 0, Bank Select 32, Program Change” is selected, text fields appear for entering these three values.

This interface uses “tab-less” tab views, which makes the implementation a little easier. I’ll write tomorrow about the structure of the entire controller. This has become a bit complex because of all the different methods of specifying patches that need to be supported.

September 2004
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
Aug  Oct

xml

Search this blog with


Lists

Less-Known Facts About Emacs

Emacs Rants

Chinese Restaurants in Calgary

Calgary/Banff Tourist Attractions

C++ Reading List

Science Fiction Series

Top-10 Reason I Stopped Working on Emacs

Top-10 Types of Questions I Get About Emacs

10 Defining Moments as Programmer


Misc

Carbon XEmacs

Emacs for Mac OS X


Copyright © 2003, 2004, 2005 Andrew Choi (Contact Information). Created with FCBlog