#![cfg_attr(not(feature = "std"), no_std)]
#![forbid(unsafe_code)]
#[cfg(feature = "alloc")]
extern crate alloc;
pub use rusty_esp_core as esp_core;
pub mod chip;
pub mod codec;
pub mod elements;
pub mod pipeline;
pub mod ring;
pub mod source;
pub use pipeline::{Element, Pipeline};
pub use ring::RingBuffer;
pub use source::{AudioSink, AudioSource};
pub mod prelude {
pub use rusty_esp_core::prelude::*;
pub use crate::codec::pcm::convert as convert_pcm;
pub use crate::elements::{
Agc, AgcConfig, Biquad, BiquadKind, Convert, DcBlock, EnergyVad, Gain, LinearResampler,
MonoToStereo, StereoToMono, VadConfig,
};
pub use crate::pipeline::{Element, Pipeline};
pub use crate::ring::RingBuffer;
pub use crate::source::{AudioSink, AudioSource, CountingSink, SineSource};
}
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
#[cfg(not(feature = "pie-s3"))]
pub use rusty_esp_dsp::sample::{peak_abs_i16, rms_dbfs_i16};
#[cfg(feature = "pie-s3")]
pub use pie::{peak_abs_i16, rms_dbfs_i16};
#[cfg(feature = "pie-s3")]
pub(crate) mod pie {
#[must_use]
pub fn rms_dbfs_i16(samples: &[u8]) -> f32 {
#[cfg(target_arch = "xtensa")]
{
rusty_esp_dsp_esp::pie_s3::rms_dbfs_i16(samples)
}
#[cfg(not(target_arch = "xtensa"))]
{
rusty_esp_dsp::sample::rms_dbfs_i16(samples)
}
}
#[must_use]
pub fn peak_abs_i16(a: &[i16]) -> u16 {
#[cfg(target_arch = "xtensa")]
{
rusty_esp_dsp_esp::pie_s3::peak_abs_i16(a)
}
#[cfg(not(target_arch = "xtensa"))]
{
rusty_esp_dsp::sample::peak_abs_i16(a)
}
}
pub fn mono_to_stereo(src: &[i16], dst: &mut [i16]) -> bool {
#[cfg(target_arch = "xtensa")]
{
rusty_esp_dsp_esp::pie_s3::mono_to_stereo_i16(src, dst);
true
}
#[cfg(not(target_arch = "xtensa"))]
{
let _ = (src, dst);
false
}
}
pub fn stereo_to_mono(src: &[i16], dst: &mut [i16]) -> bool {
#[cfg(target_arch = "xtensa")]
{
rusty_esp_dsp_esp::pie_s3::stereo_to_mono_i16(src, dst);
true
}
#[cfg(not(target_arch = "xtensa"))]
{
let _ = (src, dst);
false
}
}
pub fn mix(a: &[i16], b: &[i16], out: &mut [i16]) -> bool {
#[cfg(target_arch = "xtensa")]
{
rusty_esp_dsp_esp::pie_s3::mix_i16(a, b, out);
true
}
#[cfg(not(target_arch = "xtensa"))]
{
let _ = (a, b, out);
false
}
}
pub fn convert(
input: &rusty_esp_core::pcm::PcmBlock<'_>,
to: rusty_esp_core::pcm::SampleFormat,
out: &mut [u8],
) -> Option<usize> {
#[cfg(target_arch = "xtensa")]
{
use rusty_esp_core::pcm::SampleFormat::{I16, I24In32, I32};
use rusty_esp_core::pcm::{as_i16, as_i16_mut, as_i32, as_i32_mut};
let from = input.format.sample;
let n = rusty_esp_dsp::sample::pcm::output_bytes(from, to, input.data.len());
if out.len() < n {
return None;
}
match (from, to) {
(I16, I32) | (I16, I24In32) => {
let si = as_i16(input.data)?;
let so = as_i32_mut(&mut out[..n])?;
rusty_esp_dsp_esp::pie_s3::convert_i16_to_i32(si, so);
Some(n)
}
(I32, I16) | (I24In32, I16) => {
let si = as_i32(input.data)?;
let so = as_i16_mut(&mut out[..n])?;
rusty_esp_dsp_esp::pie_s3::convert_i32_to_i16(si, so);
Some(n)
}
(I32, I24In32) => {
let si = as_i32(input.data)?;
let so = as_i32_mut(&mut out[..n])?;
rusty_esp_dsp_esp::pie_s3::convert_i32_to_i24in32(si, so);
Some(n)
}
_ => None,
}
}
#[cfg(not(target_arch = "xtensa"))]
{
let _ = (input, to, out);
None
}
}
pub fn gain(src: &[i16], q15: i32, dst: &mut [i16]) -> bool {
#[cfg(target_arch = "xtensa")]
{
if q15.unsigned_abs() <= 32767 {
rusty_esp_dsp_esp::pie_s3::gain_i16(src, q15, dst);
return true;
}
false
}
#[cfg(not(target_arch = "xtensa"))]
{
let _ = (src, q15, dst);
false
}
}
}
#[cfg(not(feature = "pie-s3"))]
pub(crate) mod pie {
pub fn mono_to_stereo(_: &[i16], _: &mut [i16]) -> bool {
false
}
pub fn stereo_to_mono(_: &[i16], _: &mut [i16]) -> bool {
false
}
pub fn mix(_: &[i16], _: &[i16], _: &mut [i16]) -> bool {
false
}
pub fn gain(_: &[i16], _: i32, _: &mut [i16]) -> bool {
false
}
pub fn convert(
_: &rusty_esp_core::pcm::PcmBlock<'_>,
_: rusty_esp_core::pcm::SampleFormat,
_: &mut [u8],
) -> Option<usize> {
None
}
}
#[inline]
pub(crate) fn put_i16(out: &mut [u8], v: i16) {
let b = v.to_le_bytes();
out[0] = b[0];
out[1] = b[1];
}
#[inline]
pub(crate) fn get_i16(b: &[u8]) -> i16 {
i16::from_le_bytes([b[0], b[1]])
}
#[inline]
pub(crate) fn sat16(v: i32) -> i16 {
v.clamp(i32::from(i16::MIN), i32::from(i16::MAX)) as i16
}
#[inline]
pub(crate) fn round_sat16(v: f32) -> i16 {
rusty_esp_core::pcm::round_sat_i16(v)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rounding_and_saturation() {
assert_eq!(round_sat16(0.4), 0);
assert_eq!(round_sat16(0.5), 1);
assert_eq!(round_sat16(-0.5), -1);
assert_eq!(round_sat16(40000.0), i16::MAX);
assert_eq!(round_sat16(-40000.0), i16::MIN);
assert_eq!(sat16(70000), i16::MAX);
assert_eq!(sat16(-70000), i16::MIN);
}
}