]> git.donarmstrong.com Git - lilypond.git/blob - lily/midi-walker.cc
Fix #87.
[lilypond.git] / lily / midi-walker.cc
1 /*
2   midi-walker.cc -- implement Midi_walker
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
7   Jan Nieuwenhuizen <janneke@gnu.org>
8 */
9
10 #include "midi-walker.hh"
11
12 #include "audio-column.hh"
13 #include "audio-staff.hh"
14 #include "midi-item.hh"
15 #include "midi-stream.hh"
16 #include "warn.hh"
17
18 Midi_note_event::Midi_note_event ()
19 {
20   ignore_b_ = false;
21 }
22
23 int
24 compare (Midi_note_event const &left, Midi_note_event const &right)
25 {
26   Moment m = (left.key - right.key);
27
28   if (m < 0)
29     return -1;
30   else if (m > 0)
31     return 1;
32   else
33     return 0;
34 }
35
36 bool
37 audio_item_less (Audio_item * const a,
38                  Audio_item * const b)
39 {
40   return a->get_column ()->when_ <  b->get_column ()->when_;
41 }
42
43 Midi_walker::Midi_walker (Audio_staff *audio_staff, Midi_track *track,
44                           int channel)
45 {
46   channel_ = channel;
47   track_ = track;
48   index_ = 0;
49   items_ = audio_staff->audio_items_;
50   vector_sort (items_, audio_item_less);
51   last_tick_ = 0;
52 }
53
54 Midi_walker::~Midi_walker ()
55 {
56   do_stop_notes (last_tick_ + 384);
57 }
58
59 /**
60    Find out if start_note event is needed, and do it if needed.
61 */
62 void
63 Midi_walker::do_start_note (Midi_note *note)
64 {
65   Audio_item *ptr = items_[index_];
66   int stop_ticks = int (moment_to_real (note->audio_->length_mom_) * Real (384 * 4))
67     + ptr->audio_column_->ticks ();
68
69   bool play_start = true;
70   for (vsize i = 0; i < stop_note_queue.size (); i++)
71     {
72       /* if this pith already in queue */
73       if (stop_note_queue[i].val->get_semitone_pitch ()
74           == note->get_semitone_pitch ())
75         {
76           if (stop_note_queue[i].key < stop_ticks)
77             {
78               /* let stopnote in queue be ignored,
79                  new stop note wins */
80               stop_note_queue[i].ignore_b_ = true;
81               /* don't replay start note, */
82               play_start = false;
83               break;
84             }
85           else
86             {
87               /* skip this stopnote,
88                  don't play the start note */
89               delete note;
90               note = 0;
91               break;
92             }
93         }
94     }
95
96   if (note)
97     {
98       Midi_note_event e;
99       e.val = new Midi_note_off (note);
100       e.key = int (stop_ticks);
101       stop_note_queue.insert (e);
102
103       if (play_start)
104         output_event (ptr->audio_column_->ticks (), note);
105     }
106 }
107
108 /**
109    Output note events for all notes which end before #max_mom#
110 */
111 void
112 Midi_walker::do_stop_notes (int max_ticks)
113 {
114   while (stop_note_queue.size () && stop_note_queue.front ().key <= max_ticks)
115     {
116       Midi_note_event e = stop_note_queue.get ();
117       if (e.ignore_b_)
118         {
119           delete e.val;
120           continue;
121         }
122
123       int stop_ticks = e.key;
124       Midi_note *note = e.val;
125
126       output_event (stop_ticks, note);
127     }
128 }
129
130 /**
131    Advance the track to #now#, output the item, and adjust current "moment".
132 */
133 void
134 Midi_walker::output_event (int now_ticks, Midi_item *l)
135 {
136   int delta_ticks = now_ticks - last_tick_;
137   last_tick_ = now_ticks;
138
139   /*
140     this is not correct, but at least it doesn't crash when you
141     start with graces
142   */
143   if (delta_ticks < 0)
144     {
145       programming_error ("Going back in MIDI time.");
146       delta_ticks = 0;
147     }
148
149   track_->add (delta_ticks, l);
150 }
151
152 void
153 Midi_walker::process ()
154 {
155   Audio_item *audio = items_[index_];
156   do_stop_notes (audio->audio_column_->ticks ());
157
158   if (Midi_item *midi = Midi_item::get_midi (audio))
159     {
160       if (Midi_channel_item *mci = dynamic_cast<Midi_channel_item*> (midi))
161         mci->channel_ = channel_;
162       
163       //midi->channel_ = track_->number_;
164       if (Midi_note *note = dynamic_cast<Midi_note *> (midi))
165         {
166           if (note->audio_->length_mom_.to_bool ())
167             do_start_note (note);
168         }
169       else
170         output_event (audio->audio_column_->ticks (), midi);
171     }
172 }
173
174 bool
175 Midi_walker::ok () const
176 {
177   return index_ < items_.size ();
178 }
179
180 void
181 Midi_walker::operator ++ (int)
182 {
183   assert (ok ());
184   index_++;
185 }