00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <cassert>
00021
00022 #include "JackError.h"
00023 #include "JackPhysicalMidiOutput.h"
00024
00025 namespace Jack {
00026
00027 JackPhysicalMidiOutput::JackPhysicalMidiOutput(size_t non_rt_buffer_size,
00028 size_t rt_buffer_size)
00029 {
00030 size_t datum_size = sizeof(jack_midi_data_t);
00031 assert(non_rt_buffer_size > 0);
00032 assert(rt_buffer_size > 0);
00033 output_ring = jack_ringbuffer_create((non_rt_buffer_size + 1) *
00034 datum_size);
00035 if (! output_ring) {
00036 throw std::bad_alloc();
00037 }
00038 rt_output_ring = jack_ringbuffer_create((rt_buffer_size + 1) *
00039 datum_size);
00040 if (! rt_output_ring) {
00041 jack_ringbuffer_free(output_ring);
00042 throw std::bad_alloc();
00043 }
00044 jack_ringbuffer_mlock(output_ring);
00045 jack_ringbuffer_mlock(rt_output_ring);
00046 running_status = 0;
00047 }
00048
00049 JackPhysicalMidiOutput::~JackPhysicalMidiOutput()
00050 {
00051 jack_ringbuffer_free(output_ring);
00052 jack_ringbuffer_free(rt_output_ring);
00053 }
00054
00055 jack_nframes_t
00056 JackPhysicalMidiOutput::Advance(jack_nframes_t frame)
00057 {
00058 return frame;
00059 }
00060
00061 inline jack_midi_data_t
00062 JackPhysicalMidiOutput::ApplyRunningStatus(jack_midi_data_t **buffer,
00063 size_t *size)
00064 {
00065
00066
00067
00068 jack_midi_data_t status = (*buffer)[0];
00069 if ((status >= 0x80) && (status < 0xf0)) {
00070 if (status == running_status) {
00071 (*buffer)++;
00072 (*size)--;
00073 } else {
00074 running_status = status;
00075 }
00076 } else if (status < 0xf8) {
00077 running_status = 0;
00078 }
00079 return status;
00080 }
00081
00082 void
00083 JackPhysicalMidiOutput::HandleEventLoss(JackMidiEvent *event)
00084 {
00085 jack_error("%d byte MIDI event lost", event->size);
00086 }
00087
00088 void
00089 JackPhysicalMidiOutput::Process(jack_nframes_t frames)
00090 {
00091 assert(port_buffer);
00092 jack_nframes_t current_frame = Advance(0);
00093 jack_nframes_t current_midi_event = 0;
00094 jack_midi_data_t datum;
00095 size_t datum_size = sizeof(jack_midi_data_t);
00096 JackMidiEvent *midi_event;
00097 jack_midi_data_t *midi_event_buffer;
00098 size_t midi_event_size;
00099 jack_nframes_t midi_events = port_buffer->event_count;
00100
00101
00102
00103 if ((current_frame < frames) &&
00104 jack_ringbuffer_read_space(rt_output_ring)) {
00105
00106 jack_log("JackPhysicalMidiOutput::Process (%d) - Sending buffered "
00107 "realtime data from last period.", current_frame);
00108
00109 current_frame = SendBufferedData(rt_output_ring, current_frame,
00110 frames);
00111
00112 jack_log("JackPhysicalMidiOutput::Process (%d) - Sent", current_frame);
00113
00114 }
00115
00116
00117
00118 for (; (current_midi_event < midi_events) && (current_frame < frames);
00119 current_midi_event++) {
00120
00121
00122
00123
00124
00125 midi_event = &(port_buffer->events[current_midi_event]);
00126 jack_nframes_t midi_event_time = midi_event->time;
00127 midi_event_buffer = midi_event->GetData(port_buffer);
00128 midi_event_size = midi_event->size;
00129 datum = ApplyRunningStatus(&midi_event_buffer, &midi_event_size);
00130 if (current_frame < midi_event_time) {
00131
00132
00133
00134
00135 if (jack_ringbuffer_read_space(output_ring)) {
00136
00137 jack_log("JackPhysicalMidiOutput::Process (%d) - Sending "
00138 "buffered non-realtime data from last period.",
00139 current_frame);
00140
00141 current_frame = SendBufferedData(output_ring, current_frame,
00142 midi_event_time);
00143
00144 jack_log("JackPhysicalMidiOutput::Process (%d) - Sent",
00145 current_frame);
00146
00147 }
00148 if (current_frame < midi_event_time) {
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158 if (midi_event_size > 1) {
00159 if (jack_ringbuffer_write_space(output_ring) <
00160 ((midi_event_size - 1) * datum_size)) {
00161 HandleEventLoss(midi_event);
00162 continue;
00163 }
00164
00165
00166
00167
00168 do {
00169
00170 jack_log("JackPhysicalMidiOutput::Process (%d) - "
00171 "Sending unbuffered event byte early.",
00172 current_frame);
00173
00174 current_frame = Send(current_frame,
00175 *midi_event_buffer);
00176
00177 jack_log("JackPhysicalMidiOutput::Process (%d) - "
00178 "Sent.", current_frame);
00179
00180 midi_event_buffer++;
00181 midi_event_size--;
00182 if (current_frame >= midi_event_time) {
00183
00184
00185
00186
00187
00188 goto buffer_non_realtime_data;
00189 }
00190 } while (midi_event_size > 1);
00191 }
00192
00193 jack_log("JackPhysicalMidiOutput::Process (%d) - Advancing to "
00194 ">= %d", current_frame, midi_event_time);
00195
00196 current_frame = Advance(midi_event_time);
00197
00198 jack_log("JackPhysicalMidiOutput::Process (%d) - Advanced.",
00199 current_frame);
00200
00201 }
00202 }
00203
00204
00205
00206
00207
00208 if (datum >= 0xf8) {
00209
00210 jack_log("JackPhysicalMidiOutput::Process (%d) - Sending "
00211 "unbuffered realtime event.", current_frame);
00212
00213 current_frame = Send(current_frame, datum);
00214
00215 jack_log("JackPhysicalMidiOutput::Process (%d) - Sent.",
00216 current_frame);
00217
00218 } else if (jack_ringbuffer_write_space(output_ring) >=
00219 (midi_event_size * datum_size)) {
00220 buffer_non_realtime_data:
00221
00222 jack_log("JackPhysicalMidiOutput::Process (%d) - Buffering %d "
00223 "byte(s) of non-realtime data.", current_frame,
00224 midi_event_size);
00225
00226 jack_ringbuffer_write(output_ring,
00227 (const char *) midi_event_buffer,
00228 midi_event_size);
00229 } else {
00230 HandleEventLoss(midi_event);
00231 }
00232 }
00233
00234 if (current_frame < frames) {
00235
00236
00237
00238
00239
00240
00241
00242 if (jack_ringbuffer_read_space(output_ring)) {
00243
00244 jack_log("JackPhysicalMidiOutput::Process (%d) - All events "
00245 "processed. Sending buffered non-realtime data.",
00246 current_frame);
00247
00248 current_frame = SendBufferedData(output_ring, current_frame,
00249 frames);
00250
00251 jack_log("JackPhysicalMidiOutput::Process (%d) - Sent.",
00252 current_frame);
00253
00254 }
00255 } else {
00256
00257
00258
00259
00260 for (; current_midi_event < midi_events; current_midi_event++) {
00261 midi_event = &(port_buffer->events[current_midi_event]);
00262 midi_event_buffer = midi_event->GetData(port_buffer);
00263 midi_event_size = midi_event->size;
00264 datum = ApplyRunningStatus(&midi_event_buffer, &midi_event_size);
00265 if (datum >= 0xf8) {
00266
00267
00268
00269 if (jack_ringbuffer_write_space(rt_output_ring) >=
00270 datum_size) {
00271
00272 jack_log("JackPhysicalMidiOutput::Process - Buffering "
00273 "realtime event for next period.");
00274
00275 jack_ringbuffer_write(rt_output_ring,
00276 (const char *) &datum, datum_size);
00277 continue;
00278 }
00279 } else {
00280
00281
00282
00283 if (jack_ringbuffer_write_space(output_ring) >=
00284 (midi_event_size * datum_size)) {
00285
00286 jack_log("JackPhysicalMidiOutput::Process - Buffering "
00287 "non-realtime event for next period.");
00288
00289 jack_ringbuffer_write(output_ring,
00290 (const char *) midi_event_buffer,
00291 midi_event_size * datum_size);
00292 continue;
00293 }
00294 }
00295 HandleEventLoss(midi_event);
00296 }
00297 }
00298 }
00299
00300 jack_nframes_t
00301 JackPhysicalMidiOutput::SendBufferedData(jack_ringbuffer_t *buffer,
00302 jack_nframes_t current_frame,
00303 jack_nframes_t boundary)
00304 {
00305 assert(buffer);
00306 assert(current_frame < boundary);
00307 size_t datum_size = sizeof(jack_midi_data_t);
00308 size_t data_length = jack_ringbuffer_read_space(buffer) / datum_size;
00309 for (size_t i = 0; i < data_length; i++) {
00310 jack_midi_data_t datum;
00311 jack_ringbuffer_read(buffer, (char *) &datum, datum_size);
00312 current_frame = Send(current_frame, datum);
00313 if (current_frame >= boundary) {
00314 break;
00315 }
00316 }
00317 return current_frame;
00318 }
00319
00320 }