2 Copyright (C) 2007 Dmitry Baikov
3 Copyright (C) 2018 Filipe Coelho
4 Original JACK MIDI implementation Copyright (C) 2004 Ian Esten
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #include "JackError.h"
23 #include "JackPortType.h"
24 #include "JackMidiPort.h"
31 SERVER_EXPORT
void JackMidiBuffer::Reset(jack_nframes_t nframes
)
33 /* This line ate 1 hour of my life... dsbaikov */
34 this->nframes
= nframes
;
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
);
47 if (left
<= JackMidiEvent::INLINE_SIZE_MAX
) {
48 return JackMidiEvent::INLINE_SIZE_MAX
;
53 SERVER_EXPORT jack_midi_data_t
* JackMidiBuffer::ReserveEvent(jack_nframes_t time
, jack_shmsize_t size
)
55 jack_shmsize_t space
= MaxEventSize();
56 if (space
== 0 || size
> space
) {
57 jack_error("JackMidiBuffer::ReserveEvent - the buffer does not have "
58 "enough room to enqueue a %lu byte event", size
);
62 JackMidiEvent
* event
= &events
[event_count
++];
66 if (size
<= JackMidiEvent::INLINE_SIZE_MAX
) {
71 event
->offset
= buffer_size
- write_pos
;
72 return (jack_midi_data_t
*)this + event
->offset
;
75 void MidiBufferInit(void* buffer
, size_t buffer_size
, jack_nframes_t nframes
)
77 JackMidiBuffer
* midi
= (JackMidiBuffer
*)buffer
;
78 midi
->magic
= JackMidiBuffer::MAGIC
;
79 /* Since port buffer has actually always BUFFER_SIZE_MAX frames, we can safely use all the size */
80 midi
->buffer_size
= BUFFER_SIZE_MAX
* sizeof(jack_default_audio_sample_t
);
85 * The mixdown function below, is a simplest (read slowest) implementation possible.
86 * But, since it is unlikely that it will mix many buffers with many events,
87 * it should perform quite good.
88 * More efficient (and possibly, fastest possible) implementation (it exists),
89 * using calendar queue algorithm is about 3 times bigger, and uses alloca().
90 * So, let's listen to D.Knuth about premature optimisation, a leave the current
91 * implementation as is, until it is proved to be a bottleneck.
94 static void MidiBufferMixdown(void* mixbuffer
, void** src_buffers
, int src_count
, jack_nframes_t nframes
)
96 JackMidiBuffer
* mix
= static_cast<JackMidiBuffer
*>(mixbuffer
);
97 if (!mix
->IsValid()) {
98 jack_error("Jack::MidiBufferMixdown - invalid mix buffer");
103 uint32_t mix_index
[src_count
];
105 for (int i
= 0; i
< src_count
; ++i
) {
106 JackMidiBuffer
* buf
= static_cast<JackMidiBuffer
*>(src_buffers
[i
]);
107 if (!buf
->IsValid()) {
108 jack_error("Jack::MidiBufferMixdown - invalid source buffer");
112 event_count
+= buf
->event_count
;
113 mix
->lost_events
+= buf
->lost_events
;
117 for (events_done
= 0; events_done
< event_count
; ++events_done
) {
118 JackMidiBuffer
* next_buf
= 0;
119 JackMidiEvent
* next_event
= 0;
120 uint32_t next_buf_index
= 0;
122 // find the earliest event
123 for (int i
= 0; i
< src_count
; ++i
) {
124 JackMidiBuffer
* buf
= static_cast<JackMidiBuffer
*>(src_buffers
[i
]);
125 if (mix_index
[i
] >= buf
->event_count
)
127 JackMidiEvent
* e
= &buf
->events
[mix_index
[i
]];
128 if (!next_event
|| e
->time
< next_event
->time
) {
134 if (next_event
== 0) {
135 jack_error("Jack::MidiBufferMixdown - got invalid next event");
140 jack_midi_data_t
* dest
= mix
->ReserveEvent(next_event
->time
, next_event
->size
);
143 memcpy(dest
, next_event
->GetData(next_buf
), next_event
->size
);
144 mix_index
[next_buf_index
]++;
146 mix
->lost_events
+= event_count
- events_done
;
149 static size_t MidiBufferSize()
151 return BUFFER_SIZE_MAX
* sizeof(jack_default_audio_sample_t
);
154 const JackPortType gMidiPortType
=
156 JACK_DEFAULT_MIDI_TYPE
,