Fixes Issue 1504, allowing feather beam line breaking.
[lilypond/patrick.git] / lily / staff-performer.cc
blob1f34290aac4451d185499cb8c01678daff86534f
1 /*
2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2011 Jan Nieuwenhuizen <janneke@gnu.org>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #include <map>
22 #include "audio-column.hh"
23 #include "audio-item.hh"
24 #include "audio-staff.hh"
25 #include "context.hh"
26 #include "international.hh"
27 #include "performer-group.hh"
28 #include "warn.hh"
30 /* Perform a staff. Individual notes should have their instrument
31 (staff-wide) set, so we override play_element ()
33 class Staff_performer : public Performer
35 public:
36 TRANSLATOR_DECLARATIONS (Staff_performer);
37 ~Staff_performer ();
39 protected:
40 virtual void acknowledge_audio_element (Audio_element_info info);
41 virtual void finalize ();
42 virtual void initialize ();
43 void process_music ();
44 void stop_translation_timestep ();
46 private:
47 string new_instrument_string ();
48 void set_instrument_name (string voice);
49 void set_instrument (int channel, string voice);
50 int get_channel (string instrument);
51 Audio_staff* get_audio_staff (string voice);
52 Audio_staff* new_audio_staff (string voice);
53 Real get_dynamic (string voice);
55 string instrument_string_;
56 int channel_;
57 Audio_instrument *instrument_;
58 Audio_text *instrument_name_;
59 Audio_text *name_;
60 Audio_tempo *tempo_;
61 map<string, Audio_staff*> staff_map_;
62 map<string, int> channel_map_;
63 map<string, Real> dynamic_map_;
64 static map<string, int> static_channel_map_;
65 static int channel_count_;
68 map<string, int> Staff_performer::static_channel_map_;
69 int Staff_performer::channel_count_ = 0;
71 #include "translator.icc"
73 ADD_TRANSLATOR (Staff_performer,
74 /* doc */
75 "",
77 /* create */
78 "",
80 /* read */
81 "",
83 /* write */
84 "");
86 Staff_performer::Staff_performer ()
87 : channel_ (0)
88 , instrument_ (0)
89 , instrument_name_ (0)
90 , name_ (0)
91 , tempo_ (0)
95 Staff_performer::~Staff_performer ()
99 void
100 Staff_performer::initialize ()
104 Audio_staff*
105 Staff_performer::new_audio_staff (string voice)
107 Audio_staff* audio_staff = new Audio_staff;
108 string track_name = context ()->id_string () + ":" + voice;
109 if (track_name != ":")
111 name_ = new Audio_text (Audio_text::TRACK_NAME, context ()->id_string ()
112 + ":" + voice);
113 audio_staff->add_audio_item (name_);
114 announce_element (Audio_element_info (name_, 0));
116 announce_element (Audio_element_info (audio_staff, 0));
117 staff_map_[voice] = audio_staff;
118 if (!instrument_string_.empty ())
119 set_instrument (channel_, voice);
120 return audio_staff;
123 Audio_staff*
124 Staff_performer::get_audio_staff (string voice)
126 SCM channel_mapping = get_property ("midiChannelMapping");
127 if (channel_mapping != ly_symbol2scm ("instrument")
128 && staff_map_.size ())
129 return staff_map_.begin ()->second;
131 map<string, Audio_staff*>::const_iterator i = staff_map_.find (voice);
132 if (i != staff_map_.end ())
133 return i->second;
134 map<string, Audio_staff*>::const_iterator e = staff_map_.find ("");
135 if (staff_map_.size () == 1 && e != staff_map_.end ())
137 staff_map_[voice] = e->second;
138 return e->second;
140 return new_audio_staff (voice);
143 Real
144 Staff_performer::get_dynamic (string voice)
146 map<string, Real>::const_iterator i = dynamic_map_.find (voice);
147 if (i != dynamic_map_.end ())
148 return i->second;
149 return 0;
152 void
153 Staff_performer::process_music ()
157 void
158 Staff_performer::set_instrument (int channel, string voice)
160 instrument_ = new Audio_instrument (instrument_string_);
161 instrument_->channel_ = channel;
162 announce_element (Audio_element_info (instrument_, 0));
163 Audio_staff* audio_staff = get_audio_staff (voice);
164 audio_staff->add_audio_item (instrument_);
165 SCM proc = ly_lily_module_constant ("percussion?");
166 SCM drums = scm_call_1 (proc, ly_symbol2scm (instrument_string_.c_str ()));
167 audio_staff->percussion_ = (drums == SCM_BOOL_T);
170 void
171 Staff_performer::set_instrument_name (string voice)
173 instrument_name_ = new Audio_text (Audio_text::INSTRUMENT_NAME,
174 instrument_string_);
175 announce_element (Audio_element_info (instrument_name_, 0));
176 get_audio_staff (voice)->add_audio_item (instrument_name_);
179 void
180 Staff_performer::stop_translation_timestep ()
182 name_ = 0;
183 tempo_ = 0;
184 instrument_name_ = 0;
185 instrument_ = 0;
188 void
189 Staff_performer::finalize ()
191 staff_map_.clear ();
192 channel_map_.clear ();
195 string
196 Staff_performer::new_instrument_string ()
198 // mustn't ask Score for instrument: it will return piano!
199 SCM minstr = get_property ("midiInstrument");
201 if (!scm_is_string (minstr)
202 || ly_scm2string (minstr) == instrument_string_)
203 return "";
205 instrument_string_ = ly_scm2string (minstr);
207 return instrument_string_;
211 Staff_performer::get_channel (string instrument)
213 SCM channel_mapping = get_property ("midiChannelMapping");
214 map<string, int>& channel_map
215 = (channel_mapping != ly_symbol2scm ("instrument"))
216 ? channel_map_
217 : static_channel_map_;
219 map<string, int>::const_iterator i = channel_map.find (instrument);
220 if (i != channel_map.end ())
221 return i->second;
223 int channel = (channel_mapping == ly_symbol2scm ("staff"))
224 ? channel_count_++
225 : channel_map.size ();
227 /* MIDI players tend to ignore instrument settings on channel
228 10, the percussion channel. */
229 if (channel % 16 == 9)
231 channel_map["percussion"] = channel++;
232 channel_count_++;
235 if (channel > 15)
237 warning (_ ("MIDI channel wrapped around"));
238 warning (_ ("remapping modulo 16"));
239 channel = channel % 16;
242 channel_map[instrument] = channel;
243 return channel;
246 void
247 Staff_performer::acknowledge_audio_element (Audio_element_info inf)
249 if (Audio_item *ai = dynamic_cast<Audio_item *> (inf.elem_))
251 /* map each context (voice) to its own track */
252 Context* c = inf.origin_contexts (this)[0];
253 string voice;
254 if (c->is_alias (ly_symbol2scm ("Voice")))
255 voice = c->id_string ();
256 SCM channel_mapping = get_property ("midiChannelMapping");
257 if (channel_mapping == ly_symbol2scm ("voice"))
258 channel_ = get_channel (voice);
259 string str = new_instrument_string ();
260 if (str.length ())
262 if (channel_mapping != ly_symbol2scm ("voice"))
263 channel_ = get_channel (str);
264 set_instrument (channel_, voice);
265 set_instrument_name (voice);
267 Audio_staff* audio_staff = get_audio_staff (voice);
268 ai->channel_ = channel_;
269 // Output volume as velocity and disable Midi_dynamic output
270 if (Audio_dynamic *d = dynamic_cast<Audio_dynamic *> (inf.elem_))
272 dynamic_map_[voice] = d->volume_;
273 d->volume_ = -1;
275 if (Real d = get_dynamic (voice))
276 if (Audio_note *n = dynamic_cast<Audio_note *> (inf.elem_))
277 n->volume_ = d;
278 audio_staff->add_audio_item (ai);