diff --git a/libs/backends/coreaudio/coreaudio_backend.cc b/libs/backends/coreaudio/coreaudio_backend.cc index 0d8c91a680..5ceefae111 100644 --- a/libs/backends/coreaudio/coreaudio_backend.cc +++ b/libs/backends/coreaudio/coreaudio_backend.cc @@ -1067,7 +1067,7 @@ CoreAudioBackend::coremidi_rediscover() continue; } LatencyRange lr; - lr.min = lr.max = _samples_per_period; // TODO add per-port midi-systemic latency + lr.min = lr.max = 0; // TODO add per-port midi-systemic latency set_latency_range (p, false, lr); BackendPortPtr pp = std::dynamic_pointer_cast(p); pp->set_hw_port_name(_midiio->port_name(i, true)); @@ -1090,7 +1090,7 @@ CoreAudioBackend::coremidi_rediscover() continue; } LatencyRange lr; - lr.min = lr.max = _samples_per_period; // TODO add per-port midi-systemic latency + lr.min = lr.max = 0; // TODO add per-port midi-systemic latency set_latency_range (p, false, lr); BackendPortPtr pp = std::dynamic_pointer_cast(p); pp->set_hw_port_name(_midiio->port_name(i, false)); @@ -1098,7 +1098,6 @@ CoreAudioBackend::coremidi_rediscover() _port_change_flag.store (1); } - assert(_system_midi_out.size() == _midiio->n_midi_outputs()); assert(_system_midi_in.size() == _midiio->n_midi_inputs()); @@ -1236,14 +1235,25 @@ CoreAudioBackend::get_latency_range (PortEngine::PortHandle port_handle, bool fo } r = port->latency_range (for_playback); - if (port->is_physical() && port->is_terminal() && port->type() == DataType::AUDIO) { - if (port->is_input() && for_playback) { - r.min += _samples_per_period + _hw_audio_input_latency; - r.max += _samples_per_period + _hw_audio_input_latency; - } - if (port->is_output() && !for_playback) { - r.min += _samples_per_period + _hw_audio_output_latency; - r.max += _samples_per_period + _hw_audio_output_latency; + if (port->is_physical() && port->is_terminal()) { + if (port->type() == DataType::AUDIO) { + if (port->is_input() && for_playback) { + r.min += _samples_per_period + _hw_audio_input_latency; + r.max += _samples_per_period + _hw_audio_input_latency; + } + if (port->is_output() && !for_playback) { + r.min += _samples_per_period + _hw_audio_output_latency; + r.max += _samples_per_period + _hw_audio_output_latency; + } + } else { + if (port->is_input() && for_playback) { + //r.min += _samples_per_period; + //r.max += _samples_per_period; + } + if (port->is_output() && !for_playback) { + r.min += _samples_per_period; + r.max += _samples_per_period; + } } } return r; @@ -1440,11 +1450,12 @@ CoreAudioBackend::process_callback (const uint32_t n_samples, const uint64_t hos /* port-connection change */ pre_process(); - // cycle-length in usec - const double nominal_time = 1e6 * n_samples / _samplerate; - clock1 = g_get_monotonic_time(); + //_midiio->start_cycle (AudioGetCurrentHostTime (), 1e9 * n_samples / _samplerate); + _midiio->start_cycle (host_time, 1e9 * n_samples / _samplerate); + _last_process_start = host_time; + /* get midi */ i=0; for (std::vector::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) { @@ -1458,7 +1469,7 @@ CoreAudioBackend::process_callback (const uint32_t n_samples, const uint64_t hos port->clear_events (); - while (_midiio->recv_event (i, nominal_time, time_ns, data, size)) { + while (_midiio->recv_event (i, time_ns, data, size)) { pframes_t time = floor((float) time_ns * _samplerate * 1e-9); assert (time < n_samples); port->parse_events (time, data, size); @@ -1477,9 +1488,6 @@ CoreAudioBackend::process_callback (const uint32_t n_samples, const uint64_t hos memset ((*it)->get_buffer (n_samples), 0, n_samples * sizeof (Sample)); } - _midiio->start_cycle(); - _last_process_start = host_time; - if (engine.process_callback (n_samples)) { fprintf(stderr, "ENGINE PROCESS ERROR\n"); //_pcmio->pcm_stop (); @@ -1498,7 +1506,7 @@ CoreAudioBackend::process_callback (const uint32_t n_samples, const uint64_t hos for (std::vector::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it, ++i) { const CoreMidiBuffer *src = std::dynamic_pointer_cast(*it)->const_buffer(); for (CoreMidiBuffer::const_iterator mit = src->begin (); mit != src->end (); ++mit) { - _midiio->send_event (i, mit->timestamp (), mit->data (), mit->size ()); + _midiio->send_event (i, mit->timestamp () * 1e9 / _samplerate , mit->data (), mit->size ()); } } diff --git a/libs/backends/coreaudio/coremidi_io.cc b/libs/backends/coreaudio/coremidi_io.cc index d07ba1e7e5..9392a86011 100644 --- a/libs/backends/coreaudio/coremidi_io.cc +++ b/libs/backends/coreaudio/coremidi_io.cc @@ -103,7 +103,7 @@ static void midiInputCallback(const MIDIPacketList *list, void *procRef, void *s #endif if (rb->write_space() > sizeof(uint32_t) + len) { rb->write ((uint8_t*)&len, sizeof(uint32_t)); - rb->write ((uint8_t*)p, len); + rb->write ((uint8_t const*)p, len); } #ifndef NDEBUG else { @@ -144,7 +144,9 @@ CoreMidiIo::CoreMidiIo() , _rb (0) , _n_midi_in (0) , _n_midi_out (0) - , _time_at_cycle_start (0) + , _send_start (0) + , _recv_start (0) + , _recv_end (0) , _active (false) , _enabled (true) , _run (false) @@ -196,9 +198,17 @@ CoreMidiIo::cleanup() } void -CoreMidiIo::start_cycle() +CoreMidiIo::start_cycle (MIDITimeStamp time_at_cycle_start, double cycle_time_us) { - _time_at_cycle_start = AudioGetCurrentHostTime(); + _send_start = time_at_cycle_start; + _recv_end = time_at_cycle_start; + + MIDITimeStamp cycle_time = AudioConvertNanosToHostTime (cycle_time_us); + if (cycle_time <= time_at_cycle_start) { + _recv_start = time_at_cycle_start - cycle_time; + } else { + _recv_start = 0; + } } void @@ -242,9 +252,9 @@ CoreMidiIo::notify_proc(const MIDINotification *message) } size_t -CoreMidiIo::recv_event (uint32_t port, double cycle_time_us, uint64_t &time, uint8_t *d, size_t &s) +CoreMidiIo::recv_event (uint32_t port, uint64_t &time, uint8_t *d, size_t &s) { - if (!_active || _time_at_cycle_start == 0) { + if (!_active || _recv_start == 0) { return 0; } assert(port < _n_midi_in); @@ -266,18 +276,15 @@ CoreMidiIo::recv_event (uint32_t port, double cycle_time_us, uint64_t &time, uin _input_queue[port].push_back(std::shared_ptr(new _CoreMIDIPacket ((MIDIPacket*)&packet))); } - UInt64 start = _time_at_cycle_start; - UInt64 end = AudioConvertNanosToHostTime(AudioConvertHostTimeToNanos(_time_at_cycle_start) + cycle_time_us * 1e3); - for (CoreMIDIQueue::iterator it = _input_queue[port].begin (); it != _input_queue[port].end (); ) { - if ((*it)->timeStamp < end) { - if ((*it)->timeStamp < start) { - uint64_t dt = AudioConvertHostTimeToNanos(start - (*it)->timeStamp); + if ((*it)->timeStamp < _recv_end) { + if ((*it)->timeStamp < _recv_start) { + uint64_t dt = AudioConvertHostTimeToNanos(_recv_start - (*it)->timeStamp); /* note: it used to be 10ms (insert handwavy explanation about percievable latency) * turns out some midi-keyboads connected via bluetooth can be late by as much as 50ms * https://discourse.ardour.org/t/ardour-not-getting-all-messages-from-midi-keyboard/107618/13? */ - if (dt > 6e7 && (*it)->timeStamp != 0) { // 60ms slack and a timestamp is given + if (dt > 8e7 && (*it)->timeStamp != 0) { // 60ms slack and a timestamp is given #ifndef NDEBUG printf("Dropped Stale Midi Event. dt:%.2fms\n", dt * 1e-6); #endif @@ -298,7 +305,7 @@ CoreMidiIo::recv_event (uint32_t port, double cycle_time_us, uint64_t &time, uin } time = 0; } else { - time = AudioConvertHostTimeToNanos((*it)->timeStamp - start); + time = AudioConvertHostTimeToNanos((*it)->timeStamp - _recv_start); } s = std::min(s, (size_t) (*it)->length); if (s > 0) { @@ -308,7 +315,7 @@ CoreMidiIo::recv_event (uint32_t port, double cycle_time_us, uint64_t &time, uin return s; } else { #ifndef NDEBUG - uint64_t dt = AudioConvertHostTimeToNanos((*it)->timeStamp - end); + uint64_t dt = AudioConvertHostTimeToNanos((*it)->timeStamp - _recv_end); printf("Postponed future Midi Event. dt:%.2fms\n", dt * 1e-6); #endif } @@ -319,15 +326,15 @@ CoreMidiIo::recv_event (uint32_t port, double cycle_time_us, uint64_t &time, uin } int -CoreMidiIo::send_event (uint32_t port, double reltime_us, const uint8_t *d, const size_t s) +CoreMidiIo::send_event (uint32_t port, double reltime_ns, const uint8_t *d, const size_t s) { - if (!_active || _time_at_cycle_start == 0) { + if (!_active || _send_start == 0) { return 0; } assert(port < _n_midi_out); - UInt64 ts = AudioConvertHostTimeToNanos(_time_at_cycle_start); - ts += reltime_us * 1e3; + UInt64 ts = AudioConvertHostTimeToNanos(_send_start); + ts += reltime_ns; // TODO use a single packet list.. queue all events first.. MIDIPacketList pl; diff --git a/libs/backends/coreaudio/coremidi_io.h b/libs/backends/coreaudio/coremidi_io.h index 7019b3161d..84339d58a5 100644 --- a/libs/backends/coreaudio/coremidi_io.h +++ b/libs/backends/coreaudio/coremidi_io.h @@ -72,10 +72,10 @@ public: void start (); void stop (); - void start_cycle (); + void start_cycle (MIDITimeStamp, double cycle_ns); int send_event (uint32_t, double, const uint8_t *, const size_t); - size_t recv_event (uint32_t, double, uint64_t &, uint8_t *, size_t &); + size_t recv_event (uint32_t, uint64_t &, uint8_t *, size_t &); uint32_t n_midi_inputs (void) const { return _n_midi_in; } uint32_t n_midi_outputs (void) const { return _n_midi_out; } @@ -108,7 +108,9 @@ private: uint32_t _n_midi_in; uint32_t _n_midi_out; - MIDITimeStamp _time_at_cycle_start; + MIDITimeStamp _send_start; + MIDITimeStamp _recv_start; + MIDITimeStamp _recv_end; bool _active; // internal deactivate during discovery etc bool _enabled; // temporary disable, e.g. during freewheeli bool _run; // general status