BASS_MIDI_StreamEvents

Applies any number of events to a MIDI stream.

DWORD BASS_MIDI_StreamEvents(
    HSTREAM handle,
    DWORD mode,
    void *events,
    DWORD length
);

Parameters

handleThe MIDI stream to apply the events to.
modeThe type of event data to apply. One of the following, with optional flags.
BASS_MIDI_EVENTS_RAWRaw MIDI event data, as would be sent to a MIDI device. To overcome the standard 16 channel limit, the event data's channel information can optionally be overridden by adding the new channel number to this parameter, where +1 = the 1st channel. The channel limit can also be overcome with MIDI port meta-events.
BASS_MIDI_EVENTS_STRUCTAn array of BASS_MIDI_EVENT structures.
BASS_MIDI_EVENTS_CANCELFlag: Cancel pending events (not yet processed) from a previous call of this function.
BASS_MIDI_EVENTS_NORSTATUSFlag: Disable running status, meaning each event must include a status byte. Only applicable with BASS_MIDI_EVENTS_RAW.
BASS_MIDI_EVENTS_FILTERFlag: Apply filtering (enabled via BASS_MIDI_StreamSetFilter) to the events.
BASS_MIDI_EVENTS_SYNCFlag: Trigger BASS_SYNC_MIDI_EVENT syncs for the processed events.
BASS_MIDI_EVENTS_TIMEFlag: The raw MIDI data includes delta-time info (when used with BASS_MIDI_EVENTS_RAW) or the BASS_MIDI_EVENT tick and pos members should be processed (without BASS_MIDI_EVENTS_RAW). The positions are relative to the current processing position. If neither this or BASS_MIDI_EVENTS_ABSTIME is specified then the BASS_MIDI_EVENT tick and pos members will be ignored.
BASS_MIDI_EVENTS_ABSTIMEFlag: The raw MIDI data includes delta-time info (when used with BASS_MIDI_EVENTS_RAW) or the BASS_MIDI_EVENT tick and pos members should be processed (without BASS_MIDI_EVENTS_RAW). The positions are absolute. If an event's position has already passed then it will be processed immediately, or at the start of the next update cycle if the BASS_MIDI_EVENTS_ASYNC flag is also specified.
BASS_MIDI_EVENTS_ASYNCFlag: Process the events asynchronously (at the next update cycle) rather than immediately, except when called from a MIDIFILTERPROC callback. This flag is applied automatically if the BASS_MIDI_ASYNC flag is set on the stream.
BASS_MIDI_EVENTS_FLUSHFlag: Process any pending async events immediately and disable async processing for the provided events. This overrides the BASS_MIDI_EVENTS_ASYNC flag (and the BASS_MIDI_ASYNC flag if it is set on the stream).
eventsThe event data.
lengthThe length of the event data. The number of bytes or BASS_MIDI_EVENT structures, depending on the type of event data.

Return value

If successful, the number of events processed is returned, else -1 is returned. Use BASS_ErrorGetCode to get the error code. The number of processed events does not include any that have an out of range channel number.

Error codes

BASS_ERROR_HANDLEhandle is not valid.
BASS_ERROR_ILLPARAMmode is not valid.
BASS_ERROR_NOTAVAILThis function cannot be called from a MIDIFILTERPROC callback with BASS_MIDI_EVENTS_FILTER set, or with BASS_MIDI_EVENTS_SYNC set while seeking.

Remarks

Events applied to a MIDI file/sequence stream can subsequently be overridden by events in the file/sequence itself, and will also be overridden when seeking or looping. That can be avoided by using additional channels for those events, allocated via the BASS_ATTRIB_MIDI_CHANS attribute.

The MIDI port meta-event (21h) is supported in raw MIDI data, allowing access to more than the standard 16 channels: port 0 = channels 1-16, port 1 = channels 17-32, etc. The active port number persists across calls of this function.

The BASS_MIDI_EVENTS_TIME and BASS_MIDI_EVENTS_ABSTIME flags allow events to be delayed until specific positions. With raw MIDI data, they enable delta-time info to be included in the data. With an BASS_MIDI_EVENT array, they enable processing of the tick and pos members (only one should be used). The events do not necessarily need to be provided in chronological order; they will be sorted automatically. The BASS_MIDI_EVENTS_CANCEL flag can be used to remove any old pending events. Any pending events are also cancelled by BASS_ChannelSetPosition.

If the BASS_MIDI_EVENTS_ASYNC flag is used without the BASS_MIDI_EVENTS_TIME or BASS_MIDI_EVENTS_ABSTIME flags then the events will be processed in the next update cycle, at an offset determined by the time that has passed since the last update cycle. For example, if the last update cycle was 3ms ago then the events will be applied 3ms into the next update cycle's output. This unties the event's timing from the stream's update period for greater resolution, without having to resort to the BASS_MIDI_EVENTS_TIME or BASS_MIDI_EVENTS_ABSTIME options. If this function is called during an update cycle then the events will be processed at the end of that, or immediately if the call is from a MIDIFILTERPROC callback.

During playback, there will be some delay in the effect of the events being heard even if no delay is requested in the event data/flags, due to buffering. This latency can be reduced via the BASS_ATTRIB_BUFFER attribute.

Example

Play a C major chord with a velocity of 100, on channel 1 for 2 seconds.
BASS_MIDI_EVENT events[3];
memset(events, 0, sizeof(events));
events[0].event = MIDI_EVENT_NOTE;
events[0].param = MAKEWORD(60, 100); // C
events[1].event = MIDI_EVENT_NOTE;
events[1].param = MAKEWORD(64, 100); // E
events[2].event = MIDI_EVENT_NOTE;
events[2].param = MAKEWORD(67, 100); // G
BASS_MIDI_StreamEvents(handle, BASS_MIDI_EVENTS_STRUCT, events, 3); // process the events
Sleep(2000); // wait 2 seconds
// modify the event data to release the keys
events[0].param = MAKEWORD(60, 0); // release C
events[1].param = MAKEWORD(64, 0); // release E
events[2].param = MAKEWORD(67, 0); // release G
BASS_MIDI_StreamEvents(handle, BASS_MIDI_EVENTS_STRUCT, events, 3); // process the events

The same thing using raw MIDI event data.

BYTE events[7] = {0x90, 60, 100, 64, 100, 67, 100}; // the event data
BASS_MIDI_StreamEvents(handle, BASS_MIDI_EVENTS_RAW, events, 7); // process the events
Sleep(2000); // wait 2 seconds
// modify the event data to release the keys
events[2] = 0; // release C
events[4] = 0; // release E
events[6] = 0; // release G
BASS_MIDI_StreamEvents(handle, BASS_MIDI_EVENTS_RAW, events, 7); // process the events

The same thing in a single event sequence, making use of pos to delay the release.

BASS_MIDI_EVENT events[6];
memset(events, 0, sizeof(events));
events[0].event = MIDI_EVENT_NOTE;
events[0].param = MAKEWORD(60, 100); // C
events[1].event = MIDI_EVENT_NOTE;
events[1].param = MAKEWORD(64, 100); // E
events[2].event = MIDI_EVENT_NOTE;
events[2].param = MAKEWORD(67, 100); // G
events[3].event = MIDI_EVENT_NOTE;
events[3].param = MAKEWORD(60, 0); // release C
events[3].pos = BASS_ChannelSeconds2Bytes(handle, 2); // 2 seconds
events[4].event = MIDI_EVENT_NOTE;
events[4].param = MAKEWORD(64, 0); // release E
events[4].pos = events[3].pos;
events[5].event = MIDI_EVENT_NOTE;
events[5].param = MAKEWORD(67, 0); // release G
events[5].pos = events[3].pos;
BASS_MIDI_StreamEvents(handle, BASS_MIDI_EVENTS_STRUCT | BASS_MIDI_EVENTS_TIME, events, 6); // process the events

See also

BASS_MIDI_StreamCreate, BASS_MIDI_StreamEvent, BASS_MIDI_StreamGetEvent