]> git.donarmstrong.com Git - lilypond.git/blob - lily/span-dynamic-performer.cc
89f236ade30df0a8ba63d21554ab1270f9ca68a8
[lilypond.git] / lily / span-dynamic-performer.cc
1 /*
2   span-dynamic-performer.cc -- implement Span_dynamic_performer
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  2000 Jan Nieuwenhuizen <janneke@gnu.org>
7 */
8
9 #include "performer.hh"
10
11 #include "event.hh"
12 #include "audio-item.hh"
13
14 struct Audio_dynamic_tuple
15 {
16   Audio_dynamic* audio_;
17   Moment mom_;
18 };
19
20 /**
21    perform span-dynamics
22  */
23 class Span_dynamic_performer : public Performer
24 {
25 public:
26   TRANSLATOR_DECLARATIONS(Span_dynamic_performer);
27
28 protected:
29   virtual bool try_music (Music*);
30   virtual void acknowledge_audio_element (Audio_element_info);
31   virtual void process_music ();
32   virtual void stop_translation_timestep ();
33   virtual void start_translation_timestep ();
34
35 private:
36   Audio_dynamic* audio_;
37   Real last_volume_;
38   Music* span_start_req_;
39   Drul_array<Music*> span_req_l_drul_;
40   Array<Audio_dynamic_tuple> dynamic_tuples_;
41   Array<Audio_dynamic_tuple> finished_dynamic_tuples_;
42   Direction dir_;
43   Direction finished_dir_;
44 };
45
46 Span_dynamic_performer::Span_dynamic_performer ()
47 {
48   span_req_l_drul_[START] = 0;
49   span_req_l_drul_[STOP] = 0;
50   span_start_req_ = 0;
51   audio_ = 0;
52   last_volume_ = 0;
53 }
54
55 void
56 Span_dynamic_performer::acknowledge_audio_element (Audio_element_info i)
57 {
58   if (Audio_dynamic * d = dynamic_cast <Audio_dynamic*> (i.elem_))
59     {
60       last_volume_ = d->volume_;
61     }
62 }
63
64 void
65 Span_dynamic_performer::process_music ()
66 {
67   if (span_start_req_ || span_req_l_drul_[START])
68     {
69       audio_ = new Audio_dynamic (0);
70       Audio_element_info info (audio_, span_req_l_drul_[START]
71                                ? span_req_l_drul_[START]
72                                : span_req_l_drul_[STOP]);
73       announce_element (info);
74       Audio_dynamic_tuple a = { audio_, now_mom () };
75       dynamic_tuples_.push (a);
76     }
77   
78   if (span_req_l_drul_[STOP])
79     {
80       if (!span_start_req_)
81         {
82           span_req_l_drul_[STOP]->origin ()->warning (_ ("can't find start of (de)crescendo"));
83           span_req_l_drul_[STOP] = 0;
84         }
85       else
86         {
87           finished_dir_ = dir_;
88           finished_dynamic_tuples_ = dynamic_tuples_;
89         }
90       dynamic_tuples_.clear ();
91       span_start_req_ = 0;
92     }
93
94   if (span_req_l_drul_[START])
95     {
96       String t = ly_scm2string (span_req_l_drul_[START]->get_mus_property ("span-type"));
97       dir_ = (t == "crescendo") ? RIGHT : LEFT;
98       span_start_req_ = span_req_l_drul_[START];
99       
100       dynamic_tuples_.clear ();
101       Audio_dynamic_tuple a = { audio_, now_mom () };
102       dynamic_tuples_.push (a);
103     }
104
105
106   if (span_req_l_drul_[STOP])
107     { 
108       finished_dynamic_tuples_.top ().audio_->volume_ = last_volume_;
109     }
110   
111   if (span_req_l_drul_[START])
112     {
113       dynamic_tuples_[0].audio_->volume_ = last_volume_;
114     }
115   span_start_req_ = 0;
116   span_req_l_drul_[START] = 0;
117   span_req_l_drul_[STOP] = 0;
118 }
119
120 void
121 Span_dynamic_performer::stop_translation_timestep ()
122 {
123   if (finished_dynamic_tuples_.size () > 1)
124     {
125       Real start_volume = finished_dynamic_tuples_[0].audio_->volume_;
126       Real dv = finished_dynamic_tuples_.top ().audio_->volume_
127         - start_volume;
128       /*
129         urg.
130         Catch and fix the case of:
131
132              |                         |
133             x|                        x|
134             f cresc.  -- -- -- -- --  pp 
135
136          Actually, we should provide a non-displayed dynamic/volume setting,
137          to set volume to 'ff' just before the pp.
138        */
139       if (!dv || sign (dv) != finished_dir_)
140         {
141           // urg.  20%: about two volume steps
142           dv = (Real)finished_dir_ * 0.2;
143           if (!start_volume)
144             start_volume = finished_dynamic_tuples_.top
145  ().audio_->volume_ - dv;
146         }
147       Moment start_mom = finished_dynamic_tuples_[0].mom_;
148       Moment dt = finished_dynamic_tuples_.top ().mom_ - start_mom;
149       for (int i=0; i < finished_dynamic_tuples_.size (); i++)
150         {
151           Audio_dynamic_tuple* a = &finished_dynamic_tuples_[i];
152           Real volume = start_volume + dv * (Real) (a->mom_ - start_mom).main_part_
153             / (Real)dt.main_part_;
154           a->audio_->volume_ = volume;
155         }
156       finished_dynamic_tuples_.clear ();
157     }
158
159   if (audio_)
160     {
161       play_element (audio_);
162       audio_ = 0;
163     }
164 }
165
166 void
167 Span_dynamic_performer::start_translation_timestep ()
168 {
169   span_req_l_drul_[STOP] = 0;
170   span_req_l_drul_[START] = 0;
171 }
172
173 bool
174 Span_dynamic_performer::try_music (Music* r)
175 {
176   if (r->is_mus_type ("crescendo-event")
177       || r->is_mus_type ("decrescendo-event"))
178     {
179       Direction d = to_dir (r->get_mus_property ("span-direction"));
180       span_req_l_drul_[d] = r;
181       return true;
182     }
183   return false;
184 }
185 ENTER_DESCRIPTION (Span_dynamic_performer,
186                    "", "",
187                    "crescendo-event decrescendo-event", 
188                    "", "", "");