The Be Book The Midi Kit The Midi Kit Index

BMidiSynth

Derived from: BMidi
Declared in:  be/midi/MidiSynth.h
Library: libmidi.so
more...


The BMidiSynth class is the MIDI interface to the General MIDI synthesizer. If you want to send MIDI data to the synthesizer, you have to create an instance of BMidiSynth. You can can send MIDI messages to the object directly:

/* Create and initialize a BMidiSynth. */
BMidiSynth midiSynth;
midiSynth.EnableInput(true, true);

/* Choose an instrument and play a note. */
midiSynth.ProgramChange(1, B_ACOUSTIC_GRAND);
midiSynth.NoteOn(1, 40, 100, B_NOW);
snooze(1000000);
midiSynth.NoteOff(1, 40, 100, B_NOW);

Or you can connect the BMidiSynth to the output of some other BMidi object, such as a BMidiPort:

/* Connect the synth to a MIDI port. */
BMidiPort midiPort;
char buf[B_OS_NAME_LENGTH];

/* Initialize the BMidiPort. */
if (midiPort.GetDeviceName(0, buf) == B_OK) {
   midiPort.Open(buf);

   /* midiSynth from above -- already created and initialized. */
   midiPort.Connect(midiSynth);
   midiPort.Start();
   ...
}

The one thing you shouldn't do is connect a BMidiFile to a BMidiSynth. If you want to realize the contents of a MIDI file, you should use an instance of BMidiSynthFile instead (BMidiSynthFile is derived from BMidiSynth).

BMidiSynth doesn't spray MIDI messages, so it doesn't do any good to connect other BMidi objects to its output. In other words, don't do this:

/* --- DON'T DO THIS --- It's meaningless. */
midiSynth.Connect(someOtherMidiObject);

Initializing your BMidiSynth

When you create a BMidiSynth object, it creates an instance of BSynth for you (if the object doesn't already exist). The BSynth object, which its represented globally in your application as be_synth, provides control over some of the synthesizer's global parameters, such as volume and reverberation.

Before you send messages to your BMidiSynth, you have to call EnableInput(). The function enables the object's input and tells the synthesizer whether it should load the synth file. If you tell EnableInput() not to load the file, you'll have to load the instruments that you want yourself. For example, here we load a single instrument, then play a note. We also have to send a ProgramChange() message to tell the BMidiSynth object use our loaded instrument on the proper channel (i.e. the channel that we're playing the note on):

/* Enable input, but don't load the synth file. */
midiSynth.EnableInput(true, false);

/* Load a couple of instruments. */
midiSynth.LoadInstrument(B_TINKLE_BELL);
midiSynth.LoadInstrument(B_VIOLIN);

/* Associate the instrument with a MIDI channel. */
midiSynth.ProgramChange(1, B_TINKLE_BELL);
midiSynth.ProgramChange(2, B_VIOLIN);

/* Play. */
midiSynth.NoteOn(1, 84, 100);
snooze(10);
midiSynth.NoteOn(2, 60, 100);
snooze(1000000);
midiSynth.NoteOff(1, 84, 100);
snooze(10);
midiSynth.NoteOff(2, 60, 100);

The order and number of instruments follow the General MIDI specification, but begin with instrument 0 (some synthesizers and sequencers expect instrument numbers to start at 1). The handy midi_axe constants, defined in be/midi/MidiDefs.h, provide the descriptive instrument names used here.

Instrument Scope

All of the instrument loading functions (EnableInput() and the functions described under LoadInstrument()) affect all be_synth clients (i.e. all BMidiSynth objects in your application). This can be beneficial: Loading an instrument from one BMidiSynth object means it doesn't have to be loaded again when, for example, a BMidiSynthFile needs it (the synthesizer is smart about reloading: If an instrument is already loaded, it won't try to load it again). As another example, if you have more than one BMidiSynth object, they can each load all instruments (through EnableInput()) without suffering a performance penalty.

However, there's a dark side: If a BMidiSynth unloads an instrument (through UnloadInstrument() or FlushInstrumentCache(false)), thet instrument disappears for all other BMidiSynth objects as well. You can prevent unwanted instrument unloading by calling FlushInstrumentCache(true) (see the function description for more information).

Percussion Instruments

To use the MIDI Channel 10 percussion instruments, you must load all instruments:

/* I want percussion, therefore... */
midiSynth.EnableInput(true, true);


Constructor and Destructor


BMidiSynth()

BMidiSynth(void)

Creates a new BMidiSynth 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 turn on your BMidiSynth object, you must call SetEnabled() after construction.


~BMidiSynth()

virtual ~BMidiSynth()

Disconnects the object from the synthesizer, and destroys the object.


Member Functions


EnableInput() , IsInputEnabled()

status_t EnableInput(bool enable, bool loadSynthFile)
bool IsInputEnabled(void) const

EnableInput() tells the object to connect and disconnect itself to the synthesizer, as enable is true or false. A disabled BMidiSynth doesn't pass on any MIDI messages to the synthesizer.

If enable is true and loadSynthFile is true, any instruments in the synth file (as designated by be_synth) that haven't already been loaded are immediately loaded. Loading the entire synth file can take a long time (more than a second, less than a minute), and this isn't your last shot at loading instruments, so you may not want to load all at once. If you want to defer loading, you can call LoadInstrument() after calling EnableInput().

IsInputEnabled() tells you if the BMidiSynth is currently enabled.

See  "Initializing your BMidiSynth" on page30 for more on instrument loading, instrument scope, and the use of Channel 10 percussion.

BMidiSynthFile objects do not have to call EnableInput(). Input is automatically enabled when the object loads a file.

RETURN CODES

Currently, EnableInput() always return


FlushInstrumentCache()  see LoadInstrument()
GetMuteMap()  see MuteChannel()
GetSoloMap()  see MuteChannel()
IsInputEnabled()  see EnableInput()


LoadInstrument() , RemapInstrument() , UnloadInstrument() , FlushInstrumentCache()

status_t LoadInstrument(int16 instrument)
status_t RemapInstrument(int16 from, int16 to)
status_t UnloadInstrument(int16 instrument)
void FlushInstrumentCache(bool flush)

These functions affect all be_synth clients (they should actually be part of the BSynth class).

LoadInstrument() loads the designated instrument from the synth file, if it isn't loaded already. You have to load an instrument before you can use it; if you've already loaded all instruments (through InputEnabled()), you won't have to call this function. A loaded instrument is available to all BMidiSynth objects in your application.

RemapInstrument() tells the synthesizer to replace all from instrument requests with to requests. For example, here we tell the synthesizer to play a gunshot whenever a banjo note is requested:

/* Banjo becomes gunshot. A good idea. */
midiSynth.RemapInstrument(B_BANJO, B_GUNSHOT);

UnloadInstrument() removes the designated instrument from the synthesizer.

FlushInstrumentCache() has a goofy protocol. If flush is false, the synthesizer stops playing all current notes (and samples) and unloads all loaded instruments. If flush is true, the synthesizer's current output is unaffected, but it's prevented from unloading any instruments in the future. In other words, FlushInstrumentCache(true) tells the synthesizer to ignore all subsequent UnloadInstrument() calls. The inability to unload instruments holds until FlushInstrumentCache(false) is called.

See  "Initializing your BMidiSynth" on page30 for more on instrument loading, instrument scope, and the use of Channel 10 percussion.

RETURN CODES

Currently, UnloadInstrument() always returns


MuteChannel() , GetMuteMap() , SoloChannel() , GetSoloMap()

These functions are broken; don't use them.


RemapInstrument()  see LoadInstrument()


SetTransposition() , Transposition()

void SetTransposition(int16 transpose)
int16 Transposition(void) const

SetTransposition() sets the amount, in halfsteps, by which subsequently generated notes will be transposed (shifted in pitch). Notes that are already sounding are not transposed. The transposition affects all channels of the invoked-upon object.

Transposition() returns the current transposition amount (in halfsteps); the default is 0.


SetVolume() , Volume()

void SetVolume(double volume)
double Volume(void) const

SetVolume() scales the object's amplitude (on all channels) by volume. In addition to affecting subsequently-generated notes, the new volume scale affects notes that are currently being generated by this object.

Volume() returns the current amplitude scalar value; the default is 1.0.


SoloChannel()  see MuteChannel()


Tick()

uint32 Tick(void) const

Returns the number of microseconds since the object was created. You should use this measurement for relative values only (for measuring the time between notes, for example). Also, note that the time argument to the MIDI hook functions measures time in milliseconds.


Transposition()  see SetTransposition()
UnloadInstrument()  see LoadInstrument()
Volume()  see SetVolume()

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..