music21_rs/pitch/
display.rs1use super::*;
6
7impl Pitch {
8 pub fn name_in_key_signature(&self, altered_pitches: &[Pitch]) -> bool {
12 if !self.has_accidental {
13 return false;
14 }
15 altered_pitches.iter().any(|p| {
16 p.step == self.step && p.has_accidental && p.accidental.name() == self.accidental.name()
17 })
18 }
19
20 pub fn step_in_key_signature(&self, altered_pitches: &[Pitch]) -> bool {
23 altered_pitches.iter().any(|p| p.step == self.step)
24 }
25
26 pub(super) fn set_display_status_creating(&mut self, status: bool) {
27 if !self.has_accidental {
28 self.accidental = Accidental::natural();
29 self.has_accidental = true;
30 }
31 self.accidental.set_display_status(Some(status));
32 }
33
34 pub fn update_accidental_display(&mut self, options: &AccidentalDisplayOptions<'_>) {
40 let altered = options.altered_pitches;
41 let past_all: Vec<&Pitch> = options
42 .pitch_past_measure
43 .iter()
44 .chain(options.pitch_past.iter())
45 .collect();
46 let mut display_if_no_previous_accidentals = false;
47
48 if !options.override_status
49 && self.has_accidental
50 && self.accidental.display_status().is_some()
51 {
52 return;
53 }
54 if self.has_accidental && self.accidental.display_type() == "never" {
55 self.accidental.set_display_status(Some(false));
56 return;
57 }
58 if options.last_note_was_tied {
59 if self.has_accidental {
60 let even_tied = self.accidental.display_type() == "even-tied";
61 self.accidental.set_display_status(Some(even_tied));
62 }
63 return;
64 }
65 if options.cautionary_pitch_class
66 && options
67 .other_simultaneous_pitches
68 .iter()
69 .any(|p| p.step == self.step && p.pitch_class() != self.pitch_class())
70 {
71 self.set_display_status_creating(true);
72 return;
73 }
74 if options.cautionary_all
75 || (self.has_accidental
76 && matches!(self.accidental.display_type(), "even-tied" | "always"))
77 {
78 self.set_display_status_creating(true);
79 return;
80 }
81 if past_all.is_empty() {
82 if self.has_accidental
83 && (options.override_status || self.accidental.display_status() != Some(true))
84 {
85 let status = if self.accidental.name() == "natural" {
86 self.step_in_key_signature(altered)
87 } else {
88 !self.name_in_key_signature(altered)
89 };
90 self.accidental.set_display_status(Some(status));
91 } else if self.has_accidental
92 && self.accidental.display_status() == Some(true)
93 && self.name_in_key_signature(altered)
94 {
95 self.accidental.set_display_status(Some(false));
96 } else if (!self.has_accidental || self.accidental.name() == "natural")
97 && self.step_in_key_signature(altered)
98 {
99 self.set_display_status_creating(true);
100 }
101 return;
102 }
103 for past in options.pitch_past.iter().rev() {
104 if past.step == self.step && past.octave == self.octave {
105 if past.name() != self.name() {
106 self.set_display_status_creating(true);
107 return;
108 }
109 break;
110 }
111 }
112 let mut set_from_pitch_past = false;
113 let out_of_measure_length = options.pitch_past_measure.len();
114 let self_name = self.name();
115 let self_name_with_octave = self.name_with_octave();
116 let name_in_key = self.name_in_key_signature(altered);
117 let step_in_key = self.step_in_key_signature(altered);
118 let if_absolutely_necessary =
119 self.has_accidental && self.accidental.display_type() == "if-absolutely-necessary";
120 for i in (0..past_all.len()).rev() {
121 let past_in_measure = i >= out_of_measure_length;
122 let continuous_repeats_in_measure = past_in_measure
123 && past_all[i..]
124 .iter()
125 .all(|p| p.name_with_octave() == self_name_with_octave);
126 if !past_in_measure && if_absolutely_necessary {
127 break;
128 }
129 if !past_in_measure
130 && self.has_accidental
131 && self.accidental.name() != "natural"
132 && !name_in_key
133 {
134 self.accidental.set_display_status(Some(true));
135 return;
136 }
137 let past = past_all[i];
138 if past.step != self.step {
139 continue;
140 }
141 let octave_match = self.octave == past.octave;
142 let past_acc = past.explicit_accidental();
143 let past_name = past_acc.map(Accidental::name);
144 let past_status = past_acc.and_then(Accidental::display_status);
145 let self_acc_name = self
146 .has_accidental
147 .then(|| self.accidental.name().to_string());
148 let self_status = self
149 .has_accidental
150 .then(|| self.accidental.display_status())
151 .flatten();
152
153 if continuous_repeats_in_measure && past_status == Some(true) {
154 if self.has_accidental {
155 self.accidental.set_display_status(Some(false));
156 }
157 return;
158 } else if continuous_repeats_in_measure
159 && past_acc.is_some()
160 && self_acc_name.is_some()
161 && past_name == self_acc_name.as_deref()
162 {
163 if !name_in_key && (!octave_match || past_status == Some(false)) {
164 display_if_no_previous_accidentals = true;
165 continue;
166 }
167 self.accidental.set_display_status(Some(false));
168 set_from_pitch_past = true;
169 break;
170 } else if past_name == Some("natural")
171 && (self_acc_name.is_none() || self_acc_name.as_deref() == Some("natural"))
172 {
173 if continuous_repeats_in_measure {
174 if step_in_key && !octave_match {
175 self.set_display_status_creating(true);
176 } else if self.has_accidental {
177 self.accidental.set_display_status(Some(false));
178 }
179 } else if step_in_key
180 && (options.cautionary_not_immediate_repeat || !past_in_measure)
181 {
182 self.set_display_status_creating(true);
183 } else if self.has_accidental {
184 self.accidental.set_display_status(Some(false));
185 }
186 set_from_pitch_past = true;
187 break;
188 } else if past_acc.is_some()
189 && past.name() != self_name
190 && past_name != Some("natural")
191 && (self_acc_name.is_none() || self_status == Some(false))
192 {
193 if !octave_match && !options.cautionary_pitch_class {
194 continue;
195 }
196 if !octave_match && if_absolutely_necessary {
197 continue;
198 }
199 self.set_display_status_creating(true);
200 set_from_pitch_past = true;
201 break;
202 } else if self_acc_name.is_some()
203 && (((past_acc.is_none() || past_name == Some("natural"))
204 && self_acc_name.as_deref() != Some("natural"))
205 || (past_acc.is_some()
206 && past_name != self_acc_name.as_deref()
207 && (octave_match || !if_absolutely_necessary)))
208 {
209 self.accidental.set_display_status(Some(true));
210 set_from_pitch_past = true;
211 break;
212 } else if past_acc.is_none() && self_acc_name.is_some() {
213 let status = if self_acc_name.as_deref() == Some("natural") {
214 step_in_key
215 } else {
216 true
217 };
218 self.accidental.set_display_status(Some(status));
219 set_from_pitch_past = true;
220 break;
221 } else if !continuous_repeats_in_measure
222 && past_acc.is_some()
223 && self_acc_name.is_some()
224 && past_name == self_acc_name.as_deref()
225 && octave_match
226 {
227 if !options.cautionary_not_immediate_repeat && past_status != Some(false) {
228 self.accidental.set_display_status(Some(false));
229 display_if_no_previous_accidentals = false;
230 set_from_pitch_past = true;
231 break;
232 } else if past_status == Some(false) {
233 display_if_no_previous_accidentals = true;
234 } else {
235 self.accidental.set_display_status(Some(!name_in_key));
236 return;
237 }
238 }
239 }
240 if display_if_no_previous_accidentals {
241 if !name_in_key {
242 self.set_display_status_creating(true);
243 } else if self.has_accidental {
244 self.accidental.set_display_status(Some(false));
245 }
246 } else if !set_from_pitch_past && self.has_accidental {
247 let status = if self.accidental.name() == "natural" {
248 step_in_key
249 } else {
250 !name_in_key
251 };
252 self.accidental.set_display_status(Some(status));
253 } else if !set_from_pitch_past && step_in_key {
254 self.set_display_status_creating(true);
255 }
256 }
257}
258
259#[derive(Clone, Debug)]
264pub struct AccidentalDisplayOptions<'a> {
265 pub pitch_past: &'a [Pitch],
267 pub pitch_past_measure: &'a [Pitch],
269 pub other_simultaneous_pitches: &'a [Pitch],
271 pub altered_pitches: &'a [Pitch],
273 pub cautionary_pitch_class: bool,
275 pub cautionary_all: bool,
277 pub override_status: bool,
279 pub cautionary_not_immediate_repeat: bool,
282 pub last_note_was_tied: bool,
284}
285
286impl Default for AccidentalDisplayOptions<'_> {
287 fn default() -> Self {
288 Self {
289 pitch_past: &[],
290 pitch_past_measure: &[],
291 other_simultaneous_pitches: &[],
292 altered_pitches: &[],
293 cautionary_pitch_class: true,
294 cautionary_all: false,
295 override_status: false,
296 cautionary_not_immediate_repeat: true,
297 last_note_was_tied: false,
298 }
299 }
300}