Browse Source

Take away early bytes optimization from JackMidiRawOutputWriteQueue, as some MIDI systems timestamp incoming data using the time the status byte arrives vs. the time the last byte arrives. Also, doing some debugging on the 'alsarawmidi' driver (in progress).

tags/1.9.8
Devin Anderson 14 years ago
parent
commit
7483c24509
4 changed files with 56 additions and 150 deletions
  1. +40
    -106
      common/JackMidiRawOutputWriteQueue.cpp
  2. +4
    -12
      common/JackMidiRawOutputWriteQueue.h
  3. +12
    -28
      linux/alsarawmidi/JackALSARawMidiDriver.cpp
  4. +0
    -4
      linux/alsarawmidi/JackALSARawMidiOutputPort.cpp

+ 40
- 106
common/JackMidiRawOutputWriteQueue.cpp View File

@@ -50,27 +50,23 @@ JackMidiRawOutputWriteQueue::~JackMidiRawOutputWriteQueue()
delete rt_queue; delete rt_queue;
} }


bool
void
JackMidiRawOutputWriteQueue::DequeueNonRealtimeEvent() JackMidiRawOutputWriteQueue::DequeueNonRealtimeEvent()
{ {
non_rt_event = non_rt_queue->DequeueEvent(); non_rt_event = non_rt_queue->DequeueEvent();
bool result = non_rt_event != 0;
if (result) {
if (non_rt_event) {
non_rt_event_time = non_rt_event->time; non_rt_event_time = non_rt_event->time;
running_status = ApplyRunningStatus(non_rt_event, running_status); running_status = ApplyRunningStatus(non_rt_event, running_status);
} }
return result;
} }


bool
void
JackMidiRawOutputWriteQueue::DequeueRealtimeEvent() JackMidiRawOutputWriteQueue::DequeueRealtimeEvent()
{ {
rt_event = rt_queue->DequeueEvent(); rt_event = rt_queue->DequeueEvent();
bool result = rt_event != 0;
if (result) {
if (rt_event) {
rt_event_time = rt_event->time; rt_event_time = rt_event->time;
} }
return result;
} }


Jack::JackMidiWriteQueue::EnqueueResult Jack::JackMidiWriteQueue::EnqueueResult
@@ -79,11 +75,7 @@ JackMidiRawOutputWriteQueue::EnqueueEvent(jack_nframes_t time, size_t size,
{ {
JackMidiAsyncQueue *queue = (size == 1) && (*buffer >= 0xf8) ? rt_queue : JackMidiAsyncQueue *queue = (size == 1) && (*buffer >= 0xf8) ? rt_queue :
non_rt_queue; non_rt_queue;
EnqueueResult result = queue->EnqueueEvent(time, size, buffer);
if (result == OK) {
last_enqueued_message_time = time;
}
return result;
return queue->EnqueueEvent(time, size, buffer);
} }


void void
@@ -99,38 +91,34 @@ JackMidiRawOutputWriteQueue::HandleWriteQueueBug(jack_nframes_t time,
jack_nframes_t jack_nframes_t
JackMidiRawOutputWriteQueue::Process(jack_nframes_t boundary_frame) JackMidiRawOutputWriteQueue::Process(jack_nframes_t boundary_frame)
{ {
jack_nframes_t current_frame = send_queue->GetNextScheduleFrame();
while (STILL_TIME(current_frame, boundary_frame)) {
if (! non_rt_event) {
DequeueNonRealtimeEvent();
}
if (! rt_event) {
DequeueRealtimeEvent();
}
if (! (non_rt_event || rt_event)) {
return 0;
if (! non_rt_event) {
DequeueNonRealtimeEvent();
}
if (! rt_event) {
DequeueRealtimeEvent();
}
while (rt_event) {
jack_nframes_t current_frame = send_queue->GetNextScheduleFrame();
if ((rt_event_time > current_frame) && non_rt_event &&
(non_rt_event_time < rt_event_time)) {
if (! SendNonRTBytes(rt_event_time < boundary_frame ?
rt_event_time : boundary_frame)) {
return non_rt_event_time;
}
current_frame = send_queue->GetNextScheduleFrame();
} }
if (! WriteRealtimeEvents(boundary_frame)) {
break;
if (! STILL_TIME(current_frame, boundary_frame)) {
return (! non_rt_event) ? rt_event_time :
non_rt_event_time < rt_event_time ? non_rt_event_time :
rt_event_time;
} }
jack_nframes_t non_rt_boundary =
rt_event && STILL_TIME(rt_event_time, boundary_frame) ?
rt_event_time : boundary_frame;
if (! WriteNonRealtimeEvents(non_rt_boundary)) {
break;
if (! SendByte(rt_event_time, *(rt_event->buffer))) {
return rt_event_time;
} }
current_frame = send_queue->GetNextScheduleFrame();
DequeueRealtimeEvent();
} }

// If we get here, that means there is some sort of message available, and
// that either we can't currently write to the write queue or we have
// reached the boundary frame. Return the earliest time that a message is
// scheduled to be sent.

return ! non_rt_event ? rt_event_time :
non_rt_event->size > 1 ? current_frame :
! rt_event ? non_rt_event_time :
non_rt_event_time < rt_event_time ? non_rt_event_time : rt_event_time;
SendNonRTBytes(boundary_frame);
return non_rt_event ? non_rt_event_time : 0;
} }


bool bool
@@ -141,6 +129,10 @@ JackMidiRawOutputWriteQueue::SendByte(jack_nframes_t time,
case BUFFER_TOO_SMALL: case BUFFER_TOO_SMALL:
HandleWriteQueueBug(time, byte); HandleWriteQueueBug(time, byte);
case OK: case OK:

jack_info("JackMidiRawOutputWriteQueue::SendByte - '%d', '%d'", time,
GetCurrentFrame());

return true; return true;
default: default:
// This is here to stop compilers from warning us about not handling // This is here to stop compilers from warning us about not handling
@@ -151,78 +143,20 @@ JackMidiRawOutputWriteQueue::SendByte(jack_nframes_t time,
} }


bool bool
JackMidiRawOutputWriteQueue::
WriteNonRealtimeEvents(jack_nframes_t boundary_frame)
JackMidiRawOutputWriteQueue::SendNonRTBytes(jack_nframes_t boundary_frame)
{ {
if (! non_rt_event) {
if (! DequeueNonRealtimeEvent()) {
return true;
}
}
jack_nframes_t current_frame = send_queue->GetNextScheduleFrame();
do {

// Send out as much of the non-realtime buffer as we can, save for one
// byte which we will send out when the message is supposed to arrive.

for (; non_rt_event->size > 1;
while (non_rt_event) {
for (; non_rt_event->size;
(non_rt_event->size)--, (non_rt_event->buffer)++) { (non_rt_event->size)--, (non_rt_event->buffer)++) {
jack_nframes_t current_frame = send_queue->GetNextScheduleFrame();
if (! STILL_TIME(current_frame, boundary_frame)) { if (! STILL_TIME(current_frame, boundary_frame)) {
return true; return true;
} }
if (! SendByte(current_frame, *(non_rt_event->buffer))) {
if (! SendByte(non_rt_event_time, *(non_rt_event->buffer))) {
return false; return false;
} }
current_frame = send_queue->GetNextScheduleFrame();
}
if (! (STILL_TIME(current_frame, boundary_frame) &&
STILL_TIME(non_rt_event_time, boundary_frame))) {
return true;
}

// There's still time. Try to send the byte.

if (! SendByte(non_rt_event_time, *(non_rt_event->buffer))) {
return false;
}
current_frame = send_queue->GetNextScheduleFrame();
if (! DequeueNonRealtimeEvent()) {
break;
}
} while (STILL_TIME(current_frame, boundary_frame));
return true;
}

bool
JackMidiRawOutputWriteQueue::WriteRealtimeEvents(jack_nframes_t boundary_frame)
{
jack_nframes_t current_frame = send_queue->GetNextScheduleFrame();
if (! rt_event) {
if (! DequeueRealtimeEvent()) {
return true;
}
}
for (;;) {
if (! STILL_TIME(current_frame, boundary_frame)) {
return false;
}

// If:
// -there's still time before we need to send the realtime event
// -there's a non-realtime event available for sending
// -non-realtime data can be scheduled before this event

if ((rt_event_time > current_frame) && non_rt_event &&
((non_rt_event->size > 1) ||
(non_rt_event_time < rt_event_time))) {
return true;
}
if (! SendByte(rt_event_time, *(rt_event->buffer))) {
return false;
}
current_frame = send_queue->GetNextScheduleFrame();
if (! DequeueRealtimeEvent()) {
return true;
} }
DequeueNonRealtimeEvent();
} }
return true;
} }

+ 4
- 12
common/JackMidiRawOutputWriteQueue.h View File

@@ -27,7 +27,7 @@ namespace Jack {


/** /**
* This queue enqueues valid MIDI events and modifies them for raw output * This queue enqueues valid MIDI events and modifies them for raw output
* to a write queue. It has a number of advantages over straight MIDI
* to a write queue. It has a couple of advantages over straight MIDI
* event copying: * event copying:
* *
* -Running status: Status bytes can be omitted when the status byte of the * -Running status: Status bytes can be omitted when the status byte of the
@@ -39,10 +39,6 @@ namespace Jack {
* non-realtime bytes so that realtime messages can be sent as close as * non-realtime bytes so that realtime messages can be sent as close as
* possible to the time they're scheduled for sending. * possible to the time they're scheduled for sending.
* *
* -Time optimization: Bytes in non-realtime messages are sent out early
* when possible, with the last byte of the message being sent out as close
* to the specified event time as possible.
*
* Use this queue if the MIDI API you're interfacing with allows you to * Use this queue if the MIDI API you're interfacing with allows you to
* send raw MIDI bytes. * send raw MIDI bytes.
*/ */
@@ -52,7 +48,6 @@ namespace Jack {


private: private:


jack_nframes_t last_enqueued_message_time;
jack_midi_event_t *non_rt_event; jack_midi_event_t *non_rt_event;
jack_nframes_t non_rt_event_time; jack_nframes_t non_rt_event_time;
JackMidiAsyncQueue *non_rt_queue; JackMidiAsyncQueue *non_rt_queue;
@@ -62,20 +57,17 @@ namespace Jack {
jack_midi_data_t running_status; jack_midi_data_t running_status;
JackMidiSendQueue *send_queue; JackMidiSendQueue *send_queue;


bool
void
DequeueNonRealtimeEvent(); DequeueNonRealtimeEvent();


bool
void
DequeueRealtimeEvent(); DequeueRealtimeEvent();


bool bool
SendByte(jack_nframes_t time, jack_midi_data_t byte); SendByte(jack_nframes_t time, jack_midi_data_t byte);


bool bool
WriteNonRealtimeEvents(jack_nframes_t boundary_frame);

bool
WriteRealtimeEvents(jack_nframes_t boundary_frame);
SendNonRTBytes(jack_nframes_t boundary_frame);


protected: protected:




+ 12
- 28
linux/alsarawmidi/JackALSARawMidiDriver.cpp View File

@@ -159,6 +159,12 @@ JackALSARawMidiDriver::Execute()
strerror(errno)); strerror(errno));
break; break;
} }

if (timeout_frame_ptr) {
jack_info("JackALSARawMidiDriver::Execute - '%d', '%d'",
timeout_frame, GetCurrentFrame());
}

revents = poll_fds[0].revents; revents = poll_fds[0].revents;
if (revents & POLLHUP) { if (revents & POLLHUP) {
// Driver is being stopped. // Driver is being stopped.
@@ -170,10 +176,10 @@ JackALSARawMidiDriver::Execute()
break; break;
} }
timeout_frame = 0; timeout_frame = 0;
for (int i = 0; i < fCaptureChannels; i++) {
if (! input_ports[i]->ProcessALSA(&process_frame)) {
for (int i = 0; i < fPlaybackChannels; i++) {
if (! output_ports[i]->ProcessALSA(fds[0], &process_frame)) {
jack_error("JackALSARawMidiDriver::Execute - a fatal error " jack_error("JackALSARawMidiDriver::Execute - a fatal error "
"occurred while processing ALSA input events.");
"occurred while processing ALSA output events.");
goto cleanup; goto cleanup;
} }
if (process_frame && ((! timeout_frame) || if (process_frame && ((! timeout_frame) ||
@@ -181,10 +187,10 @@ JackALSARawMidiDriver::Execute()
timeout_frame = process_frame; timeout_frame = process_frame;
} }
} }
for (int i = 0; i < fPlaybackChannels; i++) {
if (! output_ports[i]->ProcessALSA(fds[0], &process_frame)) {
for (int i = 0; i < fCaptureChannels; i++) {
if (! input_ports[i]->ProcessALSA(&process_frame)) {
jack_error("JackALSARawMidiDriver::Execute - a fatal error " jack_error("JackALSARawMidiDriver::Execute - a fatal error "
"occurred while processing ALSA output events.");
"occurred while processing ALSA input events.");
goto cleanup; goto cleanup;
} }
if (process_frame && ((! timeout_frame) || if (process_frame && ((! timeout_frame) ||
@@ -337,17 +343,6 @@ JackALSARawMidiDriver::Open(bool capturing, bool playing, int in_channels,
snd_rawmidi_info_t *info = in_info_list.at(i); snd_rawmidi_info_t *info = in_info_list.at(i);
try { try {
input_ports[num_inputs] = new JackALSARawMidiInputPort(info, i); input_ports[num_inputs] = new JackALSARawMidiInputPort(info, i);

jack_info("JackALSARawMidiDriver::Open - Input port: card=%d, "
"device=%d, subdevice=%d, id=%s, name=%s, subdevice "
"name=%s",
snd_rawmidi_info_get_card(info),
snd_rawmidi_info_get_device(info),
snd_rawmidi_info_get_subdevice(info),
snd_rawmidi_info_get_id(info),
snd_rawmidi_info_get_name(info),
snd_rawmidi_info_get_subdevice_name(info));

num_inputs++; num_inputs++;
} catch (std::exception e) { } catch (std::exception e) {
jack_error("JackALSARawMidiDriver::Open - while creating new " jack_error("JackALSARawMidiDriver::Open - while creating new "
@@ -359,17 +354,6 @@ JackALSARawMidiDriver::Open(bool capturing, bool playing, int in_channels,
snd_rawmidi_info_t *info = out_info_list.at(i); snd_rawmidi_info_t *info = out_info_list.at(i);
try { try {
output_ports[num_outputs] = new JackALSARawMidiOutputPort(info, i); output_ports[num_outputs] = new JackALSARawMidiOutputPort(info, i);

jack_info("JackALSARawMidiDriver::Open - Output port: card=%d, "
"device=%d, subdevice=%d, id=%s, name=%s, subdevice "
"name=%s",
snd_rawmidi_info_get_card(info),
snd_rawmidi_info_get_device(info),
snd_rawmidi_info_get_subdevice(info),
snd_rawmidi_info_get_id(info),
snd_rawmidi_info_get_name(info),
snd_rawmidi_info_get_subdevice_name(info));

num_outputs++; num_outputs++;
} catch (std::exception e) { } catch (std::exception e) {
jack_error("JackALSARawMidiDriver::Open - while creating new " jack_error("JackALSARawMidiDriver::Open - while creating new "


+ 0
- 4
linux/alsarawmidi/JackALSARawMidiOutputPort.cpp View File

@@ -124,10 +124,6 @@ JackALSARawMidiOutputPort::ProcessALSA(int read_fd, jack_nframes_t *frame)
*frame = raw_queue->Process(); *frame = raw_queue->Process();
blocked = send_queue->IsBlocked(); blocked = send_queue->IsBlocked();
if (blocked) { if (blocked) {

jack_info("JackALSARawMidiOutputPort::ProcessALSA - MIDI port is "
"blocked");

SetPollEventMask(POLLERR | POLLNVAL | POLLOUT); SetPollEventMask(POLLERR | POLLNVAL | POLLOUT);
*frame = 0; *frame = 0;
} else { } else {


Loading…
Cancel
Save