]> git.donarmstrong.com Git - lilypond.git/blob - lily/midi-walker.cc
Run `make grand-replace'.
[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--2008 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-chunk.hh"
16 #include "midi-stream.hh"
17 #include "warn.hh"
18
19 Midi_note_event::Midi_note_event ()
20 {
21   ignore_ = false;
22 }
23
24 int
25 compare (Midi_note_event const &left, Midi_note_event const &right)
26 {
27   Moment m = (left.key - right.key);
28
29   if (m < 0)
30     return -1;
31   else if (m > 0)
32     return 1;
33   else
34     return 0;
35 }
36
37 bool
38 audio_item_less (Audio_item * const a,
39                  Audio_item * const b)
40 {
41   return a->get_column ()->when_ <  b->get_column ()->when_;
42 }
43
44 Midi_walker::Midi_walker (Audio_staff *audio_staff, Midi_track *track,
45                           int channel)
46 {
47   channel_ = channel;
48   track_ = track;
49   index_ = 0;
50   items_ = audio_staff->audio_items_;
51   vector_sort (items_, audio_item_less);
52   last_tick_ = 0;
53 }
54
55 Midi_walker::~Midi_walker ()
56 {
57   junk_pointers (midi_events_);
58 }
59
60 void
61 Midi_walker::finalize ()
62 {
63   do_stop_notes (INT_MAX);
64 }
65
66 /**
67    Find out if start_note event is needed, and do it if needed.
68 */
69 void
70 Midi_walker::do_start_note (Midi_note *note)
71 {
72   Audio_item *ptr = items_[index_];
73   assert (note->audio_ == ptr);
74   int stop_ticks = int (moment_to_real (note->audio_->length_mom_) * Real (384 * 4))
75     + ptr->audio_column_->ticks ();
76
77   bool play_start = true;
78   for (vsize i = 0; i < stop_note_queue.size (); i++)
79     {
80       /* if this pith already in queue */
81       if (stop_note_queue[i].val->get_semitone_pitch ()
82           == note->get_semitone_pitch ())
83         {
84           if (stop_note_queue[i].key < stop_ticks)
85             {
86               /* let stopnote in queue be ignored,
87                  new stop note wins */
88               stop_note_queue[i].ignore_ = true;
89
90               /* don't replay start note, */
91               play_start = false;
92               break;
93             }
94           else
95             {
96               /* skip this stopnote,
97                  don't play the start note */
98               note = 0;
99               break;
100             }
101         }
102     }
103
104   if (note)
105     {
106       Midi_note_event e;
107       e.val = new Midi_note_off (note);
108
109       midi_events_.push_back (e.val);
110       e.key = int (stop_ticks);
111       stop_note_queue.insert (e);
112
113       if (play_start)
114         output_event (ptr->audio_column_->ticks (), note);
115     }
116 }
117
118 void
119 Midi_walker::do_stop_notes (int max_ticks)
120 {
121   while (stop_note_queue.size () && stop_note_queue.front ().key <= max_ticks)
122     {
123       Midi_note_event e = stop_note_queue.get ();
124       if (e.ignore_)
125         {
126           continue;
127         }
128
129       int stop_ticks = e.key;
130       Midi_note *note = e.val;
131
132       output_event (stop_ticks, note);
133     }
134 }
135
136 void
137 Midi_walker::output_event (int now_ticks, Midi_item *l)
138 {
139   int delta_ticks = now_ticks - last_tick_;
140   last_tick_ = now_ticks;
141
142   /*
143     this is not correct, but at least it doesn't crash when you
144     start with graces
145   */
146   if (delta_ticks < 0)
147     {
148       programming_error ("Going back in MIDI time.");
149       delta_ticks = 0;
150     }
151
152   track_->add (delta_ticks, l);
153 }
154
155 void
156 Midi_walker::process ()
157 {
158   Audio_item *audio = items_[index_];
159   do_stop_notes (audio->audio_column_->ticks ());
160
161   if (Midi_item *midi = get_midi (audio))
162     {
163       if (Midi_channel_item *mci = dynamic_cast<Midi_channel_item*> (midi))
164         mci->channel_ = channel_;
165       
166       if (Midi_note *note = dynamic_cast<Midi_note *> (midi))
167         {
168           if (note->audio_->length_mom_.to_bool ())
169             do_start_note (note);
170         }
171       else
172         output_event (audio->audio_column_->ticks (), midi);
173     }
174 }
175
176 Midi_item*
177 Midi_walker::get_midi (Audio_item *i)
178 {
179   Midi_item *mi = Midi_item::get_midi (i);
180   midi_events_.push_back (mi);
181   return mi;
182 }
183
184 bool
185 Midi_walker::ok () const
186 {
187   return index_ < items_.size ();
188 }
189
190 void
191 Midi_walker::operator ++ (int)
192 {
193   assert (ok ());
194   index_++;
195 }