]> git.donarmstrong.com Git - lilypond.git/blob - lily/midi-walker.cc
Merge with master
[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-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   int stop_ticks = int (moment_to_real (note->audio_->length_mom_) * Real (384 * 4))
74     + ptr->audio_column_->ticks ();
75
76   bool play_start = true;
77   for (vsize i = 0; i < stop_note_queue.size (); i++)
78     {
79       /* if this pith already in queue */
80       if (stop_note_queue[i].val->get_semitone_pitch ()
81           == note->get_semitone_pitch ())
82         {
83           if (stop_note_queue[i].key < stop_ticks)
84             {
85               /* let stopnote in queue be ignored,
86                  new stop note wins */
87               stop_note_queue[i].ignore_ = true;
88
89               /* don't replay start note, */
90               play_start = false;
91               break;
92             }
93           else
94             {
95               /* skip this stopnote,
96                  don't play the start note */
97               note = 0;
98               break;
99             }
100         }
101     }
102
103   if (note)
104     {
105       Midi_note_event e;
106       e.val = new Midi_note_off (note);
107
108       midi_events_.push_back (e.val);
109       e.key = int (stop_ticks);
110       stop_note_queue.insert (e);
111
112       if (play_start)
113         output_event (ptr->audio_column_->ticks (), note);
114     }
115 }
116
117 /**
118    Output note events for all notes which end before #max_mom#
119 */
120 void
121 Midi_walker::do_stop_notes (int max_ticks)
122 {
123   while (stop_note_queue.size () && stop_note_queue.front ().key <= max_ticks)
124     {
125       Midi_note_event e = stop_note_queue.get ();
126       if (e.ignore_)
127         {
128           continue;
129         }
130
131       int stop_ticks = e.key;
132       Midi_note *note = e.val;
133
134       output_event (stop_ticks, note);
135     }
136 }
137
138 void
139 Midi_walker::output_event (int now_ticks, Midi_item *l)
140 {
141   int delta_ticks = now_ticks - last_tick_;
142   last_tick_ = now_ticks;
143
144   /*
145     this is not correct, but at least it doesn't crash when you
146     start with graces
147   */
148   if (delta_ticks < 0)
149     {
150       programming_error ("Going back in MIDI time.");
151       delta_ticks = 0;
152     }
153
154   track_->add (delta_ticks, l);
155 }
156
157 void
158 Midi_walker::process ()
159 {
160   Audio_item *audio = items_[index_];
161   do_stop_notes (audio->audio_column_->ticks ());
162
163   if (Midi_item *midi = get_midi (audio))
164     {
165       if (Midi_channel_item *mci = dynamic_cast<Midi_channel_item*> (midi))
166         mci->channel_ = channel_;
167       
168       if (Midi_note *note = dynamic_cast<Midi_note *> (midi))
169         {
170           if (note->audio_->length_mom_.to_bool ())
171             do_start_note (note);
172         }
173       else
174         output_event (audio->audio_column_->ticks (), midi);
175     }
176 }
177
178 Midi_item*
179 Midi_walker::get_midi (Audio_item *i)
180 {
181   Midi_item *mi = Midi_item::get_midi (i);
182   midi_events_.push_back (mi);
183   return mi;
184 }
185
186 bool
187 Midi_walker::ok () const
188 {
189   return index_ < items_.size ();
190 }
191
192 void
193 Midi_walker::operator ++ (int)
194 {
195   assert (ok ());
196   index_++;
197 }