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