Public Member Functions
BMidiLocalConsumer Class Reference

A consumer endpoint that is created by your own application. More...

Inheritance diagram for BMidiLocalConsumer:
BMidiConsumer BMidiEndpoint

List of all members.

Public Member Functions

 BMidiLocalConsumer (const char *name=NULL)
 Creates a new local consumer endpoint.
status_t Acquire ()
 Increments the endpoint's reference count.
virtual void AllNotesOff (bool justChannel, bigtime_t time)
 Not used.
virtual void ChannelPressure (uchar channel, uchar pressure, bigtime_t time)
 Invoked when a Channel Pressure event is received.
virtual void ControlChange (uchar channel, uchar controlNumber, uchar controlValue, bigtime_t time)
 Invoked when a Controller Change event is received.
virtual void Data (uchar *data, size_t length, bool atomic, bigtime_t time)
 Invoked when raw MIDI is received.
int32 GetProducerID ()
 Returns the ID of the producer that most recently sent a MIDI event to this consumer.
status_t GetProperties (BMessage *properties) const
 Reads the properties of the endpoint.
int32 ID () const
 Returns the ID of the endpoint.
bool IsConsumer () const
 Determines whether this endpoint is a BMidiConsumer.
bool IsLocal () const
 Determines whether this endpoint represents a local object.
bool IsPersistent () const
 Not used.
bool IsProducer () const
 Determines whether this endpoint is a BMidiProducer.
bool IsRemote () const
 Determines whether this endpoint is a proxy for a remote object.
bool IsValid () const
 Determines whether the endpoint still exists.
virtual void KeyPressure (uchar channel, uchar note, uchar pressure, bigtime_t time)
 Invoked when a Polyphonic Pressure (Aftertouch) event is received.
bigtime_t Latency () const
 Returns the latency of this consumer.
const char * Name () const
 Returns the name of the endpoint.
virtual void NoteOff (uchar channel, uchar note, uchar velocity, bigtime_t time)
 Invoked when a Note Off event is received.
virtual void NoteOn (uchar channel, uchar note, uchar velocity, bigtime_t time)
 Invoked when a Note On event is received.
virtual void PitchBend (uchar channel, uchar lsb, uchar msb, bigtime_t time)
 Invoked when a Pitch Bend event is received.
virtual void ProgramChange (uchar channel, uchar programNumber, bigtime_t time)
 Invoked when a Program Change event is received.
status_t Register ()
 Publishes the endpoint on the roster.
status_t Release ()
 Decrements the endpoint's reference count.
void SetLatency (bigtime_t latency)
 Changes the published latency of the consumer.
void SetName (const char *name)
 Changes the name of the endpoint.
status_t SetProperties (const BMessage *properties)
 Changes the properties of the endpoint.
void SetTimeout (bigtime_t when, void *data)
 Requests that the Timeout() hook will be called at some point.
virtual void SystemCommon (uchar status, uchar data1, uchar data2, bigtime_t time)
 Invoked when a System Common event is received.
virtual void SystemExclusive (void *data, size_t length, bigtime_t time)
 Invoked when a System Exclusive event is received.
virtual void SystemRealTime (uchar status, bigtime_t time)
 Invoked when a Real Time event is received.
virtual void TempoChange (int32 beatsPerMinute, bigtime_t time)
 Invoked when a Tempo Change event is received.
virtual void Timeout (void *data)
 Hook function that is called per your own request.
status_t Unregister ()
 Hides the endpoint from the roster/.

Detailed Description

A consumer endpoint that is created by your own application.

If you want to create a consumer that reacts to MIDI events, you should subclass BMidiLocalConsumer.

Each local consumer has its own thread that receives and dispatches the MIDI events. Whenever MIDI data arrives, the Data() hook passes the MIDI event on to a more specific hook function: NoteOn(), NoteOff(), SystemExclusive(), and so on. Calls to these hook functions are serialized -- they will never have to be re-entrant. They also should not be called from outside the thread that is invoking them.

Your subclass can override any of the MIDI event hooks. BMidiLocalConsumer doesn't provide default implementations for them, so you don't have to call a hook's default implementation if you override it. For complete control, you can also override Data().

Most hook functions take a channel argument. Even though MIDI channels are really numbered 1 through 16, the hook functions work with channels 0 through 15. The performance time for the event is specified in microseconds relative to the system time base. A performance time that is 0 (or really any time in the past) means "play as soon as possible". See the introduction for more information about timing and consumers.

The thread driving the consumer's events is a very high priority real time thread. Events should be handled as quickly as possible (not counting snoozing). If non-time-critical computation is needed it may be wise to queue events up for a lower priority thread to handle them external to the main event thread.


Constructor & Destructor Documentation

BMidiLocalConsumer::BMidiLocalConsumer ( const char *  name = NULL)

Creates a new local consumer endpoint.

The new endpoint is not visible to other applications until you Register() it.

You can tell the constructor what the name of the new consumer will be. If you pass NULL (or use the default argument), then the consumer's name will be an empty string. It won't be NULL, since endpoint names cannot be NULL.

There is no guarantee that the endpoint will be successfully created. For example, the Midi Server may not be running. Therefore, you should always call IsValid() after creating a new endpoint to make sure that everything went okay. If not, Release() the object to reclaim memory and abort gracefully.

MyConsumer* cons = new MyConsumer(...);
if (!cons->IsValid())
{
    cons->Release();
    ...exit gracefully...
}

Member Function Documentation

status_t BMidiEndpoint::Acquire ( ) [inherited]

Increments the endpoint's reference count.

Each BMidiEndpoint has a reference count associated with it, so that BMidiRoster can do proper bookkeeping. Acquire() increments this reference count, and Release() decrements it. Once the count reaches zero, the endpoint is deleted.

When you are done with the endpoint, whether local or remote, you should always Release() it!

Upon construction, local endpoints start with a reference count of 1. Any objects you obtain from BMidiRoster using the NextXXX() or FindXXX() functions have their reference counts incremented in the process. If you forget to call Release(), the objects won't be properly cleaned up and you'll make a fool out of yourself.

After you Release() an object, you are advised not to use it any further. If you do, your app will probably crash. That also happens if you Release() an object too many times.

Typically, you don't need to call Acquire(), unless you have two disparate parts of your application working with the same endpoint, and you don't want to have to keep track of who needs to Release() the endpoint. Now you simply have both of them release it.

Returns:
Always returns B_OK
See also:
Release()
void BMidiLocalConsumer::ChannelPressure ( uchar  channel,
uchar  pressure,
bigtime_t  time 
) [virtual]

Invoked when a Channel Pressure event is received.

See also:
BMidiLocalProducer::SprayChannelPressure()
void BMidiLocalConsumer::ControlChange ( uchar  channel,
uchar  controlNumber,
uchar  controlValue,
bigtime_t  time 
) [virtual]

Invoked when a Controller Change event is received.

See also:
BMidiLocalProducer::SprayControlChange()
void BMidiLocalConsumer::Data ( uchar *  data,
size_t  length,
bool  atomic,
bigtime_t  time 
) [virtual]

Invoked when raw MIDI is received.

What the default implementation of Data() does depends on the value of atomic. If atomic is true, the data received comprises a single MIDI event; i.e. one status byte followed by the appropriate number of data bytes and nothing else. In this case, Data() calls the event-specific hook function that corresponds to that status byte. This optimization is used by the Midi Kit to allow faster dispatch of events generated by the specific Spray functions from BMidiLocalProducer.

If atomic is false, Data() ignores the MIDI event. If you want a consumer to handle non-atomic events, you have to override Data() and program this yourself. In that case, you probably also want to call the default implementation to handle the "normal" MIDI events.

Data() is rarely overridden, but you can override it if you want to. If you do, remember that the data buffer is owned by the Midi Kit. Do not attempt to modify or free it, lest you wish to be laughed at by other developers.

Parameters:
datathe MIDI event data
lengthbyte size of the data buffer
atomicwhether the data buffer contains a single complete MIDI event
timethe requested performance time of the event
See also:
BMidiLocalProducer::SprayData()
int32 BMidiLocalConsumer::GetProducerID ( )

Returns the ID of the producer that most recently sent a MIDI event to this consumer.

You can call this from one of the hooks to determine which producer the event came from.

status_t BMidiEndpoint::GetProperties ( BMessage props) const [inherited]

Reads the properties of the endpoint.

Usage example:

BMessage props;
if (endpoint->GetProperties(&props) == B_OK) 
{
    ...examine the contents of the message...
}

Note that GetProperties() overwrites the contents of your BMessage.

See also:
SetProperties()
int32 BMidiEndpoint::ID ( ) const [inherited]

Returns the ID of the endpoint.

An ID uniquely identifies an endpoint in the system. The ID is a signed 32-bit number that is assigned by the Midi Server when the endpoint is created. (So even if a local endpoint is not published, it still has a unique ID.) Valid IDs range from 1 to 0x7FFFFFFF, the largest value an int32 can have. 0 and negative values are not valid IDs.

bool BMidiEndpoint::IsConsumer ( ) const [inherited]

Determines whether this endpoint is a BMidiConsumer.

If it is, you can use a dynamic_cast to convert this object into a consumer:

if (endp->IsConsumer())
{
    BMidiConsumer* cons = dynamic_cast<BMidiConsumer*>(endp);

    ....

}
bool BMidiEndpoint::IsLocal ( ) const [inherited]

Determines whether this endpoint represents a local object.

An endpoint is "local" when it is created by this application; in other words, a BMidiLocalConsumer or BMidiLocalProducer.

bool BMidiEndpoint::IsPersistent ( ) const [inherited]

Not used.

The purpose of this function is unclear, and as a result it doesn't do anything in the Haiku Midi Kit implementation.

Returns:
false always.
bool BMidiEndpoint::IsProducer ( ) const [inherited]

Determines whether this endpoint is a BMidiProducer.

If it is, you can use a dynamic_cast to convert this object into a producer:

if (endp->IsProducer())
{
    BMidiProducer* prod = dynamic_cast<BMidiProducer*>(endp);

    ....

}
bool BMidiEndpoint::IsRemote ( ) const [inherited]

Determines whether this endpoint is a proxy for a remote object.

An endpoint is "remote" when it is created by another application. Obviously, the remote object is Register()'ed as well, otherwise you would not be able to see it.

bool BMidiEndpoint::IsValid ( ) const [inherited]

Determines whether the endpoint still exists.

Suppose you obtained a proxy object for a remote endpoint by querying the BMidiRoster. What if the application that published this endpoint quits, or less drastically, Unregister()'s that endpoint? Even though you still have a BMidiEndpoint proxy object, the real endpoint no longer exists. You can use IsValid() to check for this.

Don't worry, operations on invalid objects, such as GetProperties(), will return an error code (typically B_ERROR), but not cause a crash. Local objects are always are considered to be valid, even if you did not Register() them. (The only time a local endpoint is not valid is when there was a problem constructing it.)

If the application that created the remote endpoint crashes, then there is no guarantee that the Midi Server immediately recognizes this. In that case, IsValid() may still return true. Eventually, the stale endpoint will be removed from the roster, though. From then on, IsValid() correctly returns false.

void BMidiLocalConsumer::KeyPressure ( uchar  channel,
uchar  note,
uchar  pressure,
bigtime_t  time 
) [virtual]

Invoked when a Polyphonic Pressure (Aftertouch) event is received.

See also:
BMidiLocalProducer::SprayKeyPressure()
bigtime_t BMidiConsumer::Latency ( ) const [inherited]

Returns the latency of this consumer.

The latency is measured in microseconds. Producers should attempt to get MIDI events to this consumer by (when - latency). You do this by subtracting the latency from the performance time when you spray the events (provided that you spray these events ahead of time, of course).

You cannot set the latency on a BMidiConsumer, only on a BMidiLocalConsumer.

The latency issue gets slightly more complicated when multiple endpoints are chained together, as in the following picture:

+-------+     +-------------+     +-------+
|       |     |             |     |       |
| prodA |---->| consB prodB |---->| consC |
|       |     |             |     |       |
+-------+     +-------------+     +-------+
  appA          appB (filter)       appC

Suppose consC has 200ms latency, and consB has 100ms latency. If consB simply reports 100ms, then prodA will schedule its events for (t - 100), which is really 200ms too late. (Of course, producers send out their events as soon as possible, so depending on the load of the system, everything may work out just fine.)

ConsB should report the latency of the consumer that is hooked up to its output, consC, in addition to its own latency. In other words, the full downstream latency. So, the reported latency in this case would be 300ms. This also means that appB should change the latency of consB when prodB makes or breaks a connection, and when consC reports a latency change. (If multiple consumers are connected to prodB, you should take the slowest one.) Unfortunately, the Midi Kit provides no easy mechanism for doing any of this, so you are on your own here.

const char * BMidiEndpoint::Name ( ) const [inherited]

Returns the name of the endpoint.

The function never returns NULL. If you created a local endpoint by passing a NULL name into its constructor (or passing no name, which is the same thing), then Name() will return an empty string, not NULL.

See also:
SetName()
void BMidiLocalConsumer::NoteOff ( uchar  channel,
uchar  note,
uchar  velocity,
bigtime_t  time 
) [virtual]

Invoked when a Note Off event is received.

See also:
BMidiLocalProducer::SprayNoteOff()
void BMidiLocalConsumer::NoteOn ( uchar  channel,
uchar  note,
uchar  velocity,
bigtime_t  time 
) [virtual]

Invoked when a Note On event is received.

See also:
BMidiLocalProducer::SprayNoteOn()
void BMidiLocalConsumer::PitchBend ( uchar  channel,
uchar  lsb,
uchar  msb,
bigtime_t  time 
) [virtual]

Invoked when a Pitch Bend event is received.

See also:
BMidiLocalProducer::SprayPitchBend()
void BMidiLocalConsumer::ProgramChange ( uchar  channel,
uchar  programNumber,
bigtime_t  time 
) [virtual]

Invoked when a Program Change event is received.

See also:
BMidiLocalProducer::SprayProgramChange()
status_t BMidiEndpoint::Register ( ) [inherited]

Publishes the endpoint on the roster.

MIDI objects created by an application are invisible to other applications until they are published. To publish an object use the Register() method. The corresponding Unregister() method will cause an object to once again become invisible to remote applications.

BMidiRoster also has Register() and Unregister() methods. You may also use those methods to publish or hide your endpoints; both do the same thing.

Although it is considered bad style, calling Register() on local endpoints that are already registered won't mess things up. The Midi Server will simply ignore your request. Likewise for Unregister()'ing more than once. Attempts to Register() or Unregister() remote endpoints will fail, of course.

If you are watching , you will not receive notifications for any local endpoints you register or unregister. Of course, other applications will be notified about your endpoints.

Existing connections will not be broken when an object is unregistered, but future remote connections will be denied. When objects are destroyed, they automatically become unregistered.

Returns:
B_OK on success, or an error code (typically B_ERROR) if something went wrong.
See also:
Unregister()
status_t BMidiEndpoint::Release ( ) [inherited]

Decrements the endpoint's reference count.

Returns:
Always returns B_OK
See also:
Acquire()
void BMidiLocalConsumer::SetLatency ( bigtime_t  latency)

Changes the published latency of the consumer.

See also:
Latency()
void BMidiEndpoint::SetName ( const char *  name) [inherited]

Changes the name of the endpoint.

Names don't have to be unique, but it is recommended that you give any endpoints you publish meaningful and unique names, so users can easily recognize what each endpoint does. There is no limit to the size of endpoint names.

Even though you can call this function on both remote and local objects, you are only allowed to change the names of local endpoints; SetName() calls on remote endpoints are ignored.

Parameters:
nameThe new name. If you pass NULL the name won't be changed.
See also:
Name()
status_t BMidiEndpoint::SetProperties ( const BMessage props) [inherited]

Changes the properties of the endpoint.

Endpoints can have properties, which is any kind of information that might be useful to associate with a MIDI object. The properties are stored in a BMessage.

Usage example:

BMessage props;
if (endpoint->GetProperties(&props) == B_OK)
{
    ...add data to the message...
    endpoint->SetProperties(&props);
} 

You are only allowed to call SetProperties() on a local object.

Properties should follow a protocol, so different applications will know how to read each other's properties. The current protocol is very limited -- it only allows you to associate icons with your endpoints. Be planned to publish a more complete protocol that included additional information, such as vendor/model names, copyright/version info, category, etc., but they never got around to it.

propertyVector icon (raw data)
field name"icon"
field type'VICN'

This vector icon is available under Haiku only, and comes as raw data, not a BBitmap. Before being able to display it, you first must render the vector icon in the size of your choice.

propertyLarge (32x32) icon
field name"be:large_icon"
field type'ICON'
propertySmall (16x16) icon
field name"be:mini_icon"
field type'MICN'

The MidiUtil package (downloadable from the OpenBeOS website) contains a number of convenient functions to associate icons with endpoints, so you don't have to write that code all over again.

See also:
GetProperties()
void BMidiLocalConsumer::SetTimeout ( bigtime_t  when,
void *  data 
)

Requests that the Timeout() hook will be called at some point.

This method asks the consumer thread to call the Timeout() hook as soon as possible after the timeout expires. For every call to SetTimeout(), the Timeout() hook is only called once. Note: the term "timeout" may be a little misleading; the hook will always be called, even if events are received in the mean time. Apparently, this facility is handy for dealing with early events.

Note that the event thread blocks on the consumer's port as long as no events arrive. By default no timeout is set, and as a result the thread blocks forever. Your call to SetTimeout() doesn't change this. The new timeout value will go into effect the next time the thread tries to read from the port, i.e. after the first event has been received. If no event ever comes in, the Timeout() hook will never be called. This also means that you cannot cancel a timeout once you have set it. To repeat, calling SetTimeout() only takes effect after at least one new event has been received.

Parameters:
whenAn absolute time that's measured against the system clock.
dataA pointer to a "cookie" that you can pass along to Timeout(). The data is not copied, so you must ensure that the pointer remains valid until Timeout() is called. You typically delete the data inside Timeout().
void BMidiLocalConsumer::SystemCommon ( uchar  status,
uchar  data1,
uchar  data2,
bigtime_t  time 
) [virtual]

Invoked when a System Common event is received.

Not all data bytes are used for all common events. Unused bytes are set to 0.

See also:
BMidiLocalProducer::SpraySystemCommon()
void BMidiLocalConsumer::SystemExclusive ( void *  data,
size_t  length,
bigtime_t  time 
) [virtual]

Invoked when a System Exclusive event is received.

The data does not include the sysex start and end control bytes (0xF0 and 0xF7), only the payload of the sysex message.

The data belongs to the Midi Kit and is only valid for the duration of this event. You may not modify or free it.

See also:
BMidiLocalProducer::SpraySystemExclusive()
void BMidiLocalConsumer::SystemRealTime ( uchar  status,
bigtime_t  time 
) [virtual]

Invoked when a Real Time event is received.

See also:
BMidiLocalProducer::SpraySystemRealTime()
void BMidiLocalConsumer::TempoChange ( int32  beatsPerMinute,
bigtime_t  time 
) [virtual]

Invoked when a Tempo Change event is received.

See also:
BMidiLocalProducer::SprayTempoChange()
void BMidiLocalConsumer::Timeout ( void *  data) [virtual]

Hook function that is called per your own request.

See also:
SetTimeout()
status_t BMidiEndpoint::Unregister ( ) [inherited]

Hides the endpoint from the roster/.

See also:
Register()

The Haiku Book pre-R1 - BMidiLocalConsumer Class Reference
Generated on Thu May 23 2013 by Doxygen 1.7.5.1