The Midi Kit: BMidiSynth

The Midi Kit Table of Contents | The Midi Kit Index

# BMidiSynth

Derived from: BMidi

Declared in: be/midi/MidiSynth.h

Library: libmidi.so

###### Summary

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

### 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 `B_OK`. The other two `status_t` functions return...

- `B_OK`. Instrument successfully loaded or remapped.

- `B_BAD_INSTRUMENT`. Illegal instrument specification.

- B_NO_MEMORY. Not enough memory to load instrument.

### 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 Midi Kit Table of Contents | The Midi Kit Index

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

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