Skip to main content

plato_midi_bridge/
lib.rs

1//! Plato-MIDI Bridge — Style decomposition for MIDI with Eisenstein lattices and Penrose tilings.
2//!
3//! ## Core Types
4//!
5//! - `StyleVector` — 109-dimensional musical style vector
6//! - `EisensteinLattice` — 12-chamber hexagonal lattice encoding
7//! - `PenroseEncoder` — 5D cut-and-project tiling encoding
8//! - `ScaleLevel` — Multi-scale analysis (micro, note, phrase, section, piece)
9//!
10//! ## Usage
11//!
12//! ```rust
13//! use plato_midi_bridge::{StyleVector, EisensteinLattice, PenroseEncoder, PHI};
14//!
15//! // Create a style vector from raw features
16//! let style = StyleVector::new(&[0.5; 109]);
17//!
18//! // Encode in Eisenstein lattice
19//! let coupling = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0];
20//! let chamber = EisensteinLattice::chamber(&coupling);
21//! assert!(chamber < 12);
22//!
23//! // Encode in Penrose tiling
24//! let encoder = PenroseEncoder::new(None);
25//! let v = [1.0, 0.5, 0.7, 0.3, 0.6];
26//! let (px, py, accepted) = encoder.encode(&v);
27//! assert!(accepted);
28//! ```
29
30mod eisenstein;
31mod penrose;
32mod style;
33mod multiscale;
34
35pub use eisenstein::EisensteinLattice;
36pub use penrose::PenroseEncoder;
37pub use style::StyleVector;
38pub use multiscale::ScaleLevel;
39
40use std::f64::consts::PI;
41
42/// Golden ratio φ = (1 + √5) / 2
43pub const PHI: f64 = 1.6180339887498948482045868343656381177;
44
45/// The 5th roots of unity for Penrose projection
46pub const FIFTH_ROOTS: [(f64, f64); 5] = [
47    (1.0, 0.0),
48    (0.30901699437494745, 0.9510565162951535),   // e^{2πi/5}
49    (-0.8090169943749473, 0.5877852522924732),    // e^{4πi/5}
50    (-0.8090169943749475, -0.5877852522924730),   // e^{6πi/5}
51    (0.30901699437494723, -0.9510565162951536),   // e^{8πi/5}
52];
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    #[test]
59    fn test_phi_precision() {
60        assert!((PHI - 1.618033988749895).abs() < 1e-14);
61    }
62
63    #[test]
64    fn test_fifth_roots_length() {
65        assert_eq!(FIFTH_ROOTS.len(), 5);
66        for (re, im) in &FIFTH_ROOTS {
67            let mag = (re * re + im * im).sqrt();
68            assert!((mag - 1.0).abs() < 1e-14, "Root magnitude should be 1, got {}", mag);
69        }
70    }
71}