Init engine fields, cleanup.
[jack2.git] / common / JackMidiPort.cpp
blobfb933c8566e87ef93b688ca1dcaf7947d7f97944
1 /*
2 Copyright (C) 2007 Dmitry Baikov
3 Original JACK MIDI implementation Copyright (C) 2004 Ian Esten
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #include "JackError.h"
22 #include "JackPortType.h"
23 #include "JackMidiPort.h"
24 #include <assert.h>
25 #include <string.h>
27 namespace Jack
30 SERVER_EXPORT void JackMidiBuffer::Reset(jack_nframes_t nframes)
32 /* This line ate 1 hour of my life... dsbaikov */
33 this->nframes = nframes;
34 write_pos = 0;
35 event_count = 0;
36 lost_events = 0;
37 mix_index = 0;
40 SERVER_EXPORT jack_shmsize_t JackMidiBuffer::MaxEventSize() const
42 assert (((jack_shmsize_t) - 1) < 0); // jack_shmsize_t should be signed
43 jack_shmsize_t left = buffer_size - (sizeof(JackMidiBuffer) + sizeof(JackMidiEvent) * (event_count + 1) + write_pos);
44 if (left < 0)
45 return 0;
46 if (left <= JackMidiEvent::INLINE_SIZE_MAX)
47 return JackMidiEvent::INLINE_SIZE_MAX;
48 return left;
51 SERVER_EXPORT jack_midi_data_t* JackMidiBuffer::ReserveEvent(jack_nframes_t time, jack_shmsize_t size)
53 jack_shmsize_t space = MaxEventSize();
54 if (space == 0 || size > space) {
55 lost_events++;
56 return 0;
59 JackMidiEvent* event = &events[event_count++];
60 event->time = time;
61 event->size = size;
62 if (size <= JackMidiEvent::INLINE_SIZE_MAX)
63 return event->data;
65 write_pos += size;
66 event->offset = buffer_size - write_pos;
67 return (jack_midi_data_t*)this + event->offset;
70 static void MidiBufferInit(void* buffer, size_t buffer_size, jack_nframes_t nframes)
72 JackMidiBuffer* midi = (JackMidiBuffer*)buffer;
73 midi->magic = JackMidiBuffer::MAGIC;
74 /* Since port buffer has actually always BUFFER_SIZE_MAX frames, we can safely use all the size */
75 midi->buffer_size = BUFFER_SIZE_MAX * sizeof(float);
76 midi->Reset(nframes);
80 * The mixdown function below, is a simplest (read slowest) implementation possible.
81 * But, since it is unlikely that it will mix many buffers with many events,
82 * it should perform quite good.
83 * More efficient (and possibly, fastest possible) implementation (it exists),
84 * using calendar queue algorithm is about 3 times bigger, and uses alloca().
85 * So, let's listen to D.Knuth about premature optimisation, a leave the current
86 * implementation as is, until it is proved to be a bottleneck.
87 * Dmitry Baikov.
89 static void MidiBufferMixdown(void* mixbuffer, void** src_buffers, int src_count, jack_nframes_t nframes)
91 JackMidiBuffer* mix = static_cast<JackMidiBuffer*>(mixbuffer);
92 if (!mix->IsValid()) {
93 jack_error("MIDI: invalid mix buffer");
94 return;
96 mix->Reset(nframes);
98 int event_count = 0;
99 for (int i = 0; i < src_count; ++i) {
100 JackMidiBuffer* buf = static_cast<JackMidiBuffer*>(src_buffers[i]);
101 if (!buf->IsValid())
102 return;
103 buf->mix_index = 0;
104 event_count += buf->event_count;
105 mix->lost_events += buf->lost_events;
108 int events_done;
109 for (events_done = 0; events_done < event_count; ++events_done) {
110 JackMidiBuffer* next_buf = 0;
111 JackMidiEvent* next_event = 0;
113 // find the earliest event
114 for (int i = 0; i < src_count; ++i) {
115 JackMidiBuffer* buf = static_cast<JackMidiBuffer*>(src_buffers[i]);
116 if (buf->mix_index >= buf->event_count)
117 continue;
118 JackMidiEvent* e = &buf->events[buf->mix_index];
119 if (!next_event || e->time < next_event->time) {
120 next_event = e;
121 next_buf = buf;
124 assert(next_event != 0);
126 // write the event
127 jack_midi_data_t* dest = mix->ReserveEvent(next_event->time, next_event->size);
128 if (!dest)
129 break;
130 memcpy(dest, next_event->GetData(next_buf), next_event->size);
131 next_buf->mix_index++;
133 mix->lost_events += event_count - events_done;
136 const JackPortType gMidiPortType =
138 JACK_DEFAULT_MIDI_TYPE,
139 MidiBufferInit,
140 MidiBufferMixdown
143 } // namespace Jack