About Andrew Choi
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
Fish Creek MIDI Framework
FCBlog and Patch
Chinese Checkers Program
jyut6 ping3 Cantonese Input Method
Cocoa Sample Programs
Syntax Coloring Using Flex
NSTextField and Undo
Implementing File Import
Launch Application and Open URL
Saving Uncommitted Text Field Edits
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.
Saturday May 15, 2004
Sample Code for Music Sequences in Audio Toolbox
MusicSequence data type in the Audio Toolbox (which is part of CoreAudio) is really quite easy to use. Heres some sample code that demonstrates how to construct a music sequence, set its tempo, add a track to the sequence, name the track, add a patch change, add some notes, and append an end of track meta event (so that a player wont cut off the last few notes), and save that music sequence to a standard MIDI file. And its all only 50 or so lines! My own MIDI file writer is a few times more lines than that.
Im sure once we start doing real-time stuffs with the music player, itll get a little harder. But for now thats all the functionality Ill need. The big advantage of adding
MusicSequence support to my jazz theory classes is these opaque data objects (which are supported directly by system frameworks) can then be passed between my C++ code and Objective C/Cocoa code without the need for conversion. Im also thinking about changing my chord grid objects into CoreFoundation arrays/dictionaries so that can be passed between C++ and ObjectiveC/Cocoa code conveniently.
Friday May 14, 2004
Music Player and Music Sequence in Core Audio
Nothing too fancy to post today. Just a little MIDI file player Ive thrown together quickly after studying the sample code in
/Developer/Examples/CoreAudio/Services/PlaySequence/. Its just a bit of simplification of that code, and a test for using a MIDI file already stored in an
NSData object. That way we dont have to deal with
Ive spent the afternoon reading the latest (March 25, 2004) Core Audio documentation. CoreMIDI is still not included. What I noticed was the
MusicSequence data type which, if I had noticed that before, may have convinced me not to write my own MIDI file writer. Oh, well...
If one is implementing a program that deals with MIDI sequences, there is very little reason not to use
MusicSequence and its associated functions. It handles all the file I/O and playback and record timing for you, which makes the task much easier. It also allows each track of a sequence to be mapped to an external MIDI device or a music device (software synthesizer), which results in quite a flexible MIDI program.
Wednesday May 12, 2004
Band-in-a-Box File Import
Now that Ive worked out the file import architecture and code, implementing it in my program is just a simple matter of translating the C++ code for reading BiaB files I wrote earlier into Objective C/Cocoa. Ive done that for both routines: one that reads files written by BiaB 4.0 and above, and one for reading older files. Heres the chord editor running along side the BiaB demo, both with the same BiaB format file opened. The file import code I posted yesterday has also been integrated. So if an imported file has been edited, the chord editor will prompt the user for saving it in native file format (i.e., the text format I coded up last week) when it is closed or saved.
I havent shown an example that demonstrates the benefit of using a chord spacing algorithm before. So here is one.
Notice how BiaB switches to a smaller font size (bar 1, e.g.) or truncates some chord names (bar 3, e.g.) when space is tight. Both methods contribute to the ugliness of the resulting BiaB display in they own ways. Compare that to the nice layout and spacing on the left :-).
Tuesday May 11, 2004
Designing a Foreign File Format Import Function
Many applications have the ability to import files in non-native formats. Unfortunately, the design of user interactions dealing with these files differ from application to application. Even among Apple applications, Mail, e.g., provides an
Import Mailboxes... command, TextEdit allows files in foreign formats to be opened using the usual
Open... command but asks the user about saving them in a native format when they are closed, the document-based Cocoa application model allows roles (editor, viewer, or none) to be selected for different document types, and filter services can be used to convert among different file formats. Of course I need to provide file import for my program because it can import Band-in-a-Box files.
As usual, I couldnt find any good sample code for implementing file import. Although the source code for TextEdit is available in
/Developer/Examples/AppKit/, one cant really learn much from it because of how it is written: it doesnt even use most of the features that are provided for free by Cocoa and implements its own! In fact it is quite amusing that source code that messy (1) is provided as sample code, and (2) implements such a commonly-used utility!
The easiest way to implement file import is probably to provide an
Import... command and create an untitled document (of the native document type) into which the imported file contents are placed. This method has the disadvantage of requiring the user to specify the name of the file again when the document is saved (a better interface should suggest by default the name of the imported doucment with a different file extension). Another way is to use the editor/viewer mechanism of the Cocoa document-based application. But the method described in the NSDocument FAQ for reading one type and (internally) automatically converting to another doesnt implement a good interface either. Specifically the application will prompt the user to choose the location to save a new, converted file all over again after its
fileType have been changed.
In any case, heres my clean and simple sample code for implementing file import! It follows the TextEdit interaction model most closely but without the coding mess. It handles two types of files, with suffixes
.imported, with a single document type. The method
NSDocument is overridden to inform the user of the conversion to native format when it needs to be performed. The more interesting part of the code is the overriding of
canCloseDocumentWithDelegate:shouldCloseSelector:contextInfo: which allows the user to save a document if necessary when it is closed. I suppose this code also illustrates how much the callback model for implementing GUIs is messier than the multithread model. But theres no avoiding the former if one is programming with Cocoa.
Search this blog with
Less-Known Facts About Emacs
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
Mac OS X