]> git.donarmstrong.com Git - lilypond.git/blob - lily/staff-performer.cc
Imported Upstream version 2.14.2
[lilypond.git] / lily / staff-performer.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2011 Jan Nieuwenhuizen <janneke@gnu.org>
5
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.
10
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.
15
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/>.
18 */
19
20 #include <map>
21
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"
29
30 /* Perform a staff. Individual notes should have their instrument
31   (staff-wide) set, so we override play_element ()
32 */
33 class Staff_performer : public Performer
34 {
35 public:
36   TRANSLATOR_DECLARATIONS (Staff_performer);
37   ~Staff_performer ();
38
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 ();
45
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   Audio_dynamic* get_dynamic (string voice);
54
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, Audio_dynamic*> dynamic_map_;
64   static map<string, int> static_channel_map_;
65   static int channel_count_;
66 };
67
68 map<string, int> Staff_performer::static_channel_map_;
69 int Staff_performer::channel_count_ = 0;
70
71 #include "translator.icc"
72
73 ADD_TRANSLATOR (Staff_performer,
74                 /* doc */
75                 "",
76
77                 /* create */
78                 "",
79
80                 /* read */
81                 "",
82
83                 /* write */
84                 "");
85
86 Staff_performer::Staff_performer ()
87   : channel_ (-1)
88   , instrument_ (0)
89   , instrument_name_ (0)
90   , name_ (0)
91   , tempo_ (0)
92 {
93 }
94
95 Staff_performer::~Staff_performer ()
96 {
97 }
98
99 void
100 Staff_performer::initialize ()
101 {
102 }
103
104 Audio_staff*
105 Staff_performer::new_audio_staff (string voice)
106 {
107   Audio_staff* audio_staff = new Audio_staff;
108   audio_staff->merge_unisons_
109     = to_boolean (get_property ("midiMergeUnisons"));
110   string track_name = context ()->id_string () + ":" + voice;
111   if (track_name != ":")
112     {
113       name_ = new Audio_text (Audio_text::TRACK_NAME, context ()->id_string ()
114                               + ":" + voice);
115       audio_staff->add_audio_item (name_);
116       announce_element (Audio_element_info (name_, 0));
117     }
118   announce_element (Audio_element_info (audio_staff, 0));
119   staff_map_[voice] = audio_staff;
120   if (!instrument_string_.empty ())
121     set_instrument (channel_, voice);
122   return audio_staff;
123 }
124
125 Audio_staff*
126 Staff_performer::get_audio_staff (string voice)
127 {
128   SCM channel_mapping = get_property ("midiChannelMapping");
129   if (channel_mapping != ly_symbol2scm ("instrument")
130       && staff_map_.size ())
131     return staff_map_.begin ()->second;
132
133   map<string, Audio_staff*>::const_iterator i = staff_map_.find (voice);
134   if (i != staff_map_.end ())
135     return i->second;
136   map<string, Audio_staff*>::const_iterator e = staff_map_.find ("");
137   if (staff_map_.size () == 1 && e != staff_map_.end ())
138     {
139       staff_map_[voice] = e->second;
140       return e->second;
141     }
142   return new_audio_staff (voice);
143 }
144
145 Audio_dynamic*
146 Staff_performer::get_dynamic (string voice)
147 {
148   map<string, Audio_dynamic*>::const_iterator i = dynamic_map_.find (voice);
149   if (i != dynamic_map_.end ())
150     return i->second;
151   return 0;
152 }
153
154 void
155 Staff_performer::process_music ()
156 {
157 }
158
159 void
160 Staff_performer::set_instrument (int channel, string voice)
161 {
162   instrument_ = new Audio_instrument (instrument_string_);
163   instrument_->channel_ = channel;
164   announce_element (Audio_element_info (instrument_, 0));
165   Audio_staff* audio_staff = get_audio_staff (voice);
166   audio_staff->add_audio_item (instrument_);
167   SCM proc = ly_lily_module_constant ("percussion?");
168   SCM drums = scm_call_1 (proc, ly_symbol2scm (instrument_string_.c_str ()));
169   audio_staff->percussion_ = (drums == SCM_BOOL_T);
170 }
171
172 void
173 Staff_performer::set_instrument_name (string voice)
174 {
175   instrument_name_ = new Audio_text (Audio_text::INSTRUMENT_NAME,
176                                      instrument_string_);
177   announce_element (Audio_element_info (instrument_name_, 0));
178   get_audio_staff (voice)->add_audio_item (instrument_name_);
179 }
180
181 void
182 Staff_performer::stop_translation_timestep ()
183 {
184   name_ = 0;
185   tempo_ = 0;
186   instrument_name_ = 0;
187   instrument_ = 0;
188 }
189
190 void
191 Staff_performer::finalize ()
192 {
193   staff_map_.clear ();
194   channel_map_.clear ();
195 }
196
197 string
198 Staff_performer::new_instrument_string ()
199 {
200   // mustn't ask Score for instrument: it will return piano!
201   SCM minstr = get_property ("midiInstrument");
202
203   if (!scm_is_string (minstr)
204       || ly_scm2string (minstr) == instrument_string_)
205     return "";
206
207   instrument_string_ = ly_scm2string (minstr);
208
209   return instrument_string_;
210 }
211
212 int
213 Staff_performer::get_channel (string instrument)
214 {
215   SCM channel_mapping = get_property ("midiChannelMapping");
216   map<string, int>& channel_map
217     = (channel_mapping != ly_symbol2scm ("instrument"))
218     ? channel_map_
219     : static_channel_map_;
220
221   if (channel_mapping == ly_symbol2scm ("staff")
222       && channel_ >= 0)
223     return channel_;
224
225   map<string, int>::const_iterator i = channel_map.find (instrument);
226   if (i != channel_map.end ())
227     return i->second;
228  
229   int channel = (channel_mapping == ly_symbol2scm ("staff"))
230     ? channel_count_++
231     : channel_map.size ();
232
233   /* MIDI players tend to ignore instrument settings on channel
234      10, the percussion channel.  */
235   if (channel % 16 == 9)
236     {
237       channel_map["percussion"] = channel++;
238       channel_count_++;
239     }
240
241   if (channel > 15)
242     {
243       warning (_ ("MIDI channel wrapped around"));
244       warning (_ ("remapping modulo 16"));
245       channel = channel % 16; 
246     }
247
248   channel_map[instrument] = channel;
249   return channel;
250 }
251
252 void
253 Staff_performer::acknowledge_audio_element (Audio_element_info inf)
254 {
255   if (Audio_item *ai = dynamic_cast<Audio_item *> (inf.elem_))
256     {
257       /* map each context (voice) to its own track */
258       Context* c = inf.origin_contexts (this)[0];
259       string voice;
260       if (c->is_alias (ly_symbol2scm ("Voice")))
261         voice = c->id_string ();
262       SCM channel_mapping = get_property ("midiChannelMapping");
263       string str = new_instrument_string ();
264       if (channel_mapping != ly_symbol2scm ("instrument"))
265         channel_ = get_channel (voice);
266       else if (channel_ < 0 && str.empty ())
267         channel_ = get_channel (str);
268       if (str.length ())
269         {
270           if (channel_mapping != ly_symbol2scm ("voice"))
271             channel_ = get_channel (str);
272           set_instrument (channel_, voice);
273           set_instrument_name (voice);
274         }
275       ai->channel_ = channel_;
276       bool encode_dynamics_as_velocity_ = true;
277       if (encode_dynamics_as_velocity_)
278         {
279           if (Audio_dynamic *d = dynamic_cast<Audio_dynamic *> (inf.elem_))
280             {
281               dynamic_map_[voice] = d;
282               // Output volume as velocity: must disable Midi_dynamic output
283               d->silent_ = true;
284             }
285           if (Audio_dynamic *d = get_dynamic (voice))
286             if (Audio_note *n = dynamic_cast<Audio_note *> (inf.elem_))
287               n->dynamic_ = d;
288         }
289       Audio_staff* audio_staff = get_audio_staff (voice);
290       audio_staff->add_audio_item (ai);
291     }
292 }
293