| 
							- /*
 - Copyright (C) 2007 Dmitry Baikov
 - Original JACK MIDI implementation Copyright (C) 2004 Ian Esten
 - 
 - 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 "JackError.h"
 - #include "JackPortType.h"
 - #include "JackMidiPort.h"
 - #include <assert.h>
 - #include <string.h>
 - 
 - namespace Jack
 - {
 - 
 - SERVER_EXPORT void JackMidiBuffer::Reset(jack_nframes_t nframes)
 - {
 -     /* This line ate 1 hour of my life... dsbaikov */
 -     this->nframes = nframes;
 -     write_pos = 0;
 -     event_count = 0;
 -     lost_events = 0;
 -     mix_index = 0;
 - }
 - 
 - SERVER_EXPORT jack_shmsize_t JackMidiBuffer::MaxEventSize() const
 - {
 -     assert (((jack_shmsize_t) - 1) < 0); // jack_shmsize_t should be signed
 -     jack_shmsize_t left = buffer_size - (sizeof(JackMidiBuffer) + sizeof(JackMidiEvent) * (event_count + 1) + write_pos);
 -     if (left < 0)
 -         return 0;
 -     if (left <= JackMidiEvent::INLINE_SIZE_MAX)
 -         return JackMidiEvent::INLINE_SIZE_MAX;
 -     return left;
 - }
 - 
 - SERVER_EXPORT jack_midi_data_t* JackMidiBuffer::ReserveEvent(jack_nframes_t time, jack_shmsize_t size)
 - {
 -     jack_shmsize_t space = MaxEventSize();
 -     if (space == 0 || size > space) {
 -         lost_events++;
 -         return 0;
 -     }
 - 
 -     JackMidiEvent* event = &events[event_count++];
 -     event->time = time;
 -     event->size = size;
 -     if (size <= JackMidiEvent::INLINE_SIZE_MAX)
 -         return event->data;
 - 
 -     write_pos += size;
 -     event->offset = buffer_size - write_pos;
 -     return (jack_midi_data_t*)this + event->offset;
 - }
 - 
 - static void MidiBufferInit(void* buffer, size_t buffer_size, jack_nframes_t nframes)
 - {
 -     JackMidiBuffer* midi = (JackMidiBuffer*)buffer;
 -     midi->magic = JackMidiBuffer::MAGIC;
 -     /* Since port buffer has actually always BUFFER_SIZE_MAX frames, we can safely use all the size */
 -     midi->buffer_size = BUFFER_SIZE_MAX * sizeof(jack_default_audio_sample_t);
 -     midi->Reset(nframes);
 - }
 - 
 - /*
 -  * The mixdown function below, is a simplest (read slowest) implementation possible.
 -  * But, since it is unlikely that it will mix many buffers with many events,
 -  * it should perform quite good.
 -  * More efficient (and possibly, fastest possible) implementation (it exists),
 -  * using calendar queue algorithm is about 3 times bigger, and uses alloca().
 -  * So, let's listen to D.Knuth about premature optimisation, a leave the current
 -  * implementation as is, until it is proved to be a bottleneck.
 -  * Dmitry Baikov.
 -  */
 - static void MidiBufferMixdown(void* mixbuffer, void** src_buffers, int src_count, jack_nframes_t nframes)
 - {
 -     JackMidiBuffer* mix = static_cast<JackMidiBuffer*>(mixbuffer);
 -     if (!mix->IsValid()) {
 -         jack_error("MIDI: invalid mix buffer");
 -         return;
 -     }
 -     mix->Reset(nframes);
 - 
 -     int event_count = 0;
 -     for (int i = 0; i < src_count; ++i) {
 -         JackMidiBuffer* buf = static_cast<JackMidiBuffer*>(src_buffers[i]);
 -         if (!buf->IsValid())
 -             return;
 -         buf->mix_index = 0;
 -         event_count += buf->event_count;
 -         mix->lost_events += buf->lost_events;
 -     }
 - 
 -     int events_done;
 -     for (events_done = 0; events_done < event_count; ++events_done) {
 -         JackMidiBuffer* next_buf = 0;
 -         JackMidiEvent* next_event = 0;
 - 
 -         // find the earliest event
 -         for (int i = 0; i < src_count; ++i) {
 -             JackMidiBuffer* buf = static_cast<JackMidiBuffer*>(src_buffers[i]);
 -             if (buf->mix_index >= buf->event_count)
 -                 continue;
 -             JackMidiEvent* e = &buf->events[buf->mix_index];
 -             if (!next_event || e->time < next_event->time) {
 -                 next_event = e;
 -                 next_buf = buf;
 -             }
 -         }
 -         assert(next_event != 0);
 - 
 -         // write the event
 -         jack_midi_data_t* dest = mix->ReserveEvent(next_event->time, next_event->size);
 -         if (!dest)
 -             break;
 -         memcpy(dest, next_event->GetData(next_buf), next_event->size);
 -         next_buf->mix_index++;
 -     }
 -     mix->lost_events += event_count - events_done;
 - }
 - 
 - static size_t MidiBufferSize()
 - {
 -     return BUFFER_SIZE_MAX * sizeof(jack_default_audio_sample_t);
 - }
 - 
 - const JackPortType gMidiPortType =
 - {
 -     JACK_DEFAULT_MIDI_TYPE,
 -     MidiBufferSize,
 -     MidiBufferInit,
 -     MidiBufferMixdown
 - };
 - 
 - } // namespace Jack
 
 
  |