Browse Source

Fix 'alsarawmidi' driver so that it actually works. Add functionality to 'midi_latency_test'. Fix bug in raw write queue implementation. Output error message when a source MIDI port isn't valid during mixdown. Output error messages for error conditions detected in buffer read and write queues.

tags/1.9.8
Devin Anderson 14 years ago
parent
commit
e2683cb024
11 changed files with 106 additions and 66 deletions
  1. +13
    -3
      common/JackMidiBufferReadQueue.cpp
  2. +13
    -5
      common/JackMidiBufferWriteQueue.cpp
  3. +4
    -3
      common/JackMidiPort.cpp
  4. +1
    -1
      common/JackMidiRawInputWriteQueue.cpp
  5. +28
    -11
      example-clients/midi_latency_test.c
  6. +32
    -32
      linux/alsarawmidi/JackALSARawMidiDriver.cpp
  7. +1
    -1
      linux/alsarawmidi/JackALSARawMidiDriver.h
  8. +1
    -0
      linux/alsarawmidi/JackALSARawMidiInputPort.cpp
  9. +4
    -3
      linux/alsarawmidi/JackALSARawMidiOutputPort.cpp
  10. +6
    -6
      linux/alsarawmidi/JackALSARawMidiPort.cpp
  11. +3
    -1
      linux/alsarawmidi/JackALSARawMidiPort.h

+ 13
- 3
common/JackMidiBufferReadQueue.cpp View File

@@ -46,12 +46,22 @@ JackMidiBufferReadQueue::DequeueEvent()
void void
JackMidiBufferReadQueue::ResetMidiBuffer(JackMidiBuffer *buffer) JackMidiBufferReadQueue::ResetMidiBuffer(JackMidiBuffer *buffer)
{ {
event_count = 0;
index = 0; index = 0;
if (buffer) {
if (! buffer) {
jack_error("JackMidiBufferReadQueue::ResetMidiBuffer - buffer reset "
"to NULL");
} else if (! buffer->IsValid()) {
jack_error("JackMidiBufferReadQueue::ResetMidiBuffer - buffer reset "
"to invalid buffer");
} else {
uint32_t lost_events = buffer->lost_events;
if (lost_events) {
jack_error("JackMidiBufferReadQueue::ResetMidiBuffer - %d events "
"lost during mixdown", lost_events);
}
this->buffer = buffer; this->buffer = buffer;
event_count = buffer->event_count; event_count = buffer->event_count;
last_frame_time = GetLastFrame(); last_frame_time = GetLastFrame();
} else {
event_count = 0;
} }
} }

+ 13
- 5
common/JackMidiBufferWriteQueue.cpp View File

@@ -49,9 +49,17 @@ void
JackMidiBufferWriteQueue::ResetMidiBuffer(JackMidiBuffer *buffer, JackMidiBufferWriteQueue::ResetMidiBuffer(JackMidiBuffer *buffer,
jack_nframes_t frames) jack_nframes_t frames)
{ {
this->buffer = buffer;
buffer->Reset(frames);
last_frame_time = GetLastFrame();
max_bytes = buffer->MaxEventSize();
next_frame_time = last_frame_time + frames;
if (! buffer) {
jack_error("JackMidiBufferWriteQueue::ResetMidiBuffer - buffer reset "
"to NULL");
} else if (! buffer->IsValid()) {
jack_error("JackMidiBufferWriteQueue::ResetMidiBuffer - buffer reset "
"to invalid buffer");
} else {
this->buffer = buffer;
buffer->Reset(frames);
last_frame_time = GetLastFrame();
max_bytes = buffer->MaxEventSize();
next_frame_time = last_frame_time + frames;
}
} }

+ 4
- 3
common/JackMidiPort.cpp View File

@@ -55,7 +55,6 @@ SERVER_EXPORT jack_midi_data_t* JackMidiBuffer::ReserveEvent(jack_nframes_t time
lost_events++; lost_events++;
return 0; return 0;
} }

JackMidiEvent* event = &events[event_count++]; JackMidiEvent* event = &events[event_count++];
event->time = time; event->time = time;
event->size = size; event->size = size;
@@ -90,7 +89,7 @@ static void MidiBufferMixdown(void* mixbuffer, void** src_buffers, int src_count
{ {
JackMidiBuffer* mix = static_cast<JackMidiBuffer*>(mixbuffer); JackMidiBuffer* mix = static_cast<JackMidiBuffer*>(mixbuffer);
if (!mix->IsValid()) { if (!mix->IsValid()) {
jack_error("MIDI: invalid mix buffer");
jack_error("Jack::MidiBufferMixdown - invalid mix buffer");
return; return;
} }
mix->Reset(nframes); mix->Reset(nframes);
@@ -98,8 +97,10 @@ static void MidiBufferMixdown(void* mixbuffer, void** src_buffers, int src_count
int event_count = 0; int event_count = 0;
for (int i = 0; i < src_count; ++i) { for (int i = 0; i < src_count; ++i) {
JackMidiBuffer* buf = static_cast<JackMidiBuffer*>(src_buffers[i]); JackMidiBuffer* buf = static_cast<JackMidiBuffer*>(src_buffers[i]);
if (!buf->IsValid())
if (!buf->IsValid()) {
jack_error("Jack::MidiBufferMixdown - invalid source buffer");
return; return;
}
buf->mix_index = 0; buf->mix_index = 0;
event_count += buf->event_count; event_count += buf->event_count;
mix->lost_events += buf->lost_events; mix->lost_events += buf->lost_events;


+ 1
- 1
common/JackMidiRawInputWriteQueue.cpp View File

@@ -282,7 +282,7 @@ JackMidiRawInputWriteQueue::RecordByte(jack_midi_data_t byte)
bool bool
JackMidiRawInputWriteQueue::WriteEvent(jack_nframes_t boundary_frame) JackMidiRawInputWriteQueue::WriteEvent(jack_nframes_t boundary_frame)
{ {
if (event.time < boundary_frame) {
if ((! boundary_frame) || (event.time < boundary_frame)) {
switch (write_queue->EnqueueEvent(&event)) { switch (write_queue->EnqueueEvent(&event)) {
case BUFFER_TOO_SMALL: case BUFFER_TOO_SMALL:
HandleEventLoss(&event); HandleEventLoss(&event);


+ 28
- 11
example-clients/midi_latency_test.c View File

@@ -85,7 +85,8 @@ jack_nframes_t lowest_latency;
jack_time_t lowest_latency_time; jack_time_t lowest_latency_time;
jack_midi_data_t *message_1; jack_midi_data_t *message_1;
jack_midi_data_t *message_2; jack_midi_data_t *message_2;
size_t messages_processed;
size_t messages_received;
size_t messages_sent;
size_t message_size; size_t message_size;
jack_latency_range_t out_latency_range; jack_latency_range_t out_latency_range;
jack_port_t *out_port; jack_port_t *out_port;
@@ -100,6 +101,7 @@ int timeout;
jack_nframes_t total_latency; jack_nframes_t total_latency;
jack_time_t total_latency_time; jack_time_t total_latency_time;
size_t unexpected_messages; size_t unexpected_messages;
size_t xrun_count;


static void static void
output_error(const char *source, const char *message); output_error(const char *source, const char *message);
@@ -156,11 +158,13 @@ handle_process(jack_nframes_t frames, void *arg)
} }
highest_latency = 0; highest_latency = 0;
lowest_latency = 0; lowest_latency = 0;
messages_processed = 0;
messages_received = 0;
messages_sent = 0;
process_state = 1; process_state = 1;
total_latency = 0; total_latency = 0;
total_latency_time = 0; total_latency_time = 0;
unexpected_messages = 0; unexpected_messages = 0;
xrun_count = 0;
jack_port_get_latency_range(remote_in_port, JackCaptureLatency, jack_port_get_latency_range(remote_in_port, JackCaptureLatency,
&in_latency_range); &in_latency_range);
jack_port_get_latency_range(remote_out_port, JackPlaybackLatency, jack_port_get_latency_range(remote_out_port, JackPlaybackLatency,
@@ -175,7 +179,7 @@ handle_process(jack_nframes_t frames, void *arg)
last_frame_time = jack_last_frame_time(client); last_frame_time = jack_last_frame_time(client);
for (i = 0; i < event_count; i++) { for (i = 0; i < event_count; i++) {
jack_midi_event_get(&event, port_buffer, i); jack_midi_event_get(&event, port_buffer, i);
message = (messages_processed % 2) ? message_2 : message_1;
message = (messages_received % 2) ? message_2 : message_1;
if ((event.size == message_size) && if ((event.size == message_size) &&
(! memcmp(message, event.buffer, (! memcmp(message, event.buffer,
message_size * sizeof(jack_midi_data_t)))) { message_size * sizeof(jack_midi_data_t)))) {
@@ -201,20 +205,20 @@ handle_process(jack_nframes_t frames, void *arg)
lowest_latency = frame; lowest_latency = frame;
lowest_latency_time = time; lowest_latency_time = time;
} }
latency_time_values[messages_processed] = time;
latency_values[messages_processed] = frame;
latency_time_values[messages_received] = time;
latency_values[messages_received] = frame;
total_latency += frame; total_latency += frame;
total_latency_time += time; total_latency_time += time;
messages_processed++;
if (messages_processed == samples) {
messages_received++;
if (messages_received == samples) {
process_state = 2; process_state = 2;
sem_post(&semaphore); sem_post(&semaphore);
break; break;
} }
send_message: send_message:
frame = (jack_nframes_t) ((((double) rand()) / RAND_MAX) * frames); frame = (jack_nframes_t) ((((double) rand()) / RAND_MAX) * frames);
if (frame == frames) {
frame--;
if (frame >= frames) {
frame = frames - 1;
} }
port_buffer = jack_port_get_buffer(out_port, frames); port_buffer = jack_port_get_buffer(out_port, frames);
jack_midi_clear_buffer(port_buffer); jack_midi_clear_buffer(port_buffer);
@@ -223,10 +227,11 @@ handle_process(jack_nframes_t frames, void *arg)
set_process_error(SOURCE_EVENT_RESERVE, ERROR_RESERVE); set_process_error(SOURCE_EVENT_RESERVE, ERROR_RESERVE);
break; break;
} }
message = (messages_processed % 2) ? message_2 : message_1;
message = (messages_sent % 2) ? message_2 : message_1;
memcpy(buffer, message, message_size * sizeof(jack_midi_data_t)); memcpy(buffer, message, message_size * sizeof(jack_midi_data_t));
last_activity = jack_last_frame_time(client) + frame; last_activity = jack_last_frame_time(client) + frame;
last_activity_time = jack_frames_to_time(client, last_activity); last_activity_time = jack_frames_to_time(client, last_activity);
messages_sent++;


case 2: case 2:
/* State: finished - do nothing */ /* State: finished - do nothing */
@@ -245,6 +250,12 @@ handle_shutdown(void *arg)
set_process_error("handle_shutdown", "The JACK server has been shutdown"); set_process_error("handle_shutdown", "The JACK server has been shutdown");
} }


static void
handle_xrun(void *arg)
{
xrun_count++;
}

static void static void
output_error(const char *source, const char *message) output_error(const char *source, const char *message)
{ {
@@ -551,8 +562,14 @@ main(int argc, char **argv)
printf(" > 10 ms: %u\n", jitter_plot[100]); printf(" > 10 ms: %u\n", jitter_plot[100]);
} }
} }
printf("\nMessages sent: %d\n"
"Messages received: %d\n",
messages_sent, messages_received);
if (unexpected_messages) { if (unexpected_messages) {
printf("\nUnexpected messages received: %d\n", unexpected_messages);
printf("Unexpected messages received: %d\n", unexpected_messages);
}
if (xrun_count) {
printf("Xruns: %d (messages may have been lost)", xrun_count);
} }
deactivate_client: deactivate_client:
jack_deactivate(client); jack_deactivate(client);


+ 32
- 32
linux/alsarawmidi/JackALSARawMidiDriver.cpp View File

@@ -39,8 +39,12 @@ JackALSARawMidiDriver::Attach()
{ {
jack_nframes_t buffer_size = fEngineControl->fBufferSize; jack_nframes_t buffer_size = fEngineControl->fBufferSize;
jack_port_id_t index; jack_port_id_t index;
jack_nframes_t latency = buffer_size;
jack_latency_range_t latency_range;
const char *name; const char *name;
JackPort *port; JackPort *port;
latency_range.max = latency;
latency_range.min = latency;
for (int i = 0; i < fCaptureChannels; i++) { for (int i = 0; i < fCaptureChannels; i++) {
JackALSARawMidiInputPort *input_port = input_ports[i]; JackALSARawMidiInputPort *input_port = input_ports[i];
name = input_port->GetName(); name = input_port->GetName();
@@ -55,9 +59,14 @@ JackALSARawMidiDriver::Attach()
} }
port = fGraphManager->GetPort(index); port = fGraphManager->GetPort(index);
port->SetAlias(input_port->GetAlias()); port->SetAlias(input_port->GetAlias());
port->SetLatency(buffer_size);
port->SetLatencyRange(JackCaptureLatency, &latency_range);
fCapturePortList[i] = index; fCapturePortList[i] = index;
} }
if (! fEngineControl->fSyncMode) {
latency += buffer_size;
latency_range.max = latency;
latency_range.min = latency;
}
for (int i = 0; i < fPlaybackChannels; i++) { for (int i = 0; i < fPlaybackChannels; i++) {
JackALSARawMidiOutputPort *output_port = output_ports[i]; JackALSARawMidiOutputPort *output_port = output_ports[i];
name = output_port->GetName(); name = output_port->GetName();
@@ -72,7 +81,7 @@ JackALSARawMidiDriver::Attach()
} }
port = fGraphManager->GetPort(index); port = fGraphManager->GetPort(index);
port->SetAlias(output_port->GetAlias()); port->SetAlias(output_port->GetAlias());
port->SetLatency(buffer_size);
port->SetLatencyRange(JackPlaybackLatency, &latency_range);
fPlaybackPortList[i] = index; fPlaybackPortList[i] = index;
} }
return 0; return 0;
@@ -103,23 +112,19 @@ JackALSARawMidiDriver::Execute()
{ {
jack_nframes_t timeout_frame = 0; jack_nframes_t timeout_frame = 0;
for (;;) { for (;;) {
jack_nframes_t process_frame;
jack_time_t wait_time; jack_time_t wait_time;
jack_time_t *wait_time_ptr;
unsigned short revents; unsigned short revents;
if (! timeout_frame) { if (! timeout_frame) {
wait_time = 0;
wait_time_ptr = 0;
} else { } else {
jack_time_t next_time = GetTimeFromFrames(timeout_frame); jack_time_t next_time = GetTimeFromFrames(timeout_frame);
jack_time_t now = GetMicroSeconds(); jack_time_t now = GetMicroSeconds();

if (next_time <= now) {
goto handle_ports;
}
wait_time = next_time - now;
wait_time = next_time <= now ? 0 : next_time - now;
wait_time_ptr = &wait_time;
} }

jack_info("Calling 'Poll' with wait time '%d'.", wait_time);

if (Poll(wait_time) == -1) {
if (Poll(wait_time_ptr) == -1) {
if (errno == EINTR) { if (errno == EINTR) {
continue; continue;
} }
@@ -139,8 +144,7 @@ JackALSARawMidiDriver::Execute()
break; break;
} }
handle_ports: handle_ports:
jack_nframes_t process_frame;
jack_nframes_t timeout_frame = 0;
timeout_frame = 0;
for (int i = 0; i < fCaptureChannels; i++) { for (int i = 0; i < fCaptureChannels; i++) {
process_frame = input_ports[i]->ProcessALSA(); process_frame = input_ports[i]->ProcessALSA();
if (process_frame && ((! timeout_frame) || if (process_frame && ((! timeout_frame) ||
@@ -156,9 +160,6 @@ JackALSARawMidiDriver::Execute()
} }
} }
} }

jack_info("ALSA thread is exiting.");

return false; return false;
} }


@@ -362,15 +363,15 @@ JackALSARawMidiDriver::Open(bool capturing, bool playing, int in_channels,
#ifdef HAVE_PPOLL #ifdef HAVE_PPOLL


int int
JackALSARawMidiDriver::Poll(jack_time_t wait_time)
JackALSARawMidiDriver::Poll(const jack_time_t *wait_time)
{ {
struct timespec timeout; struct timespec timeout;
struct timespec *timeout_ptr; struct timespec *timeout_ptr;
if (! wait_time) { if (! wait_time) {
timeout_ptr = 0; timeout_ptr = 0;
} else { } else {
timeout.tv_sec = wait_time / 1000000;
timeout.tv_nsec = (wait_time % 1000000) * 1000;
timeout.tv_sec = (*wait_time) / 1000000;
timeout.tv_nsec = ((*wait_time) % 1000000) * 1000;
timeout_ptr = &timeout; timeout_ptr = &timeout;
} }
return ppoll(poll_fds, poll_fd_count, timeout_ptr, 0); return ppoll(poll_fds, poll_fd_count, timeout_ptr, 0);
@@ -379,15 +380,15 @@ JackALSARawMidiDriver::Poll(jack_time_t wait_time)
#else #else


int int
JackALSARawMidiDriver::Poll(jack_time_t wait_time)
JackALSARawMidiDriver::Poll(const jack_time_t *wait_time)
{ {
int result = poll(poll_fds, poll_fd_count, int result = poll(poll_fds, poll_fd_count,
! wait_time ? -1 : (int) (wait_time / 1000));
! wait_time ? -1 : (int) ((*wait_time) / 1000));
if ((! result) && wait_time) { if ((! result) && wait_time) {
wait_time %= 1000;
if (wait_time) {
jack_time_t time_left = (*wait_time) % 1000;
if (time_left) {
// Cheap hack. // Cheap hack.
usleep(wait_time);
usleep(time_left);
result = poll(poll_fds, poll_fd_count, 0); result = poll(poll_fds, poll_fd_count, 0);
} }
} }
@@ -399,9 +400,9 @@ JackALSARawMidiDriver::Poll(jack_time_t wait_time)
int int
JackALSARawMidiDriver::Read() JackALSARawMidiDriver::Read()
{ {
jack_nframes_t buffer_size = fEngineControl->fBufferSize;
for (int i = 0; i < fCaptureChannels; i++) { for (int i = 0; i < fCaptureChannels; i++) {
input_ports[i]->ProcessJack(GetInputBuffer(i),
fEngineControl->fBufferSize);
input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size);
} }
return 0; return 0;
} }
@@ -412,8 +413,7 @@ JackALSARawMidiDriver::Start()


jack_info("JackALSARawMidiDriver::Start - Starting 'alsarawmidi' driver."); jack_info("JackALSARawMidiDriver::Start - Starting 'alsarawmidi' driver.");


// JackMidiDriver::Start();

JackMidiDriver::Start();
poll_fd_count = 1; poll_fd_count = 1;
for (int i = 0; i < fCaptureChannels; i++) { for (int i = 0; i < fCaptureChannels; i++) {
poll_fd_count += input_ports[i]->GetPollDescriptorCount(); poll_fd_count += input_ports[i]->GetPollDescriptorCount();
@@ -471,11 +471,11 @@ JackALSARawMidiDriver::Start()
poll_fd_iter += output_port->GetPollDescriptorCount(); poll_fd_iter += output_port->GetPollDescriptorCount();
} }


jack_info("Starting ALSA thread ...");
jack_info("JackALSARawMidiDriver::Start - starting ALSA thread ...");


if (! thread->StartSync()) { if (! thread->StartSync()) {


jack_info("Started ALSA thread.");
jack_info("JackALSARawMidiDriver::Start - started ALSA thread.");


return 0; return 0;
} }
@@ -496,7 +496,7 @@ int
JackALSARawMidiDriver::Stop() JackALSARawMidiDriver::Stop()
{ {


jack_info("Stopping 'alsarawmidi' driver.");
jack_info("JackALSARawMidiDriver::Stop - stopping 'alsarawmidi' driver.");


if (fds[1] != -1) { if (fds[1] != -1) {
close(fds[1]); close(fds[1]);


+ 1
- 1
linux/alsarawmidi/JackALSARawMidiDriver.h View File

@@ -34,7 +34,7 @@ namespace Jack {
int code); int code);


int int
Poll(jack_time_t wait_time);
Poll(const jack_time_t *wait_time);


public: public:




+ 1
- 0
linux/alsarawmidi/JackALSARawMidiInputPort.cpp View File

@@ -101,6 +101,7 @@ JackALSARawMidiInputPort::ProcessJack(JackMidiBuffer *port_buffer,
jack_event = thread_queue->DequeueEvent(); jack_event = thread_queue->DequeueEvent();
} }
for (; jack_event; jack_event = thread_queue->DequeueEvent()) { for (; jack_event; jack_event = thread_queue->DequeueEvent()) {

// We add `frames` so that MIDI events align with audio as closely as // We add `frames` so that MIDI events align with audio as closely as
// possible. // possible.
switch (write_queue->EnqueueEvent(jack_event->time + frames, switch (write_queue->EnqueueEvent(jack_event->time + frames,


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

@@ -101,6 +101,10 @@ JackALSARawMidiOutputPort::ProcessALSA(int read_fd)
jack_nframes_t next_frame = raw_queue->Process(); jack_nframes_t next_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);
return 0; return 0;
} }
@@ -122,9 +126,6 @@ JackALSARawMidiOutputPort::ProcessJack(JackMidiBuffer *port_buffer,
continue; continue;
} }
char c = 1; char c = 1;

jack_info("Attempting to write to file descriptor '%d'", write_fd);

ssize_t result = write(write_fd, &c, 1); ssize_t result = write(write_fd, &c, 1);
assert(result <= 1); assert(result <= 1);
if (! result) { if (! result) {


+ 6
- 6
linux/alsarawmidi/JackALSARawMidiPort.cpp View File

@@ -49,7 +49,7 @@ JackALSARawMidiPort::JackALSARawMidiPort(snd_rawmidi_info_t *info,
if (code) { if (code) {
error_message = snd_strerror(code); error_message = snd_strerror(code);
func = "snd_rawmidi_params_current"; func = "snd_rawmidi_params_current";
goto close;
goto free_params;
} }
code = snd_rawmidi_params_set_avail_min(rawmidi, params, 1); code = snd_rawmidi_params_set_avail_min(rawmidi, params, 1);
if (code) { if (code) {
@@ -129,22 +129,22 @@ JackALSARawMidiPort::PopulatePollDescriptors(struct pollfd *poll_fd)
int int
JackALSARawMidiPort::ProcessPollEvents() JackALSARawMidiPort::ProcessPollEvents()
{ {
unsigned short revents;
unsigned short revents = 0;
int code = snd_rawmidi_poll_descriptors_revents(rawmidi, poll_fds, num_fds, int code = snd_rawmidi_poll_descriptors_revents(rawmidi, poll_fds, num_fds,
&revents); &revents);
if (code) { if (code) {
jack_error("JackALSARawMidiInputPort::ProcessPollEvents - "
jack_error("JackALSARawMidiPort::ProcessPollEvents - "
"snd_rawmidi_poll_descriptors_revents: %s", "snd_rawmidi_poll_descriptors_revents: %s",
snd_strerror(code)); snd_strerror(code));
return 0; return 0;
} }
if (revents & POLLNVAL) { if (revents & POLLNVAL) {
jack_error("JackALSARawMidiInputPort::ProcessPollEvents - the file "
jack_error("JackALSARawMidiPort::ProcessPollEvents - the file "
"descriptor is invalid."); "descriptor is invalid.");
} }
if (revents & POLLERR) { if (revents & POLLERR) {
jack_error("JackALSARawMidiInputPort::ProcessPollEvents - an error "
"has occurred on the device or stream.");
jack_error("JackALSARawMidiPort::ProcessPollEvents - an error has "
"occurred on the device or stream.");
} }
return revents; return revents;
} }


+ 3
- 1
linux/alsarawmidi/JackALSARawMidiPort.h View File

@@ -30,7 +30,9 @@ namespace Jack {
public: public:


JackALSARawMidiPort(snd_rawmidi_info_t *info, size_t index); JackALSARawMidiPort(snd_rawmidi_info_t *info, size_t index);
virtual ~JackALSARawMidiPort();

virtual
~JackALSARawMidiPort();


const char * const char *
GetAlias(); GetAlias();


Loading…
Cancel
Save