]> git.donarmstrong.com Git - lilypond.git/blob - src/score.cc
368188bbc19ecdd46fc69d1c6f0367e95b81352d
[lilypond.git] / src / score.cc
1 /*
2   score.cc -- implement Score
3
4   source file of the LilyPond music typesetter
5
6   (c) 1997 Han-Wen Nienhuys <hanwen@stack.nl>
7 */
8
9 #include "tstream.hh"
10 #include "score.hh"
11 #include "sccol.hh"
12 #include "pscore.hh"
13 #include "staff.hh"
14 #include "debug.hh"
15 #include "paperdef.hh"
16 #include "main.hh"
17 #include "source.hh"
18 #include "sourcefile.hh"
19 #include "scorewalker.hh"
20 #include "mididef.hh"
21 #include "midiitem.hh"
22 #include "midistream.hh"
23 #include "midicolumn.hh"
24 #include "midistaff.hh"
25 #include "midiwalker.hh"
26
27 void
28 Score::setup_music()
29 {
30     *mlog << "\nSetting up music ..." << flush;
31     if (last() == Moment(0)) {
32         errorlevel_i_ |= 1;
33         error("Need to have music in a score.", defined_ch_c_l_);
34     }
35
36     pscore_p_ = new PScore(paper_p_);
37     find_col(0, false)->set_breakable(); // ugh
38     find_col(last(), false)->set_breakable();
39     
40         
41
42     for (iter_top(staffs_,i); i.ok(); i++) {
43         i->set_output(pscore_p_);
44         i->setup_staffcols();
45         i->OK();
46     }
47 }
48
49 void
50 Score::process_music()
51 {
52     *mlog << "Processing music ..." << flush;
53     for (Score_walker w(this); w.ok(); w++) {
54         w.process();
55    }
56 }
57
58 void
59 Score::process()
60 {
61     setup_music();
62
63     process_music();
64
65     // do this after processing, staffs first have to generate PCols.
66     do_cols();
67     print();
68     calc_idealspacing();
69
70     // debugging
71     OK();
72     *mlog << endl;
73     pscore_p_->process();
74 }
75
76 /**
77   Remove empty cols, preprocess other columns.
78   */
79 void
80 Score::clean_cols()
81 {
82     for (iter_top(staffs_,i); i.ok(); i++)
83         i->clean_cols();
84
85     for (iter_top(cols_,c); c.ok(); ) {
86         if (!c->pcol_l_->used()) {
87             delete c.get();
88         } else {
89             c->preprocess();
90             c++;
91         }
92     }
93 }
94
95 /**
96   Create columns at time #w#.
97   this sux.  We should have Score_column create the appropriate PCol.
98   Unfortunately, PCols don't know about their position.
99
100   @return cursor pointing to the nonmusical (first) column
101   */
102 PCursor<Score_column*>
103 Score::create_cols(Moment w)
104 {
105     Score_column* c1 = new Score_column(w);
106     Score_column* c2 = new Score_column(w);
107     
108     c1->musical_b_ = false;
109     c2->musical_b_ = true;
110     
111     iter_top(cols_,i);
112
113     for (; i.ok(); i++) {
114         assert(i->when() != w);
115         if (i->when() > w)
116             break;
117     }
118
119     if (!i.ok()) {
120         cols_.bottom().add(c1);
121         cols_.bottom().add(c2);
122         i = cols_.bottom();
123         i --;
124     } else {
125         i.insert(c1);
126         i.insert(c2);
127         i -= 2;
128     }
129     return i;
130 }
131
132 PCursor<Score_column*>
133 Score::find_col(Moment w, bool mus)
134 {
135     iter_top( cols_,i);
136     
137     for (; i.ok(); i++) {
138         if (i->when() == w && i->musical_b_ == mus)
139             return i;
140         if (i->when() > w)
141             break;
142     }
143     i = create_cols(w);
144     if (mus)
145         i++;
146     return i;
147 }
148
149 void
150 Score::do_cols()
151 {
152     iter_top(cols_,i);
153     for (; i.ok(); i++) {
154         pscore_p_->add(i->pcol_l_);
155     }
156     clean_cols();    // can't move clean_cols() farther up.
157 }
158
159 Moment
160 Score::last() const
161 {    
162     Moment l = 0;
163     for (iter_top(staffs_,i); i.ok(); i++) {
164         l = l>? i->last();
165     }
166     return l;
167 }
168
169 void
170 Score::set(Mididef* midi_p)
171 {    
172     delete midi_p_;
173     midi_p_ = midi_p;
174 }
175
176 void
177 Score::OK() const
178 {
179 #ifndef NDEBUG
180     for (iter_top(staffs_,i); i.ok(); i++) {
181         i->OK();
182         assert(i->score_l_ == this);
183     }
184     staffs_.OK();
185     cols_.OK();
186     for (iter_top(cols_,cc); cc.ok() && (cc+1).ok(); cc++) {
187         assert(cc->when() <= (cc+1)->when());
188     }
189 #endif    
190 }
191
192
193 void
194 Score::print() const
195 {
196 #ifndef NPRINT
197     mtor << "score {\n"; 
198     for (iter_top(staffs_,i); i.ok(); i++) {
199         i->print();
200     }
201     for (iter_top(cols_,i); i.ok(); i++) {
202         i->print();
203     }
204     if (pscore_p_)
205         pscore_p_->print();
206     
207     mtor << "}\n";
208 #endif
209 }
210
211 Score::Score(Paperdef*paper_p)
212 {
213     pscore_p_=0;
214     paper_p_ = paper_p;
215     midi_p_ = 0;
216     errorlevel_i_ = 0;
217     defined_ch_c_l_ = 0;
218 }
219
220 Score::~Score()
221 {
222     delete pscore_p_;
223     delete paper_p_;
224     delete midi_p_;
225 }
226
227 void
228 Score::output(String s)
229 {
230     OK();
231     if (paper_p_->outfile=="")
232         paper_p_->outfile = s;
233     
234     if ( errorlevel_i_ ) { 
235         *mlog << "lilypond: warning: no output to: " << paper_p_->outfile 
236         << " (errorlevel=" << errorlevel_i_ << ")" << endl;
237         return;
238     }
239
240     *mlog << "output to " << paper_p_->outfile << "...\n";
241     
242     Tex_stream the_output(paper_p_->outfile);
243     
244     the_output << "% outputting Score, defined at: " <<
245         source_global_l->
246         sourcefile_l (defined_ch_c_l_)->file_line_no_str(defined_ch_c_l_) << "\n";
247     pscore_p_->output(the_output);
248 }
249
250 void
251 Score::midi()
252 {
253     if (!midi_p_)
254         return;
255
256     *mlog << "midi output to " << midi_p_->outfile_str_ << "...\n";
257
258     int track_i = 0;
259     for ( PCursor<Staff*> staff_l_pcur( staffs_.top() ); staff_l_pcur.ok(); staff_l_pcur++ ) {
260         Midi_staff* mstaff_l = (Midi_staff*)*staff_l_pcur;
261         if ( !mstaff_l->pscore_l_ ) // we _are_ a midi-staff, ugh
262             track_i++;
263     }
264
265     Midi_stream midi_stream( midi_p_->outfile_str_, track_i, midi_p_->get_tempo_i( Moment( 1, 4 ) )  );
266
267     track_i = 0;
268     for ( PCursor<Staff*> staff_l_pcur( staffs_.top() ); staff_l_pcur.ok(); staff_l_pcur++ ) {
269         Midi_staff* mstaff_l = (Midi_staff*)*staff_l_pcur;
270         if ( !mstaff_l->pscore_l_ ) // we _are_ a midi-staff, ugh
271             mstaff_l->midi( &midi_stream, track_i++ );
272     }
273 }
274
275 void
276 Score::add(Staff*s)
277 {
278     s->score_l_ = this;
279     staffs_.bottom().add(s);
280 }