1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//! Ranked serial-row extraction hypotheses and stable evidence records.
use sim_lib_music_core::{ObjectId, Time};
use sim_lib_pitch_serial::{RowClassAlias, ToneRow};
/// Exact half-open span used by extracted serial evidence.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct SerialTimeSpan {
/// Inclusive start.
pub start: Time,
/// Exclusive end.
pub end: Time,
}
impl SerialTimeSpan {
/// Builds an ordered half-open span.
pub fn new(start: Time, end: Time) -> Self {
debug_assert!(start <= end);
Self { start, end }
}
/// Returns the exact duration.
pub fn duration(&self) -> Time {
self.end - self.start
}
}
/// Stable sort key used when ranking extraction hypotheses.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct SerialStableRank {
/// Count of missing pitch classes from a complete twelve-tone aggregate.
pub omissions: usize,
/// Count of repeated pitch classes observed before aggregate completion.
pub duplicates_before_completion: usize,
/// Count of repeated pitch classes observed after aggregate completion.
pub order_errors: usize,
/// Exact span from the first contributing attack to the last contributing release.
pub occupied_span: Time,
/// Stable tie-breaker derived from the chosen attack ordering.
pub stable_key: String,
}
/// Ordering policy selected for one same-onset attack block.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum SerialReadingOrder {
/// Preserve the canonical exact-window note order.
WindowOrder,
/// Sort equal-onset attacks by pitch, low to high.
PitchAscending,
/// Sort equal-onset attacks by pitch, high to low.
PitchDescending,
/// Sort equal-onset attacks by voice id, low to high.
VoiceAscending,
/// Sort equal-onset attacks by voice id, high to low.
VoiceDescending,
}
impl SerialReadingOrder {
/// Stable machine-readable name.
pub const fn as_str(self) -> &'static str {
match self {
Self::WindowOrder => "window-order",
Self::PitchAscending => "pitch-ascending",
Self::PitchDescending => "pitch-descending",
Self::VoiceAscending => "voice-ascending",
Self::VoiceDescending => "voice-descending",
}
}
}
/// One note attack cited by a ranked hypothesis.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SerialObservation {
/// Voice identity.
pub voice_id: ObjectId,
/// Source note identity.
pub note_id: ObjectId,
/// Source event identity.
pub event_id: ObjectId,
/// Zero-based pitch-class ordinal in the hypothesis row.
pub ordinal: usize,
/// Exact source attack span inherited from the sounding-window partition.
pub span: SerialTimeSpan,
}
/// One exact same-onset block chosen during extraction.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SerialObservationBlock {
/// Exact span for the block's source sounding window.
pub span: SerialTimeSpan,
/// Ordering policy chosen for this block.
pub order: SerialReadingOrder,
/// Notes contributing new or repeated row evidence in chosen order.
pub observations: Vec<SerialObservation>,
}
/// Alias evidence attached to a ranked row hypothesis.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SerialAliasEvidence {
/// The alias operation preserved by the observed row class.
pub alias: RowClassAlias,
/// Stable printable form such as `P0` or `RI11`.
pub label: String,
}
/// One ranked hypothesis extracted from exact source attacks.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RankedSerialHypothesis {
/// Stable ranking key; lower values are stronger.
pub stable_rank: SerialStableRank,
/// Observed row order inferred from first pitch-class occurrence.
pub row: ToneRow,
/// Exact same-onset blocks cited by the hypothesis.
pub blocks: Vec<SerialObservationBlock>,
/// Count of repeated pitch classes seen before aggregate completion.
pub duplicates_before_completion: usize,
/// Count of repeated pitch classes seen after aggregate completion.
pub order_errors: usize,
/// Missing pitch classes relative to an exact twelve-tone aggregate.
pub omissions: usize,
/// Exact span covered by the hypothesis.
pub span: SerialTimeSpan,
/// P/I/R/RI alias evidence for the observed row class.
pub aliases: Vec<SerialAliasEvidence>,
}