pub fn generate(length: usize, steps_per_octave: u32, direction: bool) -> Vec<u32> {
if length == 0 || steps_per_octave == 0 {
return vec![];
}
(0..length)
.map(|i| {
if direction {
(i as u32) % steps_per_octave
} else {
let offset = (i as u32) % steps_per_octave;
if offset == 0 {
0
} else {
steps_per_octave - offset
}
}
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_shepard_tone_ascending() {
let tone = generate(24, 12, true);
assert_eq!(tone.len(), 24);
assert_eq!(tone[0], 0);
assert_eq!(tone[1], 1);
assert_eq!(tone[11], 11);
assert_eq!(tone[12], 0); assert_eq!(tone[23], 11);
}
#[test]
fn test_shepard_tone_descending() {
let tone = generate(13, 12, false);
assert_eq!(tone.len(), 13);
assert_eq!(tone[0], 0);
assert_eq!(tone[1], 11);
assert_eq!(tone[2], 10);
assert_eq!(tone[11], 1);
assert_eq!(tone[12], 0); }
#[test]
fn test_shepard_tone_properties() {
let ascending = generate(100, 12, true);
let descending = generate(100, 12, false);
for &val in &ascending {
assert!(val < 12);
}
for &val in &descending {
assert!(val < 12);
}
let mut seen = [false; 12];
for &val in ascending.iter().take(12) {
seen[val as usize] = true;
}
assert!(seen.iter().all(|&x| x), "Should contain all 12 pitch classes");
}
#[test]
fn test_shepard_tone_edge_cases() {
let empty = generate(0, 12, true);
assert_eq!(empty, Vec::<u32>::new());
let zero_steps = generate(10, 0, true);
assert_eq!(zero_steps, Vec::<u32>::new());
let single = generate(1, 12, true);
assert_eq!(single, vec![0]);
let quarter = generate(24, 24, true);
assert_eq!(quarter.len(), 24);
assert_eq!(quarter[23], 23);
}
#[test]
fn test_shepard_tone_continuous_ascending() {
let tone = generate(12, 12, true);
for i in 0..11 {
assert_eq!(tone[i] + 1, tone[i + 1], "Ascending should increment by 1");
}
}
#[test]
fn test_shepard_tone_continuous_descending() {
let tone = generate(13, 12, false);
for i in 1..12 {
assert_eq!(
tone[i],
12 - i as u32,
"Descending should decrement: tone[{}] = {}",
i,
tone[i]
);
}
}
}
pub fn ascending() -> Vec<u32> {
generate(24, 12, true)
}
pub fn descending() -> Vec<u32> {
generate(24, 12, false)
}
pub fn long_ascending() -> Vec<u32> {
generate(48, 12, true)
}
pub fn microtonal() -> Vec<u32> {
generate(48, 24, true)
}