-\version "2.10.0"
-\header{ texidoc = "Tests MIDI output with grace notes. " }
-\score {
- \context Voice \relative c {
- \new Voice = VoiceOne
- \grace {
- \override Stem #'stroke-style = #"grace"
- c8
- \revert Stem #'stroke-style }
- d4 d d d d
- \grace {
- \override Stem #'stroke-style = #"grace"
- e16 f e f
- \revert Stem #'stroke-style }
- d4 d d d d
-
- }
- \layout { }
- \midi { }
-}
+\header {
+ texidoc = "Grace notes don't intrroduce syncing problems: the last note
+off will appear at tick 768 (2 * 384)."
+
+}
+\version "2.10.10"
+\score {
+ \relative c' {
+ c4
+ \grace { b8 }
+ d4
+ }
+ \midi { }
+}
return when_;
}
+int
+Audio_column::ticks () const
+{
+ return int (moment_to_ticks (when_));
+}
+
void
Audio_column::offset_when (Moment m)
{
when_ += m;
}
+
dynamics_.push_back (d);
}
-static Real
-moment2real (Moment m)
+Moment
+remap_grace_duration (Moment m)
{
- return m.main_part_.to_double ()
- + 0.1 * m.grace_part_.to_double ();
+ return Moment (m.main_part_ + Rational (9,40) * m.grace_part_,
+ Rational (0));
+}
+
+Real
+moment_to_real (Moment m)
+{
+ return remap_grace_duration (m).main_part_.to_double ();
+}
+
+int
+moment_to_ticks (Moment m)
+{
+ return int (moment_to_real (m) * 384 * 4);
}
void
Moment start = dynamics_[0]->get_column ()->when ();
- Real total_t = moment2real (dynamics_.back ()->get_column ()->when () - start);
+ Real total_t = moment_to_real (dynamics_.back ()->get_column ()->when () - start);
for (vsize i = 1; i < dynamics_.size(); i ++)
{
Moment dt_moment = dynamics_[i]->get_column ()->when ()
- start;
- Real dt = moment2real (dt_moment);
+ Real dt = moment_to_real (dt_moment);
Real v = start_v + delta_v * (dt / total_t);
vector<Audio_item*> audio_items_;
Moment when_;
-
+ int ticks () const ;
protected:
void offset_when (Moment m);
friend class Score_performer;
int one_beat_;
};
+int moment_to_ticks (Moment);
+Real moment_to_real (Moment);
+Moment remap_grace_duration (Moment);
+
#endif // AUDIO_ITEM_HH
class Midi_event
{
public:
- Midi_event (Moment delta_mom, Midi_item *midi);
+ Midi_event (int delta, Midi_item *midi);
- Moment delta_mom_;
+ int delta_ticks_;
Midi_item *midi_;
string to_string () const;
};
Midi_note (Audio_note *);
DECLARE_CLASSNAME(Midi_note);
- Moment get_length () const;
int get_semitone_pitch () const;
int get_fine_tuning () const;
virtual string to_string () const;
Midi_track ();
~Midi_track ();
- void add (Moment delta_time_mom, Midi_item *midi);
+ void add (int, Midi_item *midi);
virtual string data_string () const;
};
#include "lily-proto.hh"
#include "moment.hh"
-struct Midi_note_event : PQueue_ent<Moment, Midi_note *>
+struct Midi_note_event : PQueue_ent<int, Midi_note *>
{
bool ignore_b_;
Midi_note_event ();
private:
void do_start_note (Midi_note *note);
- void do_stop_notes (Moment now_mom);
- void output_event (Moment now_mom, Midi_item *l);
+ void do_stop_notes (int);
+ void output_event (int, Midi_item *l);
int channel_;
Midi_track *track_;
Audio_staff *staff_;
vsize index_;
- vector<Audio_item*> *items_;
+ vector<Audio_item*> items_;
PQueue<Midi_note_event> stop_note_queue;
- Moment last_mom_;
+ int last_tick_;
};
#endif // MIDI_WALKER_HH
return string ("<duration: ") + ::to_string (seconds_) + ">";
}
-Midi_event::Midi_event (Moment delta_mom, Midi_item *midi)
+Midi_event::Midi_event (int delta_ticks, Midi_item *midi)
{
- delta_mom_ = delta_mom;
+ delta_ticks_ = delta_ticks;
midi_ = midi;
}
string
Midi_event::to_string () const
{
- assert (delta_mom_.grace_part_ == Rational (0));
-
- Rational rat_dt = delta_mom_.main_part_ * Rational (384) * Rational (4);
- int delta = rat_dt.to_int ();
-
- string delta_string = Midi_item::i2varint_string (delta);
+ string delta_string = Midi_item::i2varint_string (delta_ticks_);
string midi_string = midi_->to_string ();
assert (midi_string.length ());
return delta_string + midi_string;
dynamic_byte_ = 0x7f;
}
-Moment
-Midi_note::get_length () const
-{
- Moment m = audio_->end_column_->when () - audio_->audio_column_->when ();
- return m;
-}
int
Midi_note::get_fine_tuning () const
str += ::to_string ((char) (0x00));
}
- str += ::to_string ((char)status_byte);
+ str += ::to_string ((char) status_byte);
str += ::to_string ((char) (get_semitone_pitch () + c0_pitch_));
str += ::to_string ((char)dynamic_byte_);
}
void
-Midi_track::add (Moment delta_time_mom, Midi_item *midi)
+Midi_track::add (int delta_ticks, Midi_item *midi)
{
- assert (delta_time_mom >= Moment (0));
+ assert (delta_ticks >= 0);
- Midi_event *e = new Midi_event (delta_time_mom, midi);
+ Midi_event *e = new Midi_event (delta_ticks, midi);
events_.push_back (e);
}
return 0;
}
+bool
+audio_item_less (Audio_item * const a,
+ Audio_item * const b)
+{
+ return a->get_column ()->when_ < b->get_column ()->when_;
+}
+
Midi_walker::Midi_walker (Audio_staff *audio_staff, Midi_track *track,
int channel)
{
channel_ = channel;
track_ = track;
index_ = 0;
- items_ = &audio_staff->audio_items_;
-
- last_mom_ = 0;
+ items_ = audio_staff->audio_items_;
+ vector_sort (items_, audio_item_less);
+ last_tick_ = 0;
}
Midi_walker::~Midi_walker ()
{
- // ugh
- do_stop_notes (last_mom_ + Moment (Rational (10, 1)));
+ do_stop_notes (last_tick_ + 384);
}
/**
void
Midi_walker::do_start_note (Midi_note *note)
{
- Audio_item *ptr = (*items_)[index_];
- Moment stop_mom = note->get_length () + ptr->audio_column_->when ();
+ Audio_item *ptr = items_[index_];
+ int stop_ticks = int (moment_to_real (note->audio_->length_mom_) * Real (384 * 4))
+ + ptr->audio_column_->ticks ();
bool play_start = true;
for (vsize i = 0; i < stop_note_queue.size (); i++)
if (stop_note_queue[i].val->get_semitone_pitch ()
== note->get_semitone_pitch ())
{
- if (stop_note_queue[i].key < stop_mom)
+ if (stop_note_queue[i].key < stop_ticks)
{
/* let stopnote in queue be ignored,
new stop note wins */
{
Midi_note_event e;
e.val = new Midi_note_off (note);
- e.key = stop_mom;
+ e.key = int (stop_ticks);
stop_note_queue.insert (e);
if (play_start)
- output_event (ptr->audio_column_->when (), note);
+ output_event (ptr->audio_column_->ticks (), note);
}
}
Output note events for all notes which end before #max_mom#
*/
void
-Midi_walker::do_stop_notes (Moment max_mom)
+Midi_walker::do_stop_notes (int max_ticks)
{
- while (stop_note_queue.size () && stop_note_queue.front ().key <= max_mom)
+ while (stop_note_queue.size () && stop_note_queue.front ().key <= max_ticks)
{
Midi_note_event e = stop_note_queue.get ();
if (e.ignore_b_)
continue;
}
- Moment stop_mom = e.key;
+ int stop_ticks = e.key;
Midi_note *note = e.val;
- output_event (stop_mom, note);
+ output_event (stop_ticks, note);
}
}
Advance the track to #now#, output the item, and adjust current "moment".
*/
void
-Midi_walker::output_event (Moment now_mom, Midi_item *l)
+Midi_walker::output_event (int now_ticks, Midi_item *l)
{
- Moment delta_t = now_mom - last_mom_;
- last_mom_ = now_mom;
+ int delta_ticks = now_ticks - last_tick_;
+ last_tick_ = now_ticks;
/*
this is not correct, but at least it doesn't crash when you
start with graces
*/
- if (delta_t < Moment (0))
- delta_t = Moment (0);
+ if (delta_ticks < 0)
+ {
+ programming_error ("Going back in MIDI time.");
+ delta_ticks = 0;
+ }
- track_->add (delta_t, l);
+ track_->add (delta_ticks, l);
}
void
Midi_walker::process ()
{
- Audio_item *audio = (*items_)[index_];
- do_stop_notes (audio->audio_column_->when ());
+ Audio_item *audio = items_[index_];
+ do_stop_notes (audio->audio_column_->ticks ());
if (Midi_item *midi = Midi_item::get_midi (audio))
{
//midi->channel_ = track_->number_;
if (Midi_note *note = dynamic_cast<Midi_note *> (midi))
{
- if (note->get_length ().to_bool ())
+ if (note->audio_->length_mom_.to_bool ())
do_start_note (note);
}
else
- output_event (audio->audio_column_->when (), midi);
+ output_event (audio->audio_column_->ticks (), midi);
}
}
bool
Midi_walker::ok () const
{
- return index_ < items_->size ();
+ return index_ < items_.size ();
}
void
tie_event = ev;
}
- Audio_note *p = new Audio_note (*pitp, get_event_length (n),
+ Moment len = get_event_length (n);
+ if (now_mom().grace_part_)
+ {
+ len.grace_part_ = len.main_part_;
+ len.main_part_ = Rational (0);
+ }
+
+ Audio_note *p = new Audio_note (*pitp, len,
tie_event, transposing.negated ());
Audio_element_info info (p, n);
announce_element (info);
{
int tracks_ = audio_staffs_.size ();
- // ugh
- int clocks_per_4 = 384;
-
- midi_stream << Midi_header (1, tracks_, clocks_per_4);
- message (_ ("Track...") + " ");
+ midi_stream << Midi_header (1, tracks_, 384);
+ if (be_verbose_global)
+ progress_indication (_ ("Track...") + " ");
int channel = 0;
for (vsize i = 0; i < audio_staffs_.size (); i++)
}
-void
-Performance::remap_grace_durations ()
-{
- for (vsize i = 0; i < audio_elements_.size (); i++)
- {
- if (Audio_column * col = dynamic_cast<Audio_column*> (audio_elements_[i]))
- {
- col->when_.main_part_ = col->when_.main_part_ + Rational (1,4) * col->when_.grace_part_;
- col->when_.grace_part_ = Rational (0);
- }
- }
-}
-
void
Performance::process ()
{
- remap_grace_durations ();
}