The Be Book The Midi Kit The Midi Kit Index

BMidiSynthFile

Derived from: public BMidiSynth
Declared in:  be/midi/MidiSynthFile.h
Library: libmidi.so
more...


The BMidiSynthFile class reads a standard MIDI file and plays it on the General MIDI synthesizer. Each BMidiSynthFile object can read (and play) only one file at a time. To use a BMidiSynthFile, you create the object, load a MIDI file, and tell the object to Start():

/* Create and initialize a BMidiSynthFile. */
BMidiSynthFile midiSynthFile;
entry_ref midiRef;
get_ref_for_path("/boot/optional/midi/QuickBrownFox.mid", &midiRef);
midiSynthFile.LoadFile(&midiRef);

/* Play the file. */
midiSynthFile.Start();

You should create a different BMidiSynthFile object for each MIDI file that you want to mix together into a single performance.

In certain circumstances, a single BMidiSynthFile object can load and play more than one MIDI file at the same time, but you shouldn't rely on this feature.

Loading and Playing

When you call LoadFile(), the BMidiSynthFile object automatically calls...

EnableInput(true, false)

It then loads the file's MIDI data into the synthesizer, which loads all the instruments that are needed by the file. If the file uses a lot of different instruments, loading the file can take some time.

When the file is finished playing (either because it's reached the end, or because you called Stop()) the instruments are not unloaded. This cuts the overhead if you play the file a second time.

The Run Thread and Function

BMidiSynthFile is different from other Start()-able BMidi objects in that it doesn't have a run loop. The MIDI data is parsed and realized in the synthesizer's subscriber thread (the thread that dumps data into the DAC stream). The lack of a run loop shouldn't affect the way you write your code, but you should be aware that the thread isn't there so you won't go looking for it while you're developing your app

Furthermore, BMidiSynthFile doesn't implement the Run() function. Starting and stopping the object's performance (activities that are normally handled in the Run() function) are handled by the synthesizer in its subscriber thread. If you create a BMidiSynthFile subclass, don't try to resurrect the Run() function—leave it as a no-op.

As with the BMidiSynth class, the BMidiSynthFile MIDI hook implementations don't call the spray functions. This means that you can't, for example, connect a BMidiSynthFile to a BMidiPort. If you want to play a MIDI file out a MIDI port, use BMidiStore to represent and play the file.


Constructor and Destructor


BMidiSynthFile()

BMidiSynthFile(void)

Creates a new, empty BMidiSynthFile object. Also constructs a BSynth object and assigns the object to the app-wide be_synth variable (if the object doesn't already exist). To load a MIDI file into the BMidiSynthFile object, you must call LoadFile() after construction. Unlike plain BMidiSynth instances, however, you don't have to call EnableInput() (LoadFile() calls it for you).


~BMidiSynthFile()

virtual ~BMidiSynthFile()

Disconnects the object from the synthesizer, unloads the object's file (and all its instruments) and destroys the object.


Member Functions


Duration() , Position() , Seek()

int32 Duration(void) const
status_t Position(int32 ticks)
int32 Seek(void)

Duration() returns the length of the object's loaded data, measured in 64ths of a MIDI tick.

Position() sets the object's current position within the data.

Seek() returns the object's current position.

If you want to reposition the "song pointer", you should do it as a percentage of the Duration() measurement.

A MIDI tick is defined by the "MIDI Division" field at the bginning of every MIDI file; this value can be specified by the file as either "ppgn" (tempo-dependent) or frames:subframes per second (tempo-independent). The BMidiSynthFile class assumes that the division is tempo-independent.

RETURN CODES

Currently Position() always returns


EnableLooping()  see Start()
GetMuteMap()  see MuteTrack()


GetPatches()

status_t GetPatches(int16 *instruments, int16 *count)

Returns an array of the instruments numbers that are needed by the loaded MIDI file. The instruments array should be 128 elements long (to be on the safe side), and must be allocated before it's passed in. Upon return, function sets count to the number of instrument numbers that it placed in the array. For example:

int16 insts[128];
int16 count;
midiSynthFile.GetPatches(insts, &count);
for (int n = 0; n < count; n++)
   printf("The file uses instrument #%dn", insts[n]);


GetSoloMap()  see MuteTrack()
IsFinished()  see Start()


LoadFile() , UnloadFile()

status_t LoadFile(const entry_ref *midiFileRef)
void UnloadFile(void) const

LoadFile() tells the object to load, into the synthesizer, the MIDI data from the midiFileRef. The synthesizer caches the data for subsequent playback (which you initiate through Start()). All instruments that are needed to play the file are loaded into the synthesizer, if they're aren't loaded already.

UnloadFile() stops playback of the data that was loaded through this object (if it's playing), and flushes the data (removes it from the synthesizer).

In certain circumstances, a single BMidiSynthFile object can load and play more than one MIDI file at the same time, but you shouldn't rely on this feature.

RETURN CODES


MuteTrack() , GetMuteMap() , SoloTrack() , GetSoloMap()

These functions are broken; don't use them.


Pause()  see Start()
Position()  see Duration()
Resume()  see Start()
ScaleTempoBy()  see Tempo()
Seek()  see Duration()
SetFileHook()  see Start()
Set  see Tempo()
SoloTrack()  see MuteTrack()


Start() , Stop() , Fade() , Pause() , Resume() , IsFinished() , EnableLooping() , SetFileHook() , synth_file_hook

virtual status_t Start(void)
virtual void Stop(void)
void Fade(void)
void Pause(void)
void Resume(void)
bool IsFinished(void) const
void EnableLooping(bool loop)
void SetFileHook(synth_file_hook fileDone, int32 arg)
typedef void (*synth_file_hook)(int32 arg)

These functions control the object's performance.

Start() tells the synthesizer to start playing the object's loaded MIDI data beginning at the beginning. Note that Start() does not halt a performance in progress; in other words, if the object is already playing its data, you'll get a second, performance while the first continues.

Stop() immediately halts the currently playing data. Fade() also stops playback, but is a bit more graceful: It fades out the sound before killing it.

BMidiSynthFile's Start() and Stop() replace the functions defined by BMidi; in particular, they spawn and control a "run" thread. See  "The Run Thread and Function" on page33 for more information.

Pause() and Resume() do as they say. Note that when you resume playback, "old" notes are not regenerated, but exact timing is respected. For example, lets say you have a MIDI file that contains two notes, one that starts at time 1.0 (seconds) and lasts for 10.0 seconds, and the other starts at time 9.0. You start the file, then Pause() at time 3.0; as expected, the first note stops. After awhile, you Resume(); there's a six second silence and then the second note plays.

IsFinished() returns false if the object is currently playing (or paused during play). Note that the function returns false before you load a file, and returns true after you've loaded a file but before you begin playing it.

EnableLooping(true) tells the object to replay the file when it reaches the end of the data. If the argument is false, the file isn't replayed. Stop() always shuts up playback, even if looping is enabled.

SetFileHook() registers a function that's called when the object is finished playing (either because it ran out of data or Stop() was called. arg is passed to the hook function as its sole argument. Note that the hook function is called when the object is completely finished—it isn't called at the end of each pass through the data while looping is enabled.

RETURN CODES

Start() returns...


Stop()  see Start()
synth_file_hook  see Start()


Tempo() , SetTempo() , ScaleTempoBy()

int32 Tempo(void) const
void SetTempo(int32 beatsPerMinute)
void ScaleTempoBy(double scalar)

Tempo() returns the tempo of the data, as read from the MIDI file (or as set by the other functions), in beats-per-minute. The other two functions set the tempo: SetTempo() sets it absolutely in beats-per-minute, and ScaleTempoBy() scales the current tempo by the argument (scalar == 2.0 means the data is played twice as fast, scalar == .5 is twice as slow, and so on).


UnloadFile()  see LoadFile()

The Be Book The Midi Kit The Midi Kit Index

The Be Book,
...in lovely HTML...
for BeOS Release 5.

Copyright © 2000 Be, Inc. All rights reserved..