Phase continuity

This commit is contained in:
Thomas Forgione 2026-02-17 17:40:07 +01:00
parent bf8f7f397e
commit bda18d8b46
2 changed files with 27 additions and 4 deletions

View File

@ -27,6 +27,19 @@ impl Wave {
} }
} }
} }
pub fn sample_from_phase(self, phase: f64) -> f64 {
match self {
Wave::Square => {
if phase < 0.5 {
1.0
} else {
-1.0
}
}
Wave::Triangle => 4.0 * (phase - 0.5).abs() - 1.0,
}
}
} }
pub struct NoteEvent { pub struct NoteEvent {
@ -50,6 +63,7 @@ pub struct Track {
pub amplitude: f64, pub amplitude: f64,
pub notes: Vec<NoteEvent>, pub notes: Vec<NoteEvent>,
pub current_tick: Tick, pub current_tick: Tick,
pub phase: f64,
} }
impl Track { impl Track {
@ -59,6 +73,7 @@ impl Track {
amplitude, amplitude,
notes: vec![], notes: vec![],
current_tick: Tick(0), current_tick: Tick(0),
phase: 0.0,
} }
} }
@ -120,6 +135,8 @@ impl Piece {
let seconds_per_tick = 60.0 / (self.bpm as u64 * TICKS_PER_BEAT) as f64; let seconds_per_tick = 60.0 / (self.bpm as u64 * TICKS_PER_BEAT) as f64;
let params = wav::Params::new(); let params = wav::Params::new();
let mut track_phases: Vec<f64> = vec![0.0; self.tracks.len()];
let total_samples = let total_samples =
(self.max_beat() as f64 * seconds_per_beat * params.sampling_rate as f64).ceil() as u32; (self.max_beat() as f64 * seconds_per_beat * params.sampling_rate as f64).ceil() as u32;
@ -134,12 +151,18 @@ impl Piece {
for i in 0..total_samples { for i in 0..total_samples {
let t = i as f64 / params.sampling_rate as f64; let t = i as f64 / params.sampling_rate as f64;
let mut value: f64 = 0.0; let mut value: f64 = 0.0;
for track in &self.tracks { for (track, phase) in self.tracks.iter().zip(track_phases.iter_mut()) {
for event in &track.notes { for event in &track.notes {
let start_time = event.start.0 as f64 * seconds_per_tick; let start_time = event.start.0 as f64 * seconds_per_tick;
let end_time = (event.start + event.duration).0 as f64 * seconds_per_tick; let end_time = (event.start + event.duration).0 as f64 * seconds_per_tick;
if t >= start_time && t < end_time { if t >= start_time && t < end_time {
value += track.amplitude * track.wave.sample(&event.note, t); let freq = event.note.freq();
// value += track.amplitude * track.wave.sample(&event.note, t);
value += track.amplitude * track.wave.sample_from_phase(*phase);
// Update phase
*phase += freq / params.sampling_rate as f64;
*phase %= 1.0;
} }
} }
} }

View File

@ -14,7 +14,7 @@ pub fn technology() -> Piece {
} }
pub fn bass_track() -> Track { pub fn bass_track() -> Track {
let mut bass_track = Track::new(Wave::Square, 0.05); let mut bass_track = Track::new(Wave::Triangle, 0.5);
for _ in 0..4 { for _ in 0..4 {
bass_track.add(A1, Tick::bar()); bass_track.add(A1, Tick::bar());
bass_track.add(G0, Tick::beats(2)); bass_track.add(G0, Tick::beats(2));
@ -121,7 +121,7 @@ pub fn chords() -> Track {
} }
pub fn main_track() -> Track { pub fn main_track() -> Track {
let mut track = Track::new(Wave::Square, 0.1); let mut track = Track::new(Wave::Square, 0.075);
track.add_silence(Tick::bars(4)); track.add_silence(Tick::bars(4));
// Lick 1 // Lick 1