2 // mudela-staff.cc -- implement Mudela_staff
4 // copyright 1997 Jan Nieuwenhuizen <janneke@gnu.org>
9 #include "duration-convert.hh"
10 #include "string-convert.hh"
11 #include "midi2ly-proto.hh"
12 #include "midi2ly-global.hh"
13 #include "mudela-column.hh"
14 #include "mudela-item.hh"
15 #include "mudela-staff.hh"
16 #include "mudela-stream.hh"
17 #include "mudela-voice.hh"
18 #include "mudela-score.hh"
20 #include "killing-cons.tcc"
22 extern Mudela_score
* mudela_score_l_g
;
24 Mudela_staff::Mudela_staff (int number_i
, String copyright_str
, String track_name_str
, String instrument_str
)
27 copyright_str_
= copyright_str
;
28 instrument_str_
= instrument_str
;
29 name_str_
= track_name_str
;
31 mudela_time_signature_l_
= 0;
36 Mudela_staff::add_item (Mudela_item
* mudela_item_p
)
38 mudela_item_p_list_
.append (new Killing_cons
<Mudela_item
> (mudela_item_p
, 0));
39 if (mudela_item_p
->mudela_column_l_
)
40 mudela_item_p
->mudela_column_l_
->add_item (mudela_item_p
);
43 Walk ITEMS and find voices. Remove categorised items.
47 * collect all channels into separate voices. Use chords for sim
48 notes on same channel.
49 * assume voices/assume chords modes.
53 Mudela_staff::eat_voice (Cons_list
<Mudela_item
>& items
)
55 Mudela_voice
* voice_p
= new Mudela_voice (this);
56 mudela_voice_p_list_
.append (new Killing_cons
<Mudela_voice
> (voice_p
, 0));
58 // Rational mom = items.top ()->at_mom ();
61 for (Cons
<Mudela_item
>** pp
= &items
.head_
; *pp
;)
63 Cons
<Mudela_item
>* i
= *pp
;
64 if (i
->car_
->at_mom () > mom
)
66 if (no_rests_b_g
&& voice_p
->last_note_l_
)
68 voice_p
->last_note_l_
->end_column_l_
= i
->car_
->mudela_column_l_
;
72 /* uh, what about quantisation? This should probably
73 use mom2standardised_dur ()
74 arg, urg: skip should get duration from start/end columns!
77 Rational r
= i
->car_
->at_mom () - mom
;
79 Mudela_column
* start
= mudela_score_l_g
->find_column_l (mom
);
80 voice_p
->add_item (new Mudela_skip (start
, r
));
83 mom
= i
->car_
->at_mom ();
84 continue; // unnecessary
87 Link_array
<Mudela_item
> now_items
;
88 for (Cons
<Mudela_item
> *cp
= i
; cp
&& cp
->car_
->at_mom () == mom
; cp
= cp
->next_
)
89 now_items
.push (i
->car_
);
93 Why don't we use <note>, if voice has:
97 we'd get last_item == key_change -> last_note == 0;
99 Mudela_note
* last_note
= dynamic_cast<Mudela_note
*> (voice_p
->last_item_l_
);
102 Not sure, is this better?
104 Mudela_note
* last_note
= voice_p
->last_note_l_
;
107 Link_array
<Mudela_item
> candidates
;
109 for (int i
=0; last_note
&& i
< now_items
.size (); i
++)
111 Mudela_note
* now_note
= dynamic_cast<Mudela_note
*> (now_items
[i
]);
112 if (now_note
&& last_note
->channel_i_
!= now_note
->channel_i_
)
113 candidates
.push (now_note
);
116 if (candidates
.size())
118 now_items
= candidates
;
121 Mudela_item
* which
= 0;
122 if (now_items
.size () > 1)
124 int mindiff
= 100000; // ugh
125 for (int i
=0; last_note
&& i
< now_items
.size (); i
++)
127 Mudela_note
*nt
= dynamic_cast<Mudela_note
*> (now_items
[i
]);
130 int diff
= abs (last_note
->pitch_i_
- nt
->pitch_i_
);
134 which
= now_items
[i
];
138 if (which
&& mindiff
> 18) // more than 1.5 octaves apart. Don't put in same voice.
143 else if (now_items
.size () == 1)
144 which
= now_items
[0];
148 while ((*pp
)->car_
!= which
)
151 mom
+= (*pp
)->car_
->duration_mom ();
152 Cons
<Mudela_item
>* c
= items
.remove_cons (pp
);
153 voice_p
->add_item (c
->car_
);
165 Mudela_staff::id_str ()
167 String
id (name_str ());
168 char *cp
= id
.ch_l ();
169 char *end
= cp
+ id
.length_i ();
170 for (;cp
< end
; cp
++)
181 Mudela_staff::name_str ()
183 if (name_str_
.length_i ())
185 return String ("track") + to_str (char ('A' - 1 + number_i_
));
191 Mudela_staff::output (Mudela_stream
& mudela_stream_r
)
195 String trackbody
= "";
196 for (Cons
<Mudela_voice
>* i
= mudela_voice_p_list_
.head_
; i
; i
= i
->next_
)
198 String voicename
= id_str () + "voice" + to_str (char (c
+ 'A'));
200 mudela_stream_r
<< voicename
<< " = \\notes ";
202 trackbody
+= "\\" + voicename
+ "\n";
204 mudela_stream_r
<< '\n';
205 i
->car_
->output (mudela_stream_r
);
209 mudela_stream_r
<< _ ("% MIDI copyright:") << copyright_str_
<< '\n';
210 mudela_stream_r
<< _ ("% MIDI instrument:") << instrument_str_
<< '\n';
211 mudela_stream_r
<< id_str () << " = ";
212 mudela_stream_r
<< "<\n " << trackbody
<< " >\n";
214 mudela_stream_r
<< " % " << name_str () << '\n';
218 Mudela_staff::output_mudela_begin_bar (Mudela_stream
& mudela_stream_r
, Rational now_mom
, int bar_i
)
220 Rational bar_mom
= mudela_time_signature_l_
->bar_mom ();
221 Rational into_bar_mom
= now_mom
- Rational (bar_i
- 1) * bar_mom
;
225 mudela_stream_r
<< "|\n";
227 mudela_stream_r
<< "% " << String_convert::i2dec_str (bar_i
, 0, ' ');
229 mudela_stream_r
<< ":" << Duration_convert::dur2_str (Duration_convert::mom2_dur (into_bar_mom
));
230 mudela_stream_r
<< '\n';
234 #if 0 // not used for now
236 Mudela_staff::output_mudela_rest (Mudela_stream
& mudela_stream_r
, Rational begin_mom
, Rational end_mom
)
238 Rational bar_mom
= mudela_time_signature_l_
->bar_mom ();
239 Rational now_mom
= begin_mom
;
241 int begin_bar_i
= (int) (now_mom
/ bar_mom
) + 1;
242 int end_bar_i
= (int) (end_mom
/ bar_mom
) + 1;
244 if (end_bar_i
== begin_bar_i
)
246 output_mudela_rest_remain (mudela_stream_r
, end_mom
- begin_mom
);
250 // multiple bars involved
251 int bar_i
= (int) (now_mom
/ bar_mom
) + 1;
254 Rational begin_bar_mom
= Rational (begin_bar_i
- 1) * bar_mom
;
255 if (now_mom
> begin_bar_mom
)
257 int next_bar_i
= (int) (now_mom
/ bar_mom
) + 2;
258 Rational next_bar_mom
= Rational (next_bar_i
- 1) * bar_mom
;
259 assert (next_bar_mom
<= end_mom
);
261 Rational remain_mom
= next_bar_mom
- now_mom
;
262 if (remain_mom
> Rational (0))
264 output_mudela_rest_remain (mudela_stream_r
, remain_mom
);
265 now_mom
+= remain_mom
;
268 bar_i
= check_end_bar_i (now_mom
, bar_i
);
272 int count_i
= end_bar_i
- bar_i
;
273 for (int i
= 0; i
< count_i
; i
++)
275 int begin_bar_i
= check_begin_bar_i (now_mom
, bar_i
);
277 output_mudela_begin_bar (mudela_stream_r
, now_mom
, begin_bar_i
);
278 mudela_stream_r
<< "r1 ";
279 // *mudela_stream_r.os_p_ << flush;
281 LOGOUT (NORMAL_ver
) << begin_bar_i
<< flush
;
282 bar_i
= check_end_bar_i (now_mom
, bar_i
);
286 // use "int i" here, and gcc 2.7.2 hits internal compiler error
287 int ii
= check_begin_bar_i (now_mom
, bar_i
);
289 output_mudela_begin_bar (mudela_stream_r
, now_mom
, ii
);
291 // bar_i = check_end_bar_i (now_mom, bar_i);
293 Rational remain_mom
= end_mom
- Rational (end_bar_i
- 1) * bar_mom
;
294 if (remain_mom
> Rational (0))
296 output_mudela_rest_remain (mudela_stream_r
, remain_mom
);
297 now_mom
+= remain_mom
;
299 assert (now_mom
== end_mom
);
303 Mudela_staff::output_mudela_rest_remain (Mudela_stream
& mudela_stream_r
, Rational mom
)
305 if (Duration_convert::no_quantify_b_s
)
307 Duration dur
= Duration_convert::mom2_dur (mom
);
308 mudela_stream_r
<< "r" << dur
.str () << " ";
309 // assert (mom == dur.mom ());
310 assert (mom
== dur
.length ());
314 Duration dur
= Duration_convert::mom2standardised_dur (mom
);
316 mudela_stream_r
<< "r" << dur
.str () << " ";
322 Mudela_staff::process ()
325 group items into voices
328 assert (mudela_score_l_g
);
329 mudela_key_l_
= mudela_score_l_g
->mudela_key_l_
;
330 mudela_time_signature_l_
= mudela_score_l_g
->mudela_time_signature_l_
;
331 mudela_tempo_l_
= mudela_score_l_g
->mudela_tempo_l_
;
333 Cons_list
<Mudela_item
> items
;
334 for (Cons
<Mudela_item
>* i
= mudela_item_p_list_
.head_
; i
; i
= i
->next_
)
335 items
.append (new Cons
<Mudela_item
> (i
->car_
, 0));
337 while (items
.size_i ())