| 
							- /*
 - Copyright (C) 2009 Devin Anderson
 - 
 - This program is free software; you can redistribute it and/or modify
 - it under the terms of the GNU Lesser General Public License as published by
 - the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
 - 
 - You should have received a copy of the GNU Lesser General Public License
 - along with this program; if not, write to the Free Software
 - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 - 
 - */
 - 
 - #include <cassert>
 - 
 - #include "JackError.h"
 - #include "JackPhysicalMidiOutput.h"
 - 
 - namespace Jack {
 - 
 - JackPhysicalMidiOutput::JackPhysicalMidiOutput(size_t non_rt_buffer_size,
 -                                                size_t rt_buffer_size)
 - {
 -     size_t datum_size = sizeof(jack_midi_data_t);
 -     assert(non_rt_buffer_size > 0);
 -     assert(rt_buffer_size > 0);
 -     output_ring = jack_ringbuffer_create((non_rt_buffer_size + 1) *
 -                                          datum_size);
 -     if (! output_ring) {
 -         throw std::bad_alloc();
 -     }
 -     rt_output_ring = jack_ringbuffer_create((rt_buffer_size + 1) *
 -                                             datum_size);
 -     if (! rt_output_ring) {
 -         jack_ringbuffer_free(output_ring);
 -         throw std::bad_alloc();
 -     }
 -     jack_ringbuffer_mlock(output_ring);
 -     jack_ringbuffer_mlock(rt_output_ring);
 -     running_status = 0;
 - }
 - 
 - JackPhysicalMidiOutput::~JackPhysicalMidiOutput()
 - {
 -     jack_ringbuffer_free(output_ring);
 -     jack_ringbuffer_free(rt_output_ring);
 - }
 - 
 - jack_nframes_t
 - JackPhysicalMidiOutput::Advance(jack_nframes_t frame)
 - {
 -     return frame;
 - }
 - 
 - inline jack_midi_data_t
 - JackPhysicalMidiOutput::ApplyRunningStatus(jack_midi_data_t **buffer,
 -                                            size_t *size)
 - {
 - 
 -     // Stolen and modified from alsa/midi_pack.h
 - 
 -     jack_midi_data_t status = (*buffer)[0];
 -     if ((status >= 0x80) && (status < 0xf0)) {
 -         if (status == running_status) {
 -             (*buffer)++;
 -             (*size)--;
 -         } else {
 -             running_status = status;
 -         }
 -     } else if (status < 0xf8) {
 -         running_status = 0;
 -     }
 -     return status;
 - }
 - 
 - void
 - JackPhysicalMidiOutput::HandleEventLoss(JackMidiEvent *event)
 - {
 -     jack_error("%d byte MIDI event lost", event->size);
 - }
 - 
 - void
 - JackPhysicalMidiOutput::Process(jack_nframes_t frames)
 - {
 -     assert(port_buffer);
 -     jack_nframes_t current_frame = Advance(0);
 -     jack_nframes_t current_midi_event = 0;
 -     jack_midi_data_t datum;
 -     size_t datum_size = sizeof(jack_midi_data_t);
 -     JackMidiEvent *midi_event;
 -     jack_midi_data_t *midi_event_buffer;
 -     size_t midi_event_size;
 -     jack_nframes_t midi_events = port_buffer->event_count;
 - 
 -     // First, send any realtime MIDI data that's left from last cycle.
 - 
 -     if ((current_frame < frames) &&
 -         jack_ringbuffer_read_space(rt_output_ring)) {
 - 
 -         jack_log("JackPhysicalMidiOutput::Process (%d) - Sending buffered "
 -                  "realtime data from last period.", current_frame);
 - 
 -         current_frame = SendBufferedData(rt_output_ring, current_frame,
 -                                          frames);
 - 
 -         jack_log("JackPhysicalMidiOutput::Process (%d) - Sent", current_frame);
 - 
 -     }
 - 
 -     // Iterate through the events in this cycle.
 - 
 -     for (; (current_midi_event < midi_events) && (current_frame < frames);
 -          current_midi_event++) {
 - 
 -         // Once we're inside this loop, we know that the realtime buffer
 -         // is empty.  As long as we don't find a realtime message, we can
 -         // concentrate on sending non-realtime data.
 - 
 -         midi_event = &(port_buffer->events[current_midi_event]);
 -         jack_nframes_t midi_event_time = midi_event->time;
 -         midi_event_buffer = midi_event->GetData(port_buffer);
 -         midi_event_size = midi_event->size;
 -         datum = ApplyRunningStatus(&midi_event_buffer, &midi_event_size);
 -         if (current_frame < midi_event_time) {
 - 
 -             // We have time before this event is scheduled to be sent.
 -             // Send data in the non-realtime buffer.
 - 
 -             if (jack_ringbuffer_read_space(output_ring)) {
 - 
 -                 jack_log("JackPhysicalMidiOutput::Process (%d) - Sending "
 -                          "buffered non-realtime data from last period.",
 -                          current_frame);
 - 
 -                 current_frame = SendBufferedData(output_ring, current_frame,
 -                                                  midi_event_time);
 - 
 -                 jack_log("JackPhysicalMidiOutput::Process (%d) - Sent",
 -                          current_frame);
 - 
 -             }
 -             if (current_frame < midi_event_time) {
 - 
 -                 // We _still_ have time before this event is scheduled to
 -                 // be sent.  Let's send as much of this event as we can
 -                 // (save for one byte, which will need to be sent at or
 -                 // after its scheduled time).  First though, we need to
 -                 // make sure that we can buffer this data if we need to.
 -                 // Otherwise, we might start sending a message that we
 -                 // can't finish.
 - 
 -                 if (midi_event_size > 1) {
 -                     if (jack_ringbuffer_write_space(output_ring) <
 -                         ((midi_event_size - 1) * datum_size)) {
 -                         HandleEventLoss(midi_event);
 -                         continue;
 -                     }
 - 
 -                     // Send as much of the event as possible (save for one
 -                     // byte).
 - 
 -                     do {
 - 
 -                         jack_log("JackPhysicalMidiOutput::Process (%d) - "
 -                                  "Sending unbuffered event byte early.",
 -                                  current_frame);
 - 
 -                         current_frame = Send(current_frame,
 -                                              *midi_event_buffer);
 - 
 -                         jack_log("JackPhysicalMidiOutput::Process (%d) - "
 -                                  "Sent.", current_frame);
 - 
 -                         midi_event_buffer++;
 -                         midi_event_size--;
 -                         if (current_frame >= midi_event_time) {
 - 
 -                             // The event we're processing must be a
 -                             // non-realtime event.  It has more than one
 -                             // byte.
 - 
 -                             goto buffer_non_realtime_data;
 -                         }
 -                     } while (midi_event_size > 1);
 -                 }
 - 
 -                 jack_log("JackPhysicalMidiOutput::Process (%d) - Advancing to "
 -                          ">= %d", current_frame, midi_event_time);
 - 
 -                 current_frame = Advance(midi_event_time);
 - 
 -                 jack_log("JackPhysicalMidiOutput::Process (%d) - Advanced.",
 -                          current_frame);
 - 
 -             }
 -         }
 - 
 -         // If the event is realtime, then we'll send the event now.
 -         // Otherwise, we attempt to put the rest of the event bytes in the
 -         // non-realtime buffer.
 - 
 -         if (datum >= 0xf8) {
 - 
 -             jack_log("JackPhysicalMidiOutput::Process (%d) - Sending "
 -                      "unbuffered realtime event.", current_frame);
 - 
 -             current_frame = Send(current_frame, datum);
 - 
 -             jack_log("JackPhysicalMidiOutput::Process (%d) - Sent.",
 -                      current_frame);
 - 
 -         } else if (jack_ringbuffer_write_space(output_ring) >=
 -                    (midi_event_size * datum_size)) {
 -         buffer_non_realtime_data:
 - 
 -             jack_log("JackPhysicalMidiOutput::Process (%d) - Buffering %d "
 -                      "byte(s) of non-realtime data.", current_frame,
 -                      midi_event_size);
 - 
 -             jack_ringbuffer_write(output_ring,
 -                                   (const char *) midi_event_buffer,
 -                                   midi_event_size);
 -         } else {
 -             HandleEventLoss(midi_event);
 -         }
 -     }
 - 
 -     if (current_frame < frames) {
 - 
 -         // If we have time left to send data, then we know that all of the
 -         // data in the realtime buffer has been sent, and that all of the
 -         // non-realtime messages have either been sent, or buffered.  We
 -         // use whatever time is left to send data in the non-realtime
 -         // buffer.
 - 
 -         if (jack_ringbuffer_read_space(output_ring)) {
 - 
 -             jack_log("JackPhysicalMidiOutput::Process (%d) - All events "
 -                      "processed.  Sending buffered non-realtime data.",
 -                      current_frame);
 - 
 -             current_frame = SendBufferedData(output_ring, current_frame,
 -                                              frames);
 - 
 -             jack_log("JackPhysicalMidiOutput::Process (%d) - Sent.",
 -                      current_frame);
 - 
 -         }
 -     } else {
 - 
 -         // Since we have no time left, we need to put all remaining midi
 -         // events in their appropriate buffers, and send them next period.
 - 
 -         for (; current_midi_event < midi_events; current_midi_event++) {
 -             midi_event = &(port_buffer->events[current_midi_event]);
 -             midi_event_buffer = midi_event->GetData(port_buffer);
 -             midi_event_size = midi_event->size;
 -             datum = ApplyRunningStatus(&midi_event_buffer, &midi_event_size);
 -             if (datum >= 0xf8) {
 - 
 -                 // Realtime.
 - 
 -                 if (jack_ringbuffer_write_space(rt_output_ring) >=
 -                     datum_size) {
 - 
 -                     jack_log("JackPhysicalMidiOutput::Process - Buffering "
 -                              "realtime event for next period.");
 - 
 -                     jack_ringbuffer_write(rt_output_ring,
 -                                           (const char *) &datum, datum_size);
 -                     continue;
 -                 }
 -             } else {
 - 
 -                 // Non-realtime.
 - 
 -                 if (jack_ringbuffer_write_space(output_ring) >=
 -                     (midi_event_size * datum_size)) {
 - 
 -                     jack_log("JackPhysicalMidiOutput::Process - Buffering "
 -                              "non-realtime event for next period.");
 - 
 -                     jack_ringbuffer_write(output_ring,
 -                                           (const char *) midi_event_buffer,
 -                                           midi_event_size * datum_size);
 -                     continue;
 -                 }
 -             }
 -             HandleEventLoss(midi_event);
 -         }
 -     }
 - }
 - 
 - jack_nframes_t
 - JackPhysicalMidiOutput::SendBufferedData(jack_ringbuffer_t *buffer,
 -                                          jack_nframes_t current_frame,
 -                                          jack_nframes_t boundary)
 - {
 -     assert(buffer);
 -     assert(current_frame < boundary);
 -     size_t datum_size = sizeof(jack_midi_data_t);
 -     size_t data_length = jack_ringbuffer_read_space(buffer) / datum_size;
 -     for (size_t i = 0; i < data_length; i++) {
 -         jack_midi_data_t datum;
 -         jack_ringbuffer_read(buffer, (char *) &datum, datum_size);
 -         current_frame = Send(current_frame, datum);
 -         if (current_frame >= boundary) {
 -             break;
 -         }
 -     }
 -     return current_frame;
 - }
 - 
 - }
 
 
  |