2#include <ossia/dataflow/graph_node.hpp> 
    3#include <ossia/dataflow/node_process.hpp> 
    4#include <ossia/dataflow/port.hpp> 
    5#include <ossia/detail/flat_multiset.hpp> 
    7#include <libremidi/ump_events.hpp> 
   12using midi_size_t = uint8_t;
 
   16  time_value duration{};
 
   19  midi_size_t velocity{};
 
   24  using is_transparent = std::true_type;
 
   25  bool operator()(
const note_data& lhs, 
const note_data& rhs)
 const 
   27    return lhs.start < rhs.start;
 
   29  bool operator()(
const note_data& lhs, int64_t rhs)
 const 
   31    return lhs.start.impl < rhs;
 
   35class midi final : 
public ossia::nonowning_graph_node
 
   37  ossia::midi_outlet midi_out;
 
   40  using note_set = ossia::flat_multiset<note_data, note_comparator>;
 
   41  explicit midi(int64_t notes)
 
   43    m_outlets.push_back(&midi_out);
 
   44    int64_t to_reserve = std::max(notes * 1.1, 128.);
 
   45    m_notes.reserve(to_reserve);
 
   46    m_orig_notes.reserve(to_reserve);
 
   47    m_playing_notes.reserve(to_reserve);
 
   48    m_to_stop.reserve(64);
 
   51  ~midi() 
override = 
default;
 
   53  std::string label() const noexcept
 override { 
return "midi"; }
 
   55  void set_channel(
int c) { m_channel = c - 1; }
 
   57  void add_note(note_data nd)
 
   59    m_orig_notes.insert(nd);
 
   60    if(nd.start > m_prev_date)
 
   66  void remove_note(note_data nd)
 
   68    m_orig_notes.erase(nd);
 
   70    auto it = m_playing_notes.find(nd);
 
   71    if(it != m_playing_notes.end())
 
   74      m_playing_notes.erase(it);
 
   78  void replace_notes(note_set&& notes)
 
   80    for(
auto& note : m_playing_notes)
 
   81      m_to_stop.insert(note);
 
   82    m_playing_notes.clear();
 
   85    swap(m_orig_notes, notes);
 
   88    auto start_it = m_orig_notes.lower_bound(m_prev_date.impl);
 
   89    if(start_it != m_orig_notes.end())
 
   91      m_notes.tree().get_sequence_ref().assign(start_it, m_orig_notes.end());
 
   97    requestTransport = 
true;
 
   98    m_transport_date = date;
 
  104    m_to_stop.insert(m_playing_notes.begin(), m_playing_notes.end());
 
  105    m_playing_notes.clear();
 
  108    if(date < m_prev_date)
 
  112        m_notes = m_orig_notes;
 
  116        auto min_it = m_orig_notes.lower_bound({date});
 
  117        auto max_it = m_orig_notes.lower_bound({m_prev_date});
 
  119        if(min_it != m_orig_notes.end())
 
  120          m_notes.insert(min_it, max_it);
 
  123        for(
auto it = m_orig_notes.begin(); it != min_it; ++it)
 
  125          if((it->start + it->duration) > date)
 
  132    else if(date > m_prev_date)
 
  135      auto min_it = m_notes.lower_bound({date});
 
  136      if(min_it != m_notes.begin() && min_it != m_notes.end())
 
  138        std::advance(min_it, -1);
 
  139        m_notes.erase(m_notes.begin(), min_it);
 
  147  void update_note(note_data oldNote, note_data newNote)
 
  150    remove_note(oldNote);
 
  154  void set_notes(note_set&& notes)
 
  156    m_notes = std::move(notes);
 
  157    m_orig_notes = m_notes;
 
  159    auto max_it = m_notes.lower_bound({m_prev_date});
 
  160    if(max_it != m_notes.begin()) 
 
  161      m_notes.erase(m_notes.begin(), max_it);
 
  165  bool requestTransport{};
 
  169  void run(
const ossia::token_request& t, ossia::exec_state_facade e) 
noexcept override 
  174      const ossia::token_request& t;
 
  177        self.m_prev_date = t.date;
 
  179        if(self.requestTransport)
 
  181          self.transport_impl(self.m_transport_date);
 
  182          self.requestTransport = 
false;
 
  187    ossia::midi_port& mp = *midi_out;
 
  188    const auto samplesratio = e.modelToSamples();
 
  189    const auto tick_start = t.physical_start(samplesratio);
 
  191    if(t.end_discontinuous)
 
  193      auto& mess = mp.messages;
 
  194      for(
auto note : m_playing_notes)
 
  196        mess.push_back(libremidi::from_midi1::note_off(m_channel, note.pitch, 0));
 
  197        mess.back().timestamp = 0;
 
  199      for(
auto note : m_to_stop)
 
  201        mess.push_back(libremidi::from_midi1::note_off(m_channel, note.pitch, 0));
 
  202        mess.back().timestamp = 0;
 
  204      m_playing_notes.clear();
 
  209    for(
const note_data& note : m_to_stop)
 
  211      mp.messages.push_back(libremidi::from_midi1::note_off(m_channel, note.pitch, 0));
 
  212      mp.messages.back().timestamp = tick_start;
 
  218      for(
auto& note : m_playing_notes)
 
  220        mp.messages.push_back(libremidi::from_midi1::note_off(m_channel, note.pitch, 0));
 
  221        mp.messages.back().timestamp = tick_start;
 
  224      m_notes = m_orig_notes;
 
  225      m_playing_notes.clear();
 
  231      if(m_notes.empty() && m_playing_notes.empty())
 
  235        auto it = m_notes.begin();
 
  237        while(it != m_notes.end() && it->start < t.date)
 
  240          mp.messages.push_back(
 
  241              libremidi::from_midi1::note_on(m_channel, note.pitch, note.velocity));
 
  242          mp.messages.back().timestamp = tick_start;
 
  243          m_playing_notes.insert(note);
 
  244          it = m_notes.erase(it);
 
  253        for(
auto it = m_playing_notes.begin(); it != m_playing_notes.end();)
 
  255          note_data& note = 
const_cast<note_data&
>(*it);
 
  256          auto end_time = note.start + note.duration;
 
  258          if(t.in_range({end_time}))
 
  260            mp.messages.push_back(
 
  261                libremidi::from_midi1::note_off(m_channel, note.pitch, 0));
 
  262            mp.messages.back().timestamp
 
  263                = t.to_physical_time_in_tick(end_time, samplesratio);
 
  265            it = m_playing_notes.erase(it);
 
  274        auto max_it = m_notes.lower_bound({t.date});
 
  275        for(
auto it = m_notes.begin(); it < max_it;)
 
  277          note_data& note = 
const_cast<note_data&
>(*it);
 
  278          auto start_time = note.start;
 
  279          if(start_time >= t.prev_date && start_time < t.date)
 
  282            mp.messages.push_back(
 
  283                libremidi::from_midi1::note_on(m_channel, note.pitch, note.velocity));
 
  284            mp.messages.back().timestamp
 
  285                = t.to_physical_time_in_tick(start_time, samplesratio);
 
  287            m_playing_notes.insert(note);
 
  288            it = m_notes.erase(it);
 
  289            max_it = std::lower_bound(
 
  290                it, m_notes.end(), t.date.impl + 1, note_comparator{});
 
  302  note_set m_orig_notes;
 
  303  note_set m_playing_notes;
 
  305  time_value m_prev_date{};
 
  306  time_value m_transport_date{};
 
  311class midi_node_process final : 
public ossia::node_process
 
  314  using ossia::node_process::node_process;
 
  318    midi& n = *
static_cast<midi*
>(node.get());
 
  324    midi& n = *
static_cast<midi*
>(node.get());
 
  325    n.request(ossia::token_request{});
 
The time_value class.
Definition ossia/editor/scenario/time_value.hpp:30