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