]> git.donarmstrong.com Git - lilypond.git/blob - lily/staff-performer.cc
Midi: set instrument for each voice (on each channel).
[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 "warn.hh"
23 #include "audio-column.hh"
24 #include "audio-item.hh"
25 #include "audio-staff.hh"
26 #include "performer-group.hh"
27 #include "context.hh"
28
29 /* Perform a staff. Individual notes should have their instrument
30   (staff-wide) set, so we override play_element ()
31 */
32 class Staff_performer : public Performer
33 {
34 public:
35   TRANSLATOR_DECLARATIONS (Staff_performer);
36   ~Staff_performer ();
37
38   string new_instrument_string ();
39   string instrument_string_;
40
41 protected:
42   virtual void acknowledge_audio_element (Audio_element_info info);
43   virtual void finalize ();
44   virtual void initialize ();
45   void process_music ();
46   void stop_translation_timestep ();
47   void set_instrument_name ();
48   void set_instrument (int channel);
49
50 private:
51   Audio_staff *audio_staff_;
52   Audio_instrument *instrument_;
53   Audio_text *instrument_name_;
54   Audio_text *name_;
55   Audio_tempo *tempo_;
56   map<string, int> channel_map_;
57 };
58
59 #include "translator.icc"
60
61 ADD_TRANSLATOR (Staff_performer,
62                 /* doc */
63                 "",
64
65                 /* create */
66                 "",
67
68                 /* read */
69                 "",
70
71                 /* write */
72                 "");
73
74 Staff_performer::Staff_performer ()
75 {
76   audio_staff_ = 0;
77   instrument_ = 0;
78   instrument_name_ = 0;
79   name_ = 0;
80   tempo_ = 0;
81 }
82
83 Staff_performer::~Staff_performer ()
84 {
85 }
86
87 void
88 Staff_performer::initialize ()
89 {
90   audio_staff_ = new Audio_staff;
91   name_ = new Audio_text (Audio_text::TRACK_NAME, context ()->id_string ());
92
93   audio_staff_->add_audio_item (name_);
94   
95   announce_element (Audio_element_info (audio_staff_, 0));
96   announce_element (Audio_element_info (name_, 0));
97 }
98
99 void
100 Staff_performer::process_music ()
101 {
102   string str = new_instrument_string ();
103   if (str.length ())
104     {
105       set_instrument (0);
106       set_instrument_name ();
107     }
108 }
109
110 void
111 Staff_performer::set_instrument (int channel)
112 {
113   instrument_ = new Audio_instrument (instrument_string_);
114   instrument_->channel_ = channel;
115   announce_element (Audio_element_info (instrument_, 0));
116   audio_staff_->add_audio_item (instrument_);
117 }
118
119 void
120 Staff_performer::set_instrument_name ()
121 {
122   instrument_name_ = new Audio_text (Audio_text::INSTRUMENT_NAME,
123                                      instrument_string_);
124   announce_element (Audio_element_info (instrument_name_, 0));
125   audio_staff_->add_audio_item (instrument_name_);
126 }
127
128 void
129 Staff_performer::stop_translation_timestep ()
130 {
131   SCM proc = ly_lily_module_constant ("percussion?");
132   SCM drums = scm_call_1 (proc, ly_symbol2scm (instrument_string_.c_str ()));
133   audio_staff_->percussion_ = (drums == SCM_BOOL_T);
134
135   name_ = 0;
136   tempo_ = 0;
137   instrument_name_ = 0;
138   instrument_ = 0;
139 }
140
141 void
142 Staff_performer::finalize ()
143 {
144   audio_staff_ = 0;
145 }
146
147 string
148 Staff_performer::new_instrument_string ()
149 {
150   // mustn't ask Score for instrument: it will return piano!
151   SCM minstr = get_property ("midiInstrument");
152
153   if (!scm_is_string (minstr)
154       || ly_scm2string (minstr) == instrument_string_)
155     return "";
156
157   instrument_string_ = ly_scm2string (minstr);
158
159   return instrument_string_;
160 }
161
162 void
163 Staff_performer::acknowledge_audio_element (Audio_element_info inf)
164 {
165   if (Audio_item *ai = dynamic_cast<Audio_item *> (inf.elem_))
166     {
167       /* map each context (voice) to its own channel */
168       Context *c = inf.origin_contexts (this)[0];
169       string id = c->id_string ();
170       int channel = channel_map_.size ();
171       /* MIDI players tend to ignore instrument settings on channel
172          10, the percussion channel.  */
173       if (channel % 16 == 9)
174         channel_map_[""] = channel++;
175
176       map<string, int>::const_iterator i = channel_map_.find (id);
177       if (i != channel_map_.end ())
178         channel = i->second;
179       else
180         {
181           channel_map_[id] = channel;
182           if (channel)
183             set_instrument (channel);
184         }
185
186       ai->channel_ = channel;
187       audio_staff_->add_audio_item (ai);
188     }
189 }
190