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/>.
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 Real
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
, 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
,
86 Staff_performer::Staff_performer ()
89 , instrument_name_ (0)
95 Staff_performer::~Staff_performer ()
100 Staff_performer::initialize ()
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 ()
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
);
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 ())
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
;
140 return new_audio_staff (voice
);
144 Staff_performer::get_dynamic (string voice
)
146 map
<string
, Real
>::const_iterator i
= dynamic_map_
.find (voice
);
147 if (i
!= dynamic_map_
.end ())
153 Staff_performer::process_music ()
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
);
171 Staff_performer::set_instrument_name (string voice
)
173 instrument_name_
= new Audio_text (Audio_text::INSTRUMENT_NAME
,
175 announce_element (Audio_element_info (instrument_name_
, 0));
176 get_audio_staff (voice
)->add_audio_item (instrument_name_
);
180 Staff_performer::stop_translation_timestep ()
184 instrument_name_
= 0;
189 Staff_performer::finalize ()
192 channel_map_
.clear ();
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_
)
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"))
217 : static_channel_map_
;
219 map
<string
, int>::const_iterator i
= channel_map
.find (instrument
);
220 if (i
!= channel_map
.end ())
223 int channel
= (channel_mapping
== ly_symbol2scm ("staff"))
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
++;
237 warning (_ ("MIDI channel wrapped around"));
238 warning (_ ("remapping modulo 16"));
239 channel
= channel
% 16;
242 channel_map
[instrument
] = channel
;
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];
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 ();
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_
;
275 if (Real d
= get_dynamic (voice
))
276 if (Audio_note
*n
= dynamic_cast<Audio_note
*> (inf
.elem_
))
278 audio_staff
->add_audio_item (ai
);