//! Sound representation.

pub mod wav;

/// Any PCM stream which may be represented as a 16-bit PCM stream.
pub trait Sound
{
	/// Returns the sample rate.
	fn rate(&self) -> u16;

	/// Returns the number of samples.
	fn len(&self) -> usize;

	/// Returns the `n`th sample.
	///
	/// # Panics
	///
	/// Panics if `n` exceeds the length of this sound.
	fn index(&self, n: usize) -> i16;

	/// Returns the number of the first sample of the loop, or `0`.
	fn lp_beg(&self) -> usize;

	/// Returns the number of the last sample of the loop, or `0`.
	fn lp_end(&self) -> usize;

	/// Returns `true` if there are no samples in this sound.
	fn is_empty(&self) -> bool {self.len() == 0}

	/// The same as `index`, but will not panic if out of bounds.
	fn get(&self, n: usize) -> Option<i16>
	{
		if n < self.len() {
			Some(self.index(n))
		} else {
			None
		}
	}
}

impl Sound16
{
	/// Creates a new `Sound16`.
	pub fn new(rate: u16, lp_beg: usize, lp_end: usize, len: usize) -> Self
	{
		Self{rate, lp_beg, lp_end, data: Vec::with_capacity(len)}
	}

	/// Creates a new `Sound16` from an unsigned 8-bit stream.
	pub fn new_from_8(rate: u16, lp_beg: usize, lp_end: usize, b: &[u8]) -> Self
	{
		let mut snd = Self::new(rate, lp_beg, lp_end, b.len());

		for &sample in b {
			snd.data.push(Self::sample_from_8(sample));
		}

		snd
	}

	/// Creates a new `Sound16` from a signed 16-bit stream.
	pub fn new_from_16(rate: u16, lp_beg: usize, lp_end: usize, b: &[u8]) -> Self
	{
		let mut snd = Self::new(rate, lp_beg, lp_end, b.len() / 2);

		for i in (0..b.len()).step_by(2) {
			snd.data.push(i16::from_le_bytes([b[i], b[i + 1]]));
		}

		snd
	}

	/// Creates a signed 16-bit sample from an unsigned 8-bit sample.
	pub fn sample_from_8(sample: u8) -> i16 {(i16::from(sample) - 0x80) << 8}
}

impl Sound for Sound16
{
	fn rate(&self) -> u16 {self.rate}
	fn len(&self) -> usize {self.data.len()}
	fn index(&self, p: usize) -> i16 {self.data[p]}
	fn lp_beg(&self) -> usize {self.lp_beg}
	fn lp_end(&self) -> usize {self.lp_end}
}

/// A 16-bit PCM stream.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
pub struct Sound16 {
	rate:   u16,
	lp_beg: usize,
	lp_end: usize,

	/// The raw signed PCM data of this sound.
	pub data: Vec<i16>,
}

// EOF
