diff --git a/docs/user/Doxyfile b/docs/user/Doxyfile
index 7c55890d27..5bbe1bc535 100644
--- a/docs/user/Doxyfile
+++ b/docs/user/Doxyfile
@@ -325,8 +325,8 @@ WARN_LOGFILE =
# with spaces.
# General documentations and extern documentation files
-INPUT = . support ppp
-INPUT += ../../headers/os/support ../../headers/posix
+INPUT = . midi midi2 support ppp
+INPUT += ../../headers/os/midi2 ../../headers/os/support ../../headers/posix
# ToDo: we should probably make it recursive once we have docs for everything...
# PPP
@@ -389,7 +389,7 @@ EXAMPLE_RECURSIVE = NO
# directories that contain image that are included in the documentation (see
# the \image command).
-IMAGE_PATH = .
+IMAGE_PATH = . midi2
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
diff --git a/docs/user/midi/midi1intro.dox b/docs/user/midi/midi1intro.dox
new file mode 100644
index 0000000000..1719629ffb
--- /dev/null
+++ b/docs/user/midi/midi1intro.dox
@@ -0,0 +1,48 @@
+/*!
+\page midi1 The old Midi Kit (libmidi.so)
+
+The old Midi Kit, or midi1 for short, goes all the way back to DR8, when the
+BeOS only ran on BeBoxen. Fortunately for us, it is pretty well documented:
+
+- Midi
+Kit chapter in the online Be Book
+- Midi
+Kit section of the old Be Developer Library
+- Be Newsletter Volume 1, Issue 49 - Introduces the MIDI synth
+- Be Newsletter Volume 1, Issue 52 - Follow-up on issue 49
+- Be Newsletter Volume 1, Issue 91 - How to use BSynth
+- Be Newsletter Volume 1, Issue 102 - Axe sample code
+- Be Newsletter Volume 1, Issue 104 - How to use BMidiPort
+- Be Newsletter Volume 2, Issue 23 - EdMidi sample code
+- Be Newsletter Volume 2, Issue 37 - How to use the MIDI synth
+- Be Newsletter Volume 3, Issue 37 - Whistle sample code
+
+To summarize, there are four basic MIDI classes:
+
+- BMidi is the base class for most other classes from the Midi Kit
+- BMidiPort can talk to a MIDI hardware port
+- BMidiStore can read, write, and perform Standard MIDI files
+- BMidiText is a debugging aid that dumps MIDI messages to stdout
+
+The following classes let you use the Midi Kit's General MIDI synthesizer:
+
+- BSynth controls the synthesizer
+- BMidiSynth connects a BMidi object to the synth
+- BMidiSynthFile connects a MIDI file to the synth
+- BSamples lets you access the synth's sound data stream
+
+To make MIDI data stream through your application, you create a "network" of
+BMidi-derived objects that send and receive MIDI messages.
+
+The old Midi Kit is slowly fading into obscurity. You may want to use the
+\ref midi2 "new kit" instead. Also note that the OpenBeOS implementation
+of the kit sometimes behaves differently than the one from BeOS R5 or what
+the BeBook says, but usually for the better ;-)
+
+Especially the synth classes are not completely functional, but enough to
+play back General MIDI tunes. They should be backwards compatible with the
+majority of BeOS MIDI applications. Not all methods of BSynth, BMidiSynth,
+and BMidiSynthFile are implemented because some of them are rather obscure.
+BSamples is a complete no-op; in other words, with the OpenBeOS Midi Kit
+you cannot push waveform data into the output stream of the softsynth.
+*/
diff --git a/docs/user/midi2/midi2concepts.png b/docs/user/midi2/midi2concepts.png
new file mode 100644
index 0000000000..2278a4d53b
Binary files /dev/null and b/docs/user/midi2/midi2concepts.png differ
diff --git a/docs/user/midi2/midi2intro.dox b/docs/user/midi2/midi2intro.dox
new file mode 100644
index 0000000000..5ba88c7654
--- /dev/null
+++ b/docs/user/midi2/midi2intro.dox
@@ -0,0 +1,303 @@
+/*!
+\page midi2 The new Midi Kit (libmidi2.so)
+
+The Midi Kit is the API that implements support for generating, processing, and
+playing music in MIDI format. MIDI, which
+stands for 'Musical Instrument Digital Interface', is a well-established
+standard for representing and communicating musical data.
+
+\section midi2twokits The two kits
+
+The BeOS comes with two different, but compatible Midi Kits. This documentation
+focuses on the "new" Midi Kit, or midi2 as we like to call it, that was
+introduced with BeOS R5. The old kit, which we'll refer to as midi1, is more
+complete than the new kit, but less powerful.
+
+Both kits let you create so-called MIDI endpoints, but the endpoints from midi1
+cannot be shared between different applications. The midi2 kit solves that
+problem, but unlike midi1 it does not include a General MIDI softsynth, nor
+does it have a facility for reading and playing Standard MIDI Files. Don't
+worry: both kits are compatible and you can mix-and-match them in your
+applications.
+
+The main differences between the two kits:
+
+- Instead of one BMidi object that both produces and consumes events, we have
+BMidiProducer and BMidiConsumer.
+- Applications are capable of sharing MIDI producers and consumers with other
+applications via the centralized Midi Roster.
+- Physical MIDI ports are now sharable without apps "stealing" events from each
+other.
+- Applications can now send/receive raw MIDI byte streams (useful if an
+application has its own MIDI parser/engine).
+- Channels are numbered 0..15, not 1..16
+- Timing is now specified in microseconds instead of milliseconds.
+
+\section midi2concepts Midi Kit concepts
+
+A brief overview of the elements that comprise the Midi Kit:
+
+- \b Endpoints. This is what the Midi Kit is all about: sending MIDI messages
+between endpoints. An endpoint is like a MIDI In or MIDI Out socket on your
+equipment; it either receives information or it sends information. Endpoints
+that send MIDI events are called \b producers; the endpoints that receive those
+events are called \b consumers. An endpoint that is created by your own
+application is called \b local; endpoints from other applications are \b
+remote. You can access remote endpoints using \b proxies.
+
+- \b Filters. A filter is an object that has a consumer and a producer
+endpoint. It reads incoming events from its consumer, performs some operation,
+and tells its producer to send out the results. In its current form, the Midi
+Kit doesn't provide any special facilities for writing filters.
+
+- \b Midi \b Roster. The roster is the list of all published producers and
+consumers. By publishing an endpoint, you allow other applications to talk to
+it. You are not required to publish your endpoints, in which case only your own
+application can use them.
+
+- \b Midi \b Server. The Midi Server does the behind-the-scenes work. It
+manages the roster, it connects endpoints, it makes sure that endpoints can
+communicate, and so on. The Midi Server is started automatically when BeOS
+boots, and you never have to deal with it directly. Just remember that it runs
+the show.
+
+- \b libmidi. The BMidi* classes live inside two shared libraries: libmidi.so
+and libmidi2.so. If you write an application that uses old Midi Kit, you must
+link it to libmidi.so. Applications that use the new Midi Kit must link to
+libmidi2.so. If you want to mix-and-match both kits, you should also link to
+both libraries.
+
+Here is a pretty picture:
+
+\image html midi2concepts.png
+
+\section midi2mediakit Midi Kit != Media Kit
+
+Be chose not to integrate the Midi Kit into the Media Kit as another media
+type, mainly because MIDI doesn't require any of the format negotiation that
+other media types need. Although the two kits look similar -- both have a
+"roster" for finding or registering "consumers" and "producers" -- there are
+some very important differences.
+
+The first and most important point to note is that BMidiConsumer and
+BMidiProducer in the Midi Kit are NOT directly analogous to BBufferConsumer and
+BBufferProducer in the Media Kit! In the Media Kit, consumers and producers are
+the data consuming and producing properties of a media node. A filter in the
+Media Kit, therefore, inherits from both BBufferConsumer and BBufferProducer,
+and implements their virtual member functions to do its work.
+
+In the Midi Kit, consumers and producers act as endpoints of MIDI data
+connections, much as media_source and media_destination do in the Media Kit.
+Thus, a MIDI filter does not derive from BMidiConsumer and BMidiProducer;
+instead, it contains BMidiConsumer and BMidiProducer objects for each of its
+distinct endpoints that connect to other MIDI objects. The Midi Kit does not
+allow the use of multiple virtual inheritance, so you can't create an object
+that's both a BMidiConsumer and a BMidiProducer.
+
+This also contrasts with the old Midi Kit's conception of a BMidi object, which
+stood for an object that both received and sent MIDI data. In the new Midi Kit,
+the endpoints of MIDI connections are all that matters. What lies between the
+endpoints, i.e., how a MIDI filter is actually structured, is entirely at your
+discretion.
+
+Also, rather than use token structs like media_node to make connections via the
+MediaRoster, the new kit makes the connections directly via the BMidiProducer
+object.
+
+\section midi2remotelocal Remote and local objects
+
+The Midi Kit makes a distinction between remote and local MIDI objects. You can
+only create local MIDI endpoints, which derive from either BMidiLocalConsumer
+or BMidiLocalProducer. Remote endpoints are endpoints that live in other
+applications, and you access them through BMidiRoster.
+
+BMidiRoster only gives you access to BMidiEndpoints, BMidiConsumers, and
+BMidiProducers. When you want to talk to remote MIDI objects, you do so through
+the proxy objects that BMidiRoster provides. Unlike BMidiLocalConsumer and
+BMidiLocalProducer, these classes do not provide a lot of functions. That is
+intentional. In order to hide the details of communication with MIDI endpoints
+in other applications, the Midi Kit must hide the details of how a particular
+endpoint is implemented.
+
+So, what can you do with remote objects? Only what BMidiConsumer,
+BMidiProducer, and BMidiEndpoint will let you do. You can connect objects, get
+the properties of these objects -- and that's about it.
+
+\section midi2lifespan Creating and destroying objects
+
+The constructors and destructors of most midi2 classes are private, which mean
+you cannot directly create them using the C++ new operator, on the
+stack, or as globals. Nor can you delete them. Instead, these
+objects are obtained through BMidiRoster. The only two exceptions to this rule
+are BMidiLocalConsumer and BMidiLocalProducer. These two objects may be
+directly created and subclassed by developers.
+
+\section midi2refcount Reference counting
+
+Each MIDI endpoint has a reference count associated with it, so that the Midi
+Roster can do proper bookkeeping. When you construct a BMidiLocalProducer or
+BMidiLocalConsumer endpoint, it starts with a reference count of 1. In
+addition, BMidiRoster increments the reference count of any object it hands to
+you as a result of \link BMidiRoster::NextEndpoint() NextEndpoint() \endlink or
+\link BMidiRoster::FindEndpoint() FindEndpoint() \endlink. Once the count hits
+0, the endpoint will be deleted.
+
+This means that, to delete an endpoint, you don't call the delete
+operator directly; instead, you call \link BMidiEndpoint::Release() Release()
+\endlink. To balance this call, there's also an \link BMidiEndpoint::Acquire()
+Acquire() \endlink, in case you have two disparate parts of your application
+working with the endpoint, and you don't want to have to keep track of who
+needs to Release() the endpoint.
+
+When you're done with any endpoint object, you must Release() it. This is true
+for both local and remote objects. Repeat after me: Release() when you're done.
+
+\section midi2events MIDI events
+
+To make some actual music, you need to \link BMidiProducer::Connect() Connect()
+\endlink your consumers to your producers. Then you tell the producer to
+"spray" MIDI events to all the connected consumers. The consumers are notified
+of these incoming events through a set of hook functions.
+
+The Midi Kit already provides a set of commonly used spray functions, such as
+\link BMidiLocalProducer::SprayNoteOn() SprayNoteOn() \endlink, \link
+BMidiLocalProducer::SprayControlChange() SprayControlChange() \endlink, and so
+on. These correspond one-to-one with the message types from the MIDI spec. You
+don't need to be a MIDI expert to use the kit, but of course some knowledge of
+the protocol helps. If you are really hardcore, you can also use the \link
+BMidiLocalProducer::SprayData() SprayData() \endlink to send raw MIDI events to
+the consumers.
+
+At the consumer side, a dedicated thread invokes a hook function for every
+incoming MIDI event. For every spray function, there is a corresponding hook
+function, e.g. \link BMidiLocalConsumer::NoteOn() NoteOn() \endlink and \link
+BMidiLocalConsumer::ControlChange() ControlChange() \endlink. The hardcore MIDI
+fanatics among you will be pleased to know that you can also tap into the \link
+BMidiLocalConsumer::Data() Data() \endlink hook and get your hands dirty with
+the raw MIDI data.
+
+\section midi2time Time
+
+The spray and hook functions accept a bigtime_t parameter named "time". This
+indicates when the MIDI event should be performed. The time is given in
+microseconds since the computer booted. To get the current tick measurement,
+you call the system_time() function from the Kernel Kit.
+
+If you override a hook function in one of your consumer objects, it should look
+at the time argument, wait until the designated time, and then perform its
+action. The preferred method is to use the Kernel Kit's
+snooze_until() function, which sends the consumer thread to sleep
+until the requested time has come. (Or, if the time has already passed, returns
+immediately.)
+
+Like this:
+
+\code
+void MyConsumer::NoteOn(
+ uchar channel, uchar note, uchar velocity, bigtime_t time)
+{
+ snooze_until(time, B_SYSTEM_TIMEBASE);
+ ...do your thing...
+}
+\endcode
+
+If you want your producers to run in real time, i.e. they produce MIDI data
+that needs to be performed immediately, you should pass time 0 to the spray
+functions (which also happens to be the default value). Since time 0 has
+already passed, snooze_until() returns immediately, and the
+consumer will process the events as soon as they are received.
+
+To schedule MIDI events for a performance time that lies somewhere in the
+future, the producer must take into account the consumer's latency. Producers
+should attempt to get notes to the consumer by or before
+(scheduled_performance_time - latency). The time argument is still the
+scheduled performance time, so if your consumer has latency, it should snooze
+like this before it starts to perform the events:
+
+\code
+snooze_until(time - Latency(), B_SYSTEM_TIMEBASE);
+\endcode
+
+Note that a typical producer sends out its events as soon as it can; unlike a
+consumer, it does not have to snooze.
+
+\section midi2ports Other timing issues
+
+Each consumer object uses a Kernel Kit port to receive MIDI events from
+connected producers. The queue for this port is only 1 message deep. This means
+that if the consumer thread is asleep in a snooze_until(), it will
+not read its port. Consequently, any producer that tries to write a new event
+to this port will block until the consumer thread is ready to receive a new
+message. This is intentional, because it prevents producers from generating and
+queueing up thousands of events.
+
+This mechanism, while simple, puts on the producer the responsibility for
+sorting the events in time. Suppose your producer sends three Note On events,
+the first on t + 0, the second on t + 4, and the third on t + 2. This last
+event won't be received until after t + 4, so it will be two ticks too late. If
+this sort of thing can happen with your producer, you should somehow sort the
+events before you spray them. Of course, if you have two or more producers
+connected to the same consumer, it is nearly impossible to sort this all out
+(pardon the pun). So it is not wise to send the same kinds of events from more
+than one producer to one consumer at the same time.
+
+The article Introduction to MIDI, Part 2 in OpenBeOS
+Newsletter 36 describes this problem in more detail, and provides a
+solution. Go read it now!
+
+\section midi2filters Writing a filter
+
+A typical filter contains a consumer and a producer endpoint. It receives
+events from the consumer, processes them, and sends them out again using the
+producer. The consumer endpoint is a subclass of BMidiLocalConsumer, whereas
+the producer is simply a BMidiLocalProducer, not a subclass. This is a common
+configuration, because consumers work by overriding the event hooks to do work
+when MIDI data arrives. Producers work by sending an event when you call their
+member functions. You should hardly ever need to derive from BMidiLocalProducer
+(unless you need to know when the producer gets connected or disconnected,
+perhaps), but you'll always have to override one or more of
+BMidiLocalConsumer's member functions to do something useful with incoming
+data.
+
+Filters should ignore the time argument from the spray and hook functions, and
+simply pass it on unchanged. Objects that only filter data should process the
+event as quickly as possible and be done with it. Do not
+snooze_until() in the consumer endpoint of a filter!
+
+\section midi2apidiffs API differences
+
+As far as the end user is concerned, the OpenBeOS Midi Kit is mostly the same
+as the BeOS R5 kits, although there are a few small differences in the API
+(mostly bug fixes):
+
+- BMidiEndpoint::IsPersistent() always returns false.
+- The B_MIDI_CHANGE_LATENCY notification is now properly sent. The Be kit
+ incorrectly set be:op to B_MIDI_CHANGED_NAME, even though the rest of the
+ message was properly structured.
+- If creating a local endpoint fails, you can still Release() the object
+ without crashing into the debugger.
+
+\section midi2seealso See also
+
+More about the Midi Kit:
+
+- \ref midi2defs
+- Be Newsletter Volume 3, Issue 47 - Motor Mix sample code
+- Be Newsletter Volume 4, Issue 3 - Overview of the new kit
+- OpenBeOS
+ Newsletter 33, Introduction to MIDI, Part 1
+- OpenBeOS
+ Newsletter 36, Introduction to MIDI, Part 2
+- Sample code and other goodies at the
+ OpenBeOS Midi Kit team page
+
+Information about MIDI in general:
+
+- MIDI Manufacturers Association
+- MIDI Tutorials
+- MIDI Specification
+- Standard MIDI File Format
+- Jim Menard's MIDI Reference
+
+*/
diff --git a/docs/user/midi2/midiconsumer.dox b/docs/user/midi2/midiconsumer.dox
new file mode 100644
index 0000000000..5083f5d64e
--- /dev/null
+++ b/docs/user/midi2/midiconsumer.dox
@@ -0,0 +1,54 @@
+/*!
+\class BMidiConsumer MidiConsumer.h
+\brief Receives MIDI events from a producer
+
+A consumer is an object that knows how to deal with incoming MIDI events. A
+consumer can be connected to multiple producers at the same time. There is no
+way to find out which producers are connected to this consumer just by looking
+at the BMidiConsumer object; you will have to consult BMidiRoster for that.
+
+A BMidiConsumer either represents a local consumer, i.e. a class extending from
+BMidiLocalConsumer, or is a proxy for a remote object published by another app.
+
+*/
+
+/*!
+\fn bigtime_t BMidiConsumer::Latency() const
+\brief 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:
+
+\verbatim
++-------+ +-------------+ +-------+
+| | | | | |
+| prodA |---->| consB prodB |---->| consC |
+| | | | | |
++-------+ +-------------+ +-------+
+ appA appB (filter) appC
+\endverbatim
+
+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.
+
+*/
diff --git a/docs/user/midi2/mididefs.dox b/docs/user/midi2/mididefs.dox
new file mode 100644
index 0000000000..0374ee59c6
--- /dev/null
+++ b/docs/user/midi2/mididefs.dox
@@ -0,0 +1,89 @@
+/*!
+\page midi2defs Midi Kit definitions (Midi2Defs.h)
+
+\section channelmasks Channel message masks
+
+
+| B_NOTE_OFF | 0x80 |
+| B_NOTE_ON | 0x90 |
+| B_KEY_PRESSURE | 0xa0 |
+| B_CONTROL_CHANGE | 0xb0 |
+| B_PROGRAM_CHANGE | 0xc0 |
+| B_CHANNEL_PRESSURE | 0xd0 |
+| B_PITCH_BEND | 0xe0 |
+
+
+\section systemmessages System messages
+
+
+| B_SYS_EX_START | 0xf0 |
+| B_MIDI_TIME_CODE | 0xf1 |
+| B_SONG_POSITION | 0xf2 |
+| B_SONG_SELECT | 0xf3 |
+| B_CABLE_MESSAGE | 0xf5 |
+| B_TUNE_REQUEST | 0xf6 |
+| B_SYS_EX_END | 0xf7 |
+| B_TIMING_CLOCK | 0xf8 |
+| B_START | 0xfa |
+| B_CONTINUE | 0xfb |
+| B_STOP | 0xfc |
+| B_ACTIVE_SENSING | 0xfe |
+| B_SYSTEM_RESET | 0xff |
+
+
+\section controllernumbers Controller numbers
+
+
+| B_MODULATION | 0x01 |
+| B_BREATH_CONTROLLER | 0x02 |
+| B_FOOT_CONTROLLER | 0x04 |
+| B_PORTAMENTO_TIME | 0x05 |
+| B_DATA_ENTRY | 0x06 |
+| B_MAIN_VOLUME | 0x07 |
+| B_MIDI_BALANCE | 0x08 |
+| B_PAN | 0x0a |
+| B_EXPRESSION_CTRL | 0x0b |
+| B_GENERAL_CTRL_1 | 0x10 |
+| B_GENERAL_CTRL_2 | 0x11 |
+| B_GENERAL_CTRL_3 | 0x12 |
+| B_GENERAL_CTRL_4 | 0x13 |
+| B_SUSTAIN_PEDAL | 0x40 |
+| B_PORTAMENTO | 0x41 |
+| B_SOSTENUTO | 0x42 |
+| B_SOFT_PEDAL | 0x43 |
+| B_HOLD_2 | 0x45 |
+| B_GENERAL_CTRL_5 | 0x50 |
+| B_GENERAL_CTRL_6 | 0x51 |
+| B_TEMPO_CHANGE | 0x51 |
+| B_GENERAL_CTRL_7 | 0x52 |
+| B_GENERAL_CTRL_8 | 0x53 |
+| B_EFFECTS_DEPTH | 0x5b |
+| B_TREMOLO_DEPTH | 0x5c |
+| B_CHORUS_DEPTH | 0x5d |
+| B_CELESTE_DEPTH | 0x5e |
+| B_PHASER_DEPTH | 0x5f |
+| B_DATA_INCREMENT | 0x60 |
+| B_DATA_DECREMENT | 0x61 |
+| B_RESET_ALL_CONTROLLERS | 0x79 |
+| B_LOCAL_CONTROL | 0x7a |
+| B_ALL_NOTES_OFF | 0x7b |
+| B_OMNI_MODE_OFF | 0x7c |
+| B_OMNI_MODE_ON | 0x7d |
+| B_MONO_MODE_ON | 0x7e |
+| B_POLY_MODE_ON | 0x7f |
+
+
+\section bmidiop BMidiOp
+
+
+| B_MIDI_NO_OP |
+| B_MIDI_REGISTERED |
+| B_MIDI_UNREGISTERED |
+| B_MIDI_CONNECTED |
+| B_MIDI_DISCONNECTED |
+| B_MIDI_CHANGED_NAME |
+| B_MIDI_CHANGED_LATENCY |
+| B_MIDI_CHANGED_PROPERTIES |
+
+
+*/
diff --git a/docs/user/midi2/midiendpoint.dox b/docs/user/midi2/midiendpoint.dox
new file mode 100644
index 0000000000..87bbb4e8de
--- /dev/null
+++ b/docs/user/midi2/midiendpoint.dox
@@ -0,0 +1,284 @@
+/*!
+\class BMidiEndpoint MidiEndpoint.h
+\brief Base class for all MIDI endpoints
+
+BMidiEndpoint is the abstract base class that represents either a producer or
+consumer endpoint. It may be used to obtain the state, name, properties, or
+system-wide ID of the object. BMidiEndpoint also provides the ability to change
+the name and properties of endpoints that were created locally.
+
+Remember, you cannot call the destructor of BMidiEndpoint and its subclasses
+directly. Endpoint objects are destructed automatically when their reference
+count drops to zero. If necessary, the destructor of a local endpoint first
+breaks off any connections and Unregister()'s the endpoint before it is
+deleted. However, for good style and bonus points you should really \link
+BMidiProducer::Disconnect() Disconnect() \endlink and Unregister() the object
+yourself and not rely on the destructor to do this.
+
+*/
+
+/*!
+\fn const char* BMidiEndpoint::Name() const
+\brief 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.
+
+\sa SetName()
+
+*/
+
+/*!
+\fn void BMidiEndpoint::SetName(const char* name)
+\brief 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.
+
+\param name The new name. If you pass NULL, the name simply won't be changed.
+
+\sa Name()
+
+*/
+
+/*!
+\fn int32 BMidiEndpoint::ID() const
+\brief 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.
+
+*/
+
+/*!
+\fn bool BMidiEndpoint::IsProducer() const
+\brief Determines whether this endpoint is a BMidiProducer
+
+If it is, you can use a dynamic_cast to convert this object into a producer:
+
+\code
+if (endp->IsProducer())
+{
+ BMidiProducer* prod = dynamic_cast(endp);
+ ....
+}
+\endcode
+*/
+
+/*!
+\fn bool BMidiEndpoint::IsConsumer() const
+\brief Determines whether this endpoint is a BMidiConsumer
+
+If it is, you can use a dynamic_cast to convert this object into a consumer:
+
+\code
+if (endp->IsConsumer())
+{
+ BMidiConsumer* cons = dynamic_cast(endp);
+ ....
+}
+\endcode
+*/
+
+/*!
+\fn bool BMidiEndpoint::IsRemote() const
+\brief 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.
+
+*/
+
+/*!
+\fn bool BMidiEndpoint::IsLocal() const
+\brief 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.
+
+*/
+
+/*!
+\fn bool BMidiEndpoint::IsPersistent() const
+\brief Not used
+
+The purpose of this function is unclear, and as a result it doesn't do anything
+in the OpenBeOS implementation of the Midi Kit.
+
+\return Always returns false.
+*/
+
+/*!
+\fn bool BMidiEndpoint::IsValid() const
+\brief 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.
+
+*/
+
+/*!
+\fn status_t BMidiEndpoint::Acquire()
+\brief 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.
+
+\return Always returns B_OK
+\sa Release()
+*/
+
+/*!
+\fn status_t BMidiEndpoint::Release()
+\brief Decrements the endpoint's reference count
+\return Always returns B_OK
+\sa Acquire()
+*/
+
+/*!
+\fn status_t BMidiEndpoint::Register()
+\brief 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 \link BMidiRoster::StartWatching() watching \endlink, 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.
+
+\return B_OK on success, or a negative error code (typically B_ERROR) if
+something went wrong.
+
+\sa Unregister()
+*/
+
+/*!
+\fn status_t BMidiEndpoint::Unregister()
+\brief Hides the endpoint from the roster
+\sa Register()
+*/
+
+/*!
+\fn status_t BMidiEndpoint::SetProperties(const BMessage* props)
+\brief 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:
+
+\code
+BMessage props;
+if (endpoint->GetProperties(&props) == B_OK)
+{
+ ...add data to the message...
+ endpoint->SetProperties(&props);
+}
+\endcode
+
+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.
+
+
+| property | Large (32x32) icon |
+| field name | "be:large_icon" |
+| field type | 'ICON' |
+
+
+
+| property | Small (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.
+
+\sa GetProperties()
+*/
+
+/*!
+\fn status_t BMidiEndpoint::GetProperties(BMessage* props) const
+\brief Reads the properties of the endpoint
+
+Usage example:
+
+\code
+BMessage props;
+if (endpoint->GetProperties(&props) == B_OK)
+{
+ ...examine the contents of the message...
+}
+\endcode
+
+Note that GetProperties() overwrites the contents of your BMessage.
+
+\sa SetProperties()
+*/
diff --git a/docs/user/midi2/midilocalcons.dox b/docs/user/midi2/midilocalcons.dox
new file mode 100644
index 0000000000..4a63a6b337
--- /dev/null
+++ b/docs/user/midi2/midilocalcons.dox
@@ -0,0 +1,230 @@
+/*!
+\class BMidiLocalConsumer MidiConsumer.h
+\brief 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 \ref midi2time "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.
+
+*/
+
+/*!
+\fn BMidiLocalConsumer::BMidiLocalConsumer(const char *name = NULL)
+\brief 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.
+
+\code
+MyConsumer* cons = new MyConsumer(...);
+if (!cons->IsValid())
+{
+ cons->Release();
+ ...exit gracefully...
+}
+\endcode
+
+*/
+
+/*!
+\fn void BMidiLocalConsumer::SetLatency(bigtime_t latency)
+\brief Changes the published latency of the consumer
+\sa Latency()
+*/
+
+/*!
+\fn int32 BMidiLocalConsumer::GetProducerID()
+\brief 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.
+
+*/
+
+/*!
+\fn void BMidiLocalConsumer::SetTimeout(bigtime_t when, void* data)
+\brief 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.
+
+\param when An absolute time that's measured against the system clock.
+
+\param data A 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().
+
+*/
+
+/*!
+\fn void BMidiLocalConsumer::Timeout(void* data)
+\brief Hook function that is called per your own request
+\sa SetTimeout()
+*/
+
+/*!
+\fn void BMidiLocalConsumer::Data(
+ uchar* data, size_t length, bool atomic, bigtime_t time)
+\brief 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.
+
+\param data the MIDI event data
+\param length byte size of the data buffer
+\param atomic whether the data buffer contains a single complete MIDI event
+\param time the requested performance time of the event
+
+\sa BMidiLocalProducer::SprayData()
+*/
+
+/*!
+\fn void BMidiLocalConsumer::NoteOff(
+ uchar channel, uchar note, uchar velocity, bigtime_t time)
+\brief Invoked when a Note Off event is received
+\sa BMidiLocalProducer::SprayNoteOff()
+*/
+
+/*!
+\fn void BMidiLocalConsumer::NoteOn(
+ uchar channel, uchar note, uchar velocity, bigtime_t time)
+\brief Invoked when a Note On event is received
+\sa BMidiLocalProducer::SprayNoteOn()
+*/
+
+/*!
+\fn void BMidiLocalConsumer::KeyPressure(
+ uchar channel, uchar note, uchar pressure, bigtime_t time)
+\brief Invoked when a Polyphonic Pressure (Aftertouch) event is received
+\sa BMidiLocalProducer::SprayKeyPressure()
+*/
+
+/*!
+\fn void BMidiLocalConsumer::ControlChange(
+ uchar channel, uchar controlNumber, uchar controlValue, bigtime_t time)
+\brief Invoked when a Controller Change event is received
+\sa BMidiLocalProducer::SprayControlChange()
+*/
+
+/*!
+\fn void BMidiLocalConsumer::ProgramChange(
+ uchar channel, uchar programNumber, bigtime_t time)
+\brief Invoked when a Program Change event is received
+\sa BMidiLocalProducer::SprayProgramChange()
+*/
+
+/*!
+\fn void BMidiLocalConsumer::ChannelPressure(
+ uchar channel, uchar pressure, bigtime_t time)
+\brief Invoked when a Channel Pressure event is received
+\sa BMidiLocalProducer::SprayChannelPressure()
+*/
+
+/*!
+\fn void BMidiLocalConsumer::PitchBend(
+ uchar channel, uchar lsb, uchar msb, bigtime_t time)
+\brief Invoked when a Pitch Bend event is received
+\sa BMidiLocalProducer::SprayPitchBend()
+*/
+
+/*!
+\fn void BMidiLocalConsumer::SystemExclusive(
+ void* data, size_t length, bigtime_t time)
+\brief 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.
+
+\sa BMidiLocalProducer::SpraySystemExclusive()
+*/
+
+/*!
+\fn void BMidiLocalConsumer::SystemCommon(
+ uchar status, uchar data1, uchar data2, bigtime_t time)
+\brief Invoked when a System Common event is received
+
+Not all data bytes are used for all common events. Unused bytes are set to 0.
+
+\sa BMidiLocalProducer::SpraySystemCommon()
+*/
+
+/*!
+\fn void BMidiLocalConsumer::SystemRealTime(
+ uchar status, bigtime_t time)
+\brief Invoked when a Real Time event is received
+\sa BMidiLocalProducer::SpraySystemRealTime()
+*/
+
+/*!
+\fn void BMidiLocalConsumer::TempoChange(int32 beatsPerMinute, bigtime_t time)
+\brief Invoked when a Tempo Change event is received
+\sa BMidiLocalProducer::SprayTempoChange()
+*/
+
+/*!
+\fn void BMidiLocalConsumer::AllNotesOff(bool justChannel, bigtime_t time)
+\brief Not used
+*/
diff --git a/docs/user/midi2/midilocalprod.dox b/docs/user/midi2/midilocalprod.dox
new file mode 100644
index 0000000000..a8063ae362
--- /dev/null
+++ b/docs/user/midi2/midilocalprod.dox
@@ -0,0 +1,226 @@
+/*!
+\class BMidiLocalProducer MidiProducer.h
+\brief A producer endpoint that is created by your own application
+
+You create a BMidiLocalProducer if you want your application to send MIDI
+events. You use the various spray functions to send events to all connected
+consumers. If no consumers are connected to the producer, any calls to the
+spray functions are ignored.
+
+Most spray functions accept a channel argument. Even though MIDI channels are
+really numbered 1 through 16, the spray functions work with channels 0 through
+15. You can also specify the performance time for the event using the time
+argument. Specify 0 (or any time in the past) to perform the event "now", i.e.
+as soon as possible. You can also schedule events to be performed in the
+future, by passing a time such as system_time() + 5000000, which means 5
+seconds from now.
+
+Unlike BMidiLocalConsumer, which should be subclassed almost always, you hardly
+ever need to derive a class from BMidiLocalProducer. The only reason for
+subclassing is when you need to know when the producer gets connected or
+disconnected.
+
+Also unlike consumers, local producers have no thread of control directly
+associated with them. If you want to send out the MIDI events from a different
+thread, you will have to create one yourself.
+
+*/
+
+/*!
+\fn BMidiLocalProducer::BMidiLocalProducer(const char *name = NULL)
+\brief Creates a new local producer 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 producer will be. If you
+pass NULL (or use the default argument), then the producer'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.
+
+\code
+BMidiLocalProducer* prod = new BMidiLocalProducer(...);
+if (!prod->IsValid())
+{
+ prod->Release();
+ ...exit gracefully...
+}
+\endcode
+
+*/
+
+/*!
+\fn void BMidiLocalProducer::Connected(BMidiConsumer* cons)
+\brief Invoked when a new consumer is connected to this producer
+
+Although typical notifications (i.e. from BMidiRoster's "watching" facility)
+are only sent if it is some other app that is performing the operation,
+Connected() is also called if you are making the connection yourself.
+
+If you override this hook, you don't have to call the default implementation,
+because that does nothing.
+
+\param cons The newly connected consumer. The reference count of the consumer
+object is not increased, so you should not Release() it. However, if you want
+to keep track of the consumer beyond this function, you should first Acquire()
+it, and Release() it when you are done.
+
+\sa Disconnected()
+*/
+
+/*!
+\fn void BMidiLocalProducer::Disconnected(BMidiConsumer* cons)
+\brief Invoked when a consumer is disconnected from this producer
+\sa Connected()
+*/
+
+/*!
+\fn void BMidiLocalProducer::SprayData(
+ void* data, size_t length, bool atomic = false, bigtime_t time = 0) const
+\brief Sends raw MIDI data downstream to all connected consumers
+
+Typically you won't have to call SprayData(); the other spray functions will do
+just fine. If you do call it, remember that you retain ownership of the data
+and that you are responsible for freeing it at some point. (Even though data is
+not declared const, the function does not change it.)
+
+With atomic set to false, you can send a MIDI message in segments (perhaps for
+a large sysex dump). However, when you do this, you are on your own. The Midi
+Kit only tags the data as being non-atomic, but offers no additional support.
+The default implementation of BMidiLocalConsumer completely ignores such
+events. To handle non-atomic MIDI data, you should override the
+BMidiLocalConsumer::Data() hook and process the MIDI event yourself. All of
+BMidiLocalProducer's other spray functions always send atomic data.
+
+\param data the MIDI event data
+\param length byte size of the data buffer
+\param atomic whether the data buffer contains a single complete MIDI event
+\param time the required performance time of the event
+
+\sa BMidiLocalConsumer::Data()
+*/
+
+/*!
+\fn void BMidiLocalProducer::SprayNoteOff(
+ uchar channel, uchar note, uchar velocity, bigtime_t time = 0) const
+\brief Sends a Note Off event to all connected consumers
+\sa BMidiLocalConsumer::NoteOff()
+*/
+
+/*!
+\fn void BMidiLocalProducer::SprayNoteOn(
+ uchar channel, uchar note, uchar velocity, bigtime_t time = 0) const
+\brief Sends a Note On event to all connected consumers
+\sa BMidiLocalConsumer::NoteOn()
+*/
+
+/*!
+\fn void BMidiLocalProducer::SprayKeyPressure(
+ uchar channel, uchar note, uchar pressure, bigtime_t time = 0) const
+\brief Sends a Polyphonic Pressure (Aftertouch) event to all connected
+consumers
+\sa BMidiLocalConsumer::KeyPressure()
+*/
+
+/*!
+\fn void BMidiLocalProducer::SprayControlChange(
+ uchar channel, uchar controlNumber, uchar controlValue,
+ bigtime_t time = 0) const
+\brief Sends a Controller Change event to all connected consumers
+
+\sa \ref controllernumbers
+\sa BMidiLocalConsumer::ControlChange()
+*/
+
+/*!
+\fn void BMidiLocalProducer::SprayProgramChange(
+ uchar channel, uchar programNumber, bigtime_t time = 0) const
+\brief Sends a Program Change event to all connected consumers
+\sa BMidiLocalConsumer::ProgramChange()
+*/
+
+/*!
+\fn void BMidiLocalProducer::SprayChannelPressure(
+ uchar channel, uchar pressure, bigtime_t time = 0) const
+\brief Sends a Channel Pressure event to all connected consumers
+\sa BMidiLocalConsumer::ChannelPressure()
+*/
+
+/*!
+\fn void BMidiLocalProducer::SprayPitchBend(
+ uchar channel, uchar lsb, uchar msb, bigtime_t time = 0) const
+\brief Sends a Pitch Bend event to all connected consumers
+\sa BMidiLocalConsumer::PitchBend()
+*/
+
+/*!
+\fn void BMidiLocalProducer::SpraySystemExclusive(
+ void* data, size_t length, bigtime_t time = 0) const
+\brief Sends a System Exclusive event to all connected consumers
+
+You retain ownership of the data and are responsible for freeing it. Even
+though data is not declared const, the function does not change it. Even though
+the amount of data may be quite large, this function always sends sysex
+messages as an atomic block of data.
+
+\sa BMidiLocalConsumer::SystemExclusive()
+*/
+
+/*!
+\fn void BMidiLocalProducer::SpraySystemCommon(
+ uchar status, uchar data1, uchar data2, bigtime_t time = 0) const
+\brief Sends a System Common event to the connected consumers
+
+The status byte must be one of the following:
+
+
+| 0xF1 | B_MIDI_TIME_CODE | data1 only |
+| 0xF2 | B_SONG_POSITION | data1 and data2 |
+| 0xF3 | B_SONG_SELECT | data1 only |
+| 0xF5 | B_CABLE_MESSAGE | data1 only |
+| 0xF6 | B_TUNE_REQUEST | no data |
+| 0xF7 | B_SYS_EX_END | no data |
+
+
+\sa BMidiLocalConsumer::SystemCommon()
+*/
+
+/*!
+\fn void BMidiLocalProducer::SpraySystemRealTime(
+ uchar status, bigtime_t time = 0) const
+\brief Sends a Real Time event to the connected consumers
+
+The status byte must be one of the following:
+
+
+| 0xF8 | B_TIMING_CLOCK |
+| 0xFA | B_START |
+| 0xFB | B_CONTINUE |
+| 0xFC | B_STOP |
+| 0xFE | B_ACTIVE_SENSING |
+| 0xFF | B_SYSTEM_RESET |
+
+
+Because of their high priority, the MIDI specification allows real time
+messages to "interleave" with other MIDI messages. A large sysex dump, for
+example, may be interrupted by a real time event. The Midi Kit, however,
+doesn't care. If you (or another producer) have just sent a big system
+exclusive to a consumer, any following real time message will simply have to
+wait until the consumer has dealt with the sysex.
+
+\sa BMidiLocalConsumer::SystemRealTime()
+*/
+
+/*!
+\fn void BMidiLocalProducer::SprayTempoChange(
+ int32 bpm, bigtime_t time = 0) const
+\brief Sends a Tempo Change event to the connected consumers.
+
+This kind of Tempo Change event is not really part of the MIDI spec, rather
+it is an extension from the SMF (Standard MIDI File) format.
+
+\sa BMidiLocalConsumer::TempoChange()
+*/
diff --git a/docs/user/midi2/midiproducer.dox b/docs/user/midi2/midiproducer.dox
new file mode 100644
index 0000000000..9af0f395f0
--- /dev/null
+++ b/docs/user/midi2/midiproducer.dox
@@ -0,0 +1,75 @@
+/*!
+\class BMidiProducer MidiProducer.h
+\brief Streams MIDI events to connected consumers
+
+A producer is an object that generate a stream of MIDI events. Each producer
+has a list of BMidiConsumer objects to which it is connected, and may be asked
+to connect to or disconnect from a BMidiConsumer. A producer can spray its
+events to multiple consumers at the same time.
+
+A BMidiProducer either represents a local producer, i.e. a class extending from
+BMidiLocalProducer, or is a proxy for a remote object published by another app.
+
+*/
+
+/*!
+\fn status_t BMidiProducer::Connect(BMidiConsumer* cons)
+\brief Connects a consumer to this producer
+
+Establishes a connection between this producer and the specified consumer
+endpoint. From now on, any events that this producer sprays will be sent to
+that consumer. You may connect multiple consumers to a producer.
+
+\return B_OK on success, or an error code when the connection could not be
+established. If the consumer is a proxy for a remote object and that object no
+longer exists, Connect() returns B_ERROR. It also returns B_ERROR if you try to
+connect the same producer and consumer more than once.
+
+\sa Disconnect()
+*/
+
+/*!
+\fn status_t BMidiProducer::Disconnect(BMidiConsumer* cons)
+\brief Disconnects a consumer from this producer
+
+Terminates the connection between this producer and the specified consumer
+endpoint. From now on, any events that this producer sprays no longer go to
+that consumer.
+
+\return B_OK on success, or an error code if there was no connection to break
+
+\sa Connect()
+*/
+
+/*!
+\fn bool BMidiProducer::IsConnected(BMidiConsumer* cons) const
+\brief Determines whether a consumer is connected to this producer
+\sa Connect()
+\sa Disconnect()
+*/
+
+/*!
+\fn BList* BMidiProducer::Connections() const
+\brief Returns a list with all connected consumers
+
+Returns a BList with pointers to BMidiEndpoint objects for all consumers that
+are connected to this producer. You can examine the contents of the list as
+follows:
+
+\code
+BList* list = prod->Connections();
+for (int32 t = 0; t < list->CountItems(); ++t)
+{
+ BMidiEndpoint* endp = (BMidiEndpoint*) list->ItemAt(t);
+ ...do stuff...
+ endp->Release(); // yes, here too!
+}
+delete list;
+\endcode
+
+Every time you call this function, a new BList is allocated. The caller (that
+is you) is responsible for freeing this list. The BMidiEndpoint objects in the
+list have their reference counts bumped, so you need to Release() them before
+you delete the list or they will go all leaky on you.
+
+*/
diff --git a/docs/user/midi2/midiroster.dox b/docs/user/midi2/midiroster.dox
new file mode 100644
index 0000000000..5389882805
--- /dev/null
+++ b/docs/user/midi2/midiroster.dox
@@ -0,0 +1,292 @@
+/*!
+\class BMidiRoster MidiRoster.h
+\brief Interface to the system-wide Midi Roster
+
+BMidiRoster allows you to find available MIDI consumer and producer objects.
+You can locate these objects using the iterative NextEndpoint(),
+NextProducer(), and NextConsumer() methods or by requesting notification
+messages to be sent with StartWatching(). Notification messages may contain
+object IDs which can be resolved using the FindEndpoint(), FindProducer(), and
+FindConsumer() methods.
+
+The constructor and destructor of BMidiRoster are private, which means that you
+cannot create or delete your own BMidiRoster objects. Every application can
+have only one instance of BMidiRoster, which is automatically created the very
+first time you use a Midi Kit function.
+
+You can call BMidiRoster's functions like this:
+
+\code
+producer = BMidiRoster::FindProducer(someID);
+\endcode
+
+Or using the slightly more annoying:
+
+\code
+BMidiRoster* roster = BMidiRoster::MidiRoster();
+if (roster != NULL)
+{
+ producer = roster->FindProducer(someID);
+}
+\endcode
+*/
+
+/*!
+\fn BMidiEndpoint* BMidiRoster::NextEndpoint(int32* id)
+\brief Returns the next endpoint from the roster
+
+The "next endpoint" means: the endpoint with the ID that follows id. So if you
+set id to 3, the first possible endpoint it returns is endpoint 4. No endpoint
+can have ID 0, so passing 0 gives you the first endpoint. If you pass NULL
+instead of an ID, NextEndpoint() always returns NULL. When the function
+returns, it sets id to the ID of the endpoint that was found. If no more
+endpoints exist, NextEndpoint() returns NULL and id is not changed.
+NextEndpoint() does not return locally created endpoints, even if they
+are Register()'ed.
+
+Usage example:
+
+\code
+int32 id = 0;
+BMidiEndpoint* endp;
+while ((endp = BMidiRoster::NextEndpoint(&id)) != NULL)
+{
+ ...do something with endpoint ...
+ endp->Release(); // don't forget!
+}
+\endcode
+
+Remember that NextEndpoint() bumps the endpoint's reference count, so you
+should always \link BMidiEndpoint::Release() Release() \endlink it when you are
+done.
+
+*/
+
+/*!
+\fn BMidiProducer* BMidiRoster::NextProducer(int32* id)
+\brief Returns the next producer from the roster
+
+Like NextEndpoint(), but only returns producer endpoints.
+
+\sa NextConsumer
+\sa NextEndpoint
+*/
+
+/*!
+\fn BMidiConsumer* BMidiRoster::NextConsumer(int32* id)
+\brief Returns the next consumer from the roster
+
+Like NextEndpoint(), but only returns consumer endpoints.
+
+\sa NextProducer
+\sa NextEndpoint
+*/
+
+/*!
+\fn BMidiEndpoint* BMidiRoster::FindEndpoint(
+ int32 id, bool localOnly = false)
+\brief Returns the endpoint with the specified ID
+
+FindEndpoint() will always find any local endpoints created by this
+application; they do not have to be published with Register() first. If
+localOnly is false, FindEndpoint() also looks at remote endpoints, otherwise
+only local endpoints will be resolved. Returns NULL if no such endpoint could
+be found.
+
+You should use a dynamic_cast to convert the BMidiEndpoint into a producer or
+consumer:
+
+\code
+BMidiEndpoint* endp = ...;
+BMidiProducer* prod = NULL;
+BMidiConsumer* cons = NULL;
+
+if (endp->IsProducer())
+{
+ prod = dynamic_cast(endp);
+}
+else if (endp->IsConsumer())
+{
+ cons = dynamic_cast(endp);
+}
+\endcode
+
+Remember that FindEndpoint() increments the endpoint's reference count, so you
+should always \link BMidiEndpoint::Release() Release() \endlink an endpoint
+when you are done with it:
+
+\code
+BMidiEndpoint* endp = BMidiRoster::FindEndpoint(someID);
+if (endp != NULL)
+{
+ ...do stuff with the endpoint...
+ endp->Release();
+}
+\endcode
+
+*/
+
+/*!
+\fn BMidiProducer* BMidiRoster::FindProducer(
+ int32 id, bool localOnly = false)
+\brief Finds the producer with the specified ID
+
+Like FindEndpoint(), but only looks for producer endpoints. Returns NULL if no
+endpoint with that ID exists, or if that endpoint is not a producer.
+
+\sa FindConsumer
+\sa FindEndpoint
+*/
+
+/*!
+\fn BMidiConsumer* BMidiRoster::FindConsumer(
+ int32 id, bool localOnly = false)
+\brief Finds the consumer with the specified ID
+
+Like FindEndpoint(), but only looks for consumer endpoints. Returns NULL if no
+endpoint with that ID exists, or if that endpoint is not a consumer.
+
+\sa FindProducer
+\sa FindEndpoint
+*/
+
+/*!
+\fn void BMidiRoster::StartWatching(const BMessenger* msngr)
+\brief Start receiving notifications from the Midi Roster
+
+When you start watching, BMidiRoster sends you notifications for all currently
+published remote endpoints, and all the current connections
+between them. (At this point, BMidiRoster does not let you know about
+connections between unpublished endpoints, nor does it tell you anything about
+your local endpoints, even though they may be published.)
+
+Thereafter, you'll receive notifications any time something important happens
+to an object. The application that performs these operations is itself not
+notified. The assumption here is that you already know about these changes,
+because you are the one that is performing them.
+
+The notifications are BMessages with code B_MIDI_EVENT. You specify the
+BMessenger that will be used to send these messages. Each message contains a
+field called be:op that describes the type of notification.
+
+The "registered" and "unregistered" notifications are sent when a remote
+endpoint Register()'s or Unregister()'s, respectively. You don't receive these
+notifications when you register or unregister your local endpoints, but the
+other apps will.
+
+
+| be:op | int32 | B_MIDI_REGISTERED |
+| be:id | int32 | ID of the endpoint |
+| be:type | string | "producer" or "consumer" |
+
+
+
+| be:op | int32 | B_MIDI_UNREGISTERED |
+| be:id | int32 | ID of the endpoint |
+| be:type | string | "producer" or "consumer" |
+
+
+The "connected" and "disconnected" notifications are sent when a consumer \link
+BMidiProducer::Connect() Connect()\endlink's to a producer, or when they \link
+BMidiProducer::Disconnect() Disconnect() \endlink. You will receive these
+notifications when any two endpoints connect or disconnect, even if they
+are not published. (The purpose of which is debatable.) You won't receive the
+notifications if you are the one making the connection, even if both endpoints
+are remote. You will be notified when another app connects one of your
+published endpoints.
+
+
+| be:op | int32 | B_MIDI_CONNECTED |
+| be:producer | int32 | ID of the connector |
+| be:consumer | int32 | ID of the connectee |
+
+
+
+| be:op | int32 | B_MIDI_DISCONNECTED |
+| be:producer | int32 | ID of the connector |
+| be:consumer | int32 | ID of the connectee |
+
+
+The following notifications are sent when an endpoint's attributes are changed.
+You receive these notifications only if another application is changing one of
+its published endpoints.
+
+
+| be:op | int32 | B_MIDI_CHANGED_NAME |
+| be:id | int32 | ID of the endpoint |
+| be:type | string | "producer" or "consumer" |
+| be:name | string | the endpoint's new name |
+
+
+
+| be:op | int32 | B_MIDI_CHANGED_LATENCY |
+| be:id | int32 | ID of the endpoint |
+| be:type | string | "producer" or "consumer" |
+| be:latency | int64 | the new latency (microseconds) |
+
+
+
+| be:op | int32 | B_MIDI_CHANGED_PROPERTIES |
+| be:id | int32 | ID of the endpoint |
+| be:type | string | "producer" or "consumer" |
+| be:properties | BMessage | the new properties |
+
+
+Typical usage example:
+
+\code
+void MyView::AttachedToWindow()
+{
+ BMessenger msgr(this);
+ BMidiRoster::StartWatching(&msgr);
+}
+
+void MyView::MessageReceived(BMessage* msg)
+{
+ switch (msg->what)
+ {
+ case B_MIDI_EVENT:
+ HandleMidiEvent(msg);
+ break;
+ default:
+ super::MessageReceived(msg);
+ break;
+ }
+}
+\endcode
+
+\sa \ref bmidiop "The possible be:op codes (BMidiOp)"
+*/
+
+/*!
+\fn void BMidiRoster::StopWatching()
+\brief Stop receiving notifications from the Midi Roster
+\sa StartWatching()
+*/
+
+/*!
+\fn status_t BMidiRoster::Register(BMidiEndpoint* object)
+\brief Publishes an endpoint to other applications
+
+Calls BMidiEndpoint's \link BMidiEndpoint::Register() Register() \endlink
+method to publish an endpoint, which makes it visible to other applications.
+
+*/
+
+/*!
+\fn status_t BMidiRoster::Unregister(BMidiEndpoint* object)
+\brief Hides an endpoint from other applications
+
+Calls BMidiEndpoint's \link BMidiEndpoint::Unregister() Unregister() \endlink
+method to hide a previously published endpoint from other applications.
+
+*/
+
+/*!
+\fn BMidiRoster* BMidiRoster::MidiRoster()
+\brief Returns a pointer to the only instance of BMidiRoster
+
+There is no real reason use this function, since all BMidiRoster's public
+function are static.
+
+*/