JackALSARawMidiOutputPort.cpp
/*
Copyright (C) 2011 Devin Anderson
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <cassert>
#include <memory>
#include "JackALSARawMidiOutputPort.h"
#include "JackError.h"
using Jack::JackALSARawMidiOutputPort;
JackALSARawMidiOutputPort::JackALSARawMidiOutputPort(snd_rawmidi_info_t *info,
size_t index,
size_t max_bytes_per_poll,
size_t max_bytes,
size_t max_messages):
JackALSARawMidiPort(info, index, POLLOUT)
{
alsa_event = 0;
read_queue = new JackMidiBufferReadQueue();
std::auto_ptr<JackMidiBufferReadQueue> read_ptr(read_queue);
send_queue = new JackALSARawMidiSendQueue(rawmidi, max_bytes_per_poll);
std::auto_ptr<JackALSARawMidiSendQueue> send_ptr(send_queue);
thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages);
std::auto_ptr<JackMidiAsyncQueue> thread_ptr(thread_queue);
raw_queue = new JackMidiRawOutputWriteQueue(send_queue, max_bytes,
max_messages, max_messages);
thread_ptr.release();
send_ptr.release();
read_ptr.release();
}
JackALSARawMidiOutputPort::~JackALSARawMidiOutputPort()
{
delete raw_queue;
delete read_queue;
delete send_queue;
delete thread_queue;
}
bool
JackALSARawMidiOutputPort::ProcessJack(JackMidiBuffer *port_buffer,
jack_nframes_t frames)
{
read_queue->ResetMidiBuffer(port_buffer);
bool enqueued = false;
for (jack_midi_event_t *event = read_queue->DequeueEvent(); event;
event = read_queue->DequeueEvent()) {
switch (thread_queue->EnqueueEvent(event, frames)) {
case JackMidiWriteQueue::BUFFER_FULL:
jack_error("JackALSARawMidiOutputPort::ProcessJack - The thread "
"queue doesn't have enough room to enqueue a %d-byte "
"event. Dropping event.", event->size);
continue;
case JackMidiWriteQueue::BUFFER_TOO_SMALL:
jack_error("JackALSARawMidiOutputPort::ProcessJack - The thread "
"queue is too small to enqueue a %d-byte event. "
"Dropping event.", event->size);
continue;
default:
enqueued = true;
}
}
return enqueued ? TriggerQueueEvent() : true;
}
bool
JackALSARawMidiOutputPort::ProcessPollEvents(bool handle_output, bool timeout,
jack_nframes_t *frame)
{
int io_event;
int queue_event;
send_queue->ResetPollByteCount();
if (! handle_output) {
assert(timeout);
goto process_raw_queue;
}
io_event = GetIOPollEvent();
if (io_event == -1) {
return false;
}
queue_event = GetQueuePollEvent();
if (queue_event == -1) {
return false;
}
if (io_event || timeout) {
process_raw_queue:
// We call the 'Process' event early because there are events waiting
// to be processed that either need to be sent now, or before now.
raw_queue->Process();
} else if (! queue_event) {
return true;
}
if (! alsa_event) {
alsa_event = thread_queue->DequeueEvent();
}
for (; alsa_event; alsa_event = thread_queue->DequeueEvent()) {
switch (raw_queue->EnqueueEvent(alsa_event)) {
case JackMidiWriteQueue::BUFFER_TOO_SMALL:
jack_error("JackALSARawMidiOutputPort::ProcessQueues - The raw "
"output queue couldn't enqueue a %d-byte event. "
"Dropping event.", alsa_event->size);
// Fallthrough on purpose.
case JackMidiWriteQueue::OK:
continue;
default:
;
}
// Try to free up some space by processing events early.
*frame = raw_queue->Process();
switch (raw_queue->EnqueueEvent(alsa_event)) {
case JackMidiWriteQueue::BUFFER_FULL:
goto set_io_events;
case JackMidiWriteQueue::BUFFER_TOO_SMALL:
// This shouldn't happen.
assert(false);
default:
;
}
}
*frame = raw_queue->Process();
set_io_events:
bool blocked = send_queue->IsBlocked();
SetIOEventsEnabled(blocked);
if (blocked) {
*frame = 0;
}
return true;
}
Jack::JackMidiBufferReadQueue::DequeueEvent
jack_midi_event_t * DequeueEvent()
Definition: JackMidiBufferReadQueue.cpp:33
Jack::JackMidiBufferReadQueue::ResetMidiBuffer
void ResetMidiBuffer(JackMidiBuffer *buffer)
Definition: JackMidiBufferReadQueue.cpp:48
jack_error
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
jack_midi_event_t::size
size_t size
Definition: JackMidiPort.h:36
jack_midi_event_t
Definition: JackMidiPort.h:33
Jack::JackMidiRawOutputWriteQueue::EnqueueEvent
EnqueueResult EnqueueEvent(jack_nframes_t time, size_t size, jack_midi_data_t *buffer)
Definition: JackMidiRawOutputWriteQueue.cpp:73
Jack::JackMidiRawOutputWriteQueue::Process
jack_nframes_t Process(jack_nframes_t boundary_frame=0)
Definition: JackMidiRawOutputWriteQueue.cpp:92
Jack::JackMidiAsyncQueue::DequeueEvent
virtual jack_midi_event_t * DequeueEvent()
Definition: JackMidiAsyncQueue.cpp:53
Jack::JackALSARawMidiOutputPort
Definition: JackALSARawMidiOutputPort.h:31
Jack::JackMidiAsyncQueue::EnqueueEvent
virtual EnqueueResult EnqueueEvent(jack_nframes_t time, size_t size, jack_midi_data_t *buffer)
Definition: JackMidiAsyncQueue.cpp:72