2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2012 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/>.
22 #include "audio-column.hh"
23 #include "audio-item.hh"
24 #include "audio-staff.hh"
26 #include "international.hh"
27 #include "performer-group.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
36 TRANSLATOR_DECLARATIONS (Staff_performer);
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 ();
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 Audio_dynamic *get_dynamic (string voice);
55 string instrument_string_;
57 Audio_instrument *instrument_;
58 Audio_text *instrument_name_;
61 map<string, Audio_staff *> staff_map_;
62 map<string, int> channel_map_;
63 map<string, Audio_dynamic *> dynamic_map_;
64 // Would prefer to have the following two items be
65 // members of the containing class Performance,
66 // so they can be reset for each new midi file output.
67 static map<string, int> static_channel_map_;
68 static int channel_count_;
69 // For now, ask the last Staff_performer clean up during its finalize method
70 static int staff_performer_count_;
73 map<string, int> Staff_performer::static_channel_map_;
74 int Staff_performer::channel_count_ = 0;
75 int Staff_performer::staff_performer_count_ = 0;
77 #include "translator.icc"
79 ADD_TRANSLATOR (Staff_performer,
92 Staff_performer::Staff_performer ()
101 Staff_performer::~Staff_performer ()
106 Staff_performer::initialize ()
108 ++staff_performer_count_;
112 Staff_performer::new_audio_staff (string voice)
114 Audio_staff *audio_staff = new Audio_staff;
115 audio_staff->merge_unisons_
116 = to_boolean (get_property ("midiMergeUnisons"));
117 string track_name = context ()->id_string () + ":" + voice;
118 if (track_name != ":")
120 name_ = new Audio_text (Audio_text::TRACK_NAME, context ()->id_string ()
122 audio_staff->add_audio_item (name_);
123 announce_element (Audio_element_info (name_, 0));
125 announce_element (Audio_element_info (audio_staff, 0));
126 staff_map_[voice] = audio_staff;
127 if (!instrument_string_.empty ())
128 set_instrument (channel_, voice);
133 Staff_performer::get_audio_staff (string voice)
135 SCM channel_mapping = get_property ("midiChannelMapping");
136 if (channel_mapping != ly_symbol2scm ("instrument")
137 && staff_map_.size ())
138 return staff_map_.begin ()->second;
140 map<string, Audio_staff *>::const_iterator i = staff_map_.find (voice);
141 if (i != staff_map_.end ())
143 map<string, Audio_staff *>::const_iterator e = staff_map_.find ("");
144 if (staff_map_.size () == 1 && e != staff_map_.end ())
146 staff_map_[voice] = e->second;
149 return new_audio_staff (voice);
153 Staff_performer::get_dynamic (string voice)
155 map<string, Audio_dynamic *>::const_iterator i = dynamic_map_.find (voice);
156 if (i != dynamic_map_.end ())
162 Staff_performer::process_music ()
167 Staff_performer::set_instrument (int channel, string voice)
169 instrument_ = new Audio_instrument (instrument_string_);
170 instrument_->channel_ = channel;
171 announce_element (Audio_element_info (instrument_, 0));
172 Audio_staff *audio_staff = get_audio_staff (voice);
173 audio_staff->add_audio_item (instrument_);
174 SCM proc = ly_lily_module_constant ("percussion?");
175 SCM drums = scm_call_1 (proc, ly_symbol2scm (instrument_string_.c_str ()));
176 audio_staff->percussion_ = (drums == SCM_BOOL_T);
180 Staff_performer::set_instrument_name (string voice)
182 instrument_name_ = new Audio_text (Audio_text::INSTRUMENT_NAME,
184 announce_element (Audio_element_info (instrument_name_, 0));
185 get_audio_staff (voice)->add_audio_item (instrument_name_);
189 Staff_performer::stop_translation_timestep ()
193 instrument_name_ = 0;
198 Staff_performer::finalize ()
201 channel_map_.clear ();
202 if (staff_performer_count_)
203 --staff_performer_count_;
204 if (0 == staff_performer_count_)
206 static_channel_map_.clear ();
212 Staff_performer::new_instrument_string ()
214 // mustn't ask Score for instrument: it will return piano!
215 SCM minstr = get_property ("midiInstrument");
217 if (!scm_is_string (minstr)
218 || ly_scm2string (minstr) == instrument_string_)
221 instrument_string_ = ly_scm2string (minstr);
223 return instrument_string_;
227 Staff_performer::get_channel (string instrument)
229 SCM channel_mapping = get_property ("midiChannelMapping");
230 map<string, int>& channel_map
231 = (channel_mapping != ly_symbol2scm ("instrument"))
233 : static_channel_map_;
235 if (channel_mapping == ly_symbol2scm ("staff")
239 map<string, int>::const_iterator i = channel_map.find (instrument);
240 if (i != channel_map.end ())
243 int channel = (channel_mapping == ly_symbol2scm ("staff"))
245 : channel_map.size ();
247 /* MIDI players tend to ignore instrument settings on channel
248 10, the percussion channel. */
249 if (channel % 16 == 9)
251 channel_map["percussion"] = channel++;
257 warning (_ ("MIDI channel wrapped around"));
258 warning (_ ("remapping modulo 16"));
259 channel = channel % 16;
262 channel_map[instrument] = channel;
267 Staff_performer::acknowledge_audio_element (Audio_element_info inf)
269 if (Audio_item *ai = dynamic_cast<Audio_item *> (inf.elem_))
271 /* map each context (voice) to its own track */
272 Context *c = inf.origin_contexts (this)[0];
274 if (c->is_alias (ly_symbol2scm ("Voice")))
275 voice = c->id_string ();
276 SCM channel_mapping = get_property ("midiChannelMapping");
277 string str = new_instrument_string ();
278 if (channel_mapping != ly_symbol2scm ("instrument"))
279 channel_ = get_channel (voice);
280 else if (channel_ < 0 && str.empty ())
281 channel_ = get_channel (str);
284 if (channel_mapping != ly_symbol2scm ("voice"))
285 channel_ = get_channel (str);
286 set_instrument (channel_, voice);
287 set_instrument_name (voice);
289 ai->channel_ = channel_;
290 bool encode_dynamics_as_velocity_ = true;
291 if (encode_dynamics_as_velocity_)
293 if (Audio_dynamic *d = dynamic_cast<Audio_dynamic *> (inf.elem_))
295 dynamic_map_[voice] = d;
296 // Output volume as velocity: must disable Midi_dynamic output
299 if (Audio_dynamic *d = get_dynamic (voice))
300 if (Audio_note *n = dynamic_cast<Audio_note *> (inf.elem_))
303 Audio_staff *audio_staff = get_audio_staff (voice);
304 audio_staff->add_audio_item (ai);