const AMPLITUDE_MIN: f32 = 0.005;
const AMPLITUDE_QUANT: f32 = 0.02;

pub struct Tone {
    // Parameters
    pub frequency: f32,
    pub amplitude_target: f32,
    pub amplitude_current: f32,
    // Timing
    pub hold_elapsed_cycles: u64,
    pub release_elapsed_cycles: u64,
    // Flags
    pub is_active: bool,
    pub is_held: bool,
}

impl Tone {
    pub fn new(frequency: f32) -> Tone {
        Tone {
            amplitude_target: 0.0,
            amplitude_current: 0.0,
            frequency,
            hold_elapsed_cycles: 0,
            release_elapsed_cycles: 0,
            is_active: false,
            is_held: false,
        }
    }

    pub fn hold(&mut self) {
        if !self.is_held {
            self.hold_elapsed_cycles = 0;
            self.release_elapsed_cycles = 0;
            self.is_active = true;
            self.is_held = true;
        }
    }

    pub fn release(&mut self) {
        self.is_held = false;
    }

    pub fn advance(&mut self) {
        self.hold_elapsed_cycles += 1;
        if !self.is_held {
            self.release_elapsed_cycles += 1;
        }

        if self.amplitude_target > self.amplitude_current + AMPLITUDE_QUANT {
            self.amplitude_current += AMPLITUDE_QUANT;
        } else if self.amplitude_target < self.amplitude_current - AMPLITUDE_QUANT {
            self.amplitude_current -= AMPLITUDE_QUANT;
        } else {
            self.amplitude_current = self.amplitude_target;
        }

        if self.amplitude_current < AMPLITUDE_MIN && self.amplitude_target < AMPLITUDE_MIN {
            self.is_active = false;
        }
    }
}
