use std::collections::HashMap;
use std::os::raw::{c_int, c_void};
#[derive(Debug)]
pub struct MajorInfo {
pub name: String,
pub extension: String,
}
#[derive(Debug)]
pub struct SubtypeInfo {
pub name: String,
}
lazy_static! {
static ref MAJOR_FORMAT_LIST: HashMap<MajorFormat, MajorInfo> = {
let mut n: c_int = 0;
unsafe {
sndfile_sys::sf_command(
std::ptr::null_mut(),
sndfile_sys::SFC_GET_FORMAT_MAJOR_COUNT,
&mut n as *mut c_int as *mut c_void,
std::mem::size_of::<c_int>() as c_int,
)
};
assert!(n >= 0);
let mut fmt_info = sndfile_sys::SF_FORMAT_INFO {
format: 0,
name: std::ptr::null(),
extension: std::ptr::null(),
};
let mut out = HashMap::new();
for i in 0..n {
fmt_info.format = i;
unsafe {
sndfile_sys::sf_command(
std::ptr::null_mut(),
sndfile_sys::SFC_GET_FORMAT_MAJOR,
&mut fmt_info as *mut sndfile_sys::SF_FORMAT_INFO as *mut c_void,
std::mem::size_of::<sndfile_sys::SF_FORMAT_INFO>() as c_int,
)
};
match flags_to_major_format(fmt_info.format) {
Some(major_format) => {
let name = unsafe { std::ffi::CStr::from_ptr(fmt_info.name) }
.to_str()
.unwrap();
let extension = unsafe { std::ffi::CStr::from_ptr(fmt_info.extension) }
.to_str()
.unwrap();
out.insert(
major_format,
MajorInfo {
name: name.to_string(),
extension: extension.to_string(),
},
);
}
_ => {}
}
}
out
};
static ref SUBTYPE_FORMAT_LIST: HashMap<SubtypeFormat, SubtypeInfo> = {
let mut n: c_int = 0;
unsafe {
sndfile_sys::sf_command(
std::ptr::null_mut(),
sndfile_sys::SFC_GET_FORMAT_SUBTYPE_COUNT,
&mut n as *mut c_int as *mut c_void,
std::mem::size_of::<c_int>() as c_int,
)
};
assert!(n >= 0);
let mut fmt_info = sndfile_sys::SF_FORMAT_INFO {
format: 0,
name: std::ptr::null(),
extension: std::ptr::null(),
};
let mut out = HashMap::new();
for i in 0..n {
fmt_info.format = i;
unsafe {
sndfile_sys::sf_command(
std::ptr::null_mut(),
sndfile_sys::SFC_GET_FORMAT_SUBTYPE,
&mut fmt_info as *mut sndfile_sys::SF_FORMAT_INFO as *mut c_void,
std::mem::size_of::<sndfile_sys::SF_FORMAT_INFO>() as c_int,
)
};
match flags_to_subtype_format(fmt_info.format) {
Some(subtype_format) => {
let name = unsafe { std::ffi::CStr::from_ptr(fmt_info.name) }
.to_str()
.unwrap();
out.insert(
subtype_format,
SubtypeInfo {
name: name.to_string(),
},
);
}
_ => {}
}
}
out
};
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum MajorFormat {
WAV,
AIFF,
AU,
RAW,
PAF,
SVX,
NIST,
VOC,
IRCAM,
W64,
MAT4,
MAT5,
PVF,
XI,
HTK,
SDS,
AVR,
WAVEX,
SD2,
FLAC,
CAF,
WVE,
OGG,
MPC2K,
RF64,
}
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum SubtypeFormat {
PCM_S8,
PCM_16,
PCM_24,
PCM_32,
PCM_U8,
FLOAT,
DOUBLE,
ULAW,
ALAW,
IMA_ADPCM,
MS_ADPCM,
GSM610,
VOX_ADPCM,
G721_32,
G723_24,
G723_40,
DWVW_12,
DWVW_16,
DWVW_24,
DWVW_N,
DPCM_8,
DPCM_16,
VORBIS,
ALAC_16,
ALAC_20,
ALAC_24,
ALAC_32,
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Endian {
File,
Little,
Big,
CPU,
}
pub fn flags_to_major_format(flags: c_int) -> Option<MajorFormat> {
match flags & sndfile_sys::SF_FORMAT_TYPEMASK {
sndfile_sys::SF_FORMAT_WAV => Some(MajorFormat::WAV),
sndfile_sys::SF_FORMAT_AIFF => Some(MajorFormat::AIFF),
sndfile_sys::SF_FORMAT_AU => Some(MajorFormat::AU),
sndfile_sys::SF_FORMAT_RAW => Some(MajorFormat::RAW),
sndfile_sys::SF_FORMAT_PAF => Some(MajorFormat::PAF),
sndfile_sys::SF_FORMAT_SVX => Some(MajorFormat::SVX),
sndfile_sys::SF_FORMAT_NIST => Some(MajorFormat::NIST),
sndfile_sys::SF_FORMAT_VOC => Some(MajorFormat::VOC),
sndfile_sys::SF_FORMAT_IRCAM => Some(MajorFormat::IRCAM),
sndfile_sys::SF_FORMAT_W64 => Some(MajorFormat::W64),
sndfile_sys::SF_FORMAT_MAT4 => Some(MajorFormat::MAT4),
sndfile_sys::SF_FORMAT_MAT5 => Some(MajorFormat::MAT5),
sndfile_sys::SF_FORMAT_PVF => Some(MajorFormat::PVF),
sndfile_sys::SF_FORMAT_XI => Some(MajorFormat::XI),
sndfile_sys::SF_FORMAT_HTK => Some(MajorFormat::HTK),
sndfile_sys::SF_FORMAT_SDS => Some(MajorFormat::SDS),
sndfile_sys::SF_FORMAT_AVR => Some(MajorFormat::AVR),
sndfile_sys::SF_FORMAT_WAVEX => Some(MajorFormat::WAVEX),
sndfile_sys::SF_FORMAT_SD2 => Some(MajorFormat::SD2),
sndfile_sys::SF_FORMAT_FLAC => Some(MajorFormat::FLAC),
sndfile_sys::SF_FORMAT_CAF => Some(MajorFormat::CAF),
sndfile_sys::SF_FORMAT_WVE => Some(MajorFormat::WVE),
sndfile_sys::SF_FORMAT_OGG => Some(MajorFormat::OGG),
sndfile_sys::SF_FORMAT_MPC2K => Some(MajorFormat::MPC2K),
sndfile_sys::SF_FORMAT_RF64 => Some(MajorFormat::RF64),
_ => None,
}
}
pub fn flags_to_subtype_format(flags: c_int) -> Option<SubtypeFormat> {
match flags & sndfile_sys::SF_FORMAT_SUBMASK {
sndfile_sys::SF_FORMAT_PCM_S8 => Some(SubtypeFormat::PCM_S8),
sndfile_sys::SF_FORMAT_PCM_16 => Some(SubtypeFormat::PCM_16),
sndfile_sys::SF_FORMAT_PCM_24 => Some(SubtypeFormat::PCM_24),
sndfile_sys::SF_FORMAT_PCM_32 => Some(SubtypeFormat::PCM_32),
sndfile_sys::SF_FORMAT_PCM_U8 => Some(SubtypeFormat::PCM_U8),
sndfile_sys::SF_FORMAT_FLOAT => Some(SubtypeFormat::FLOAT),
sndfile_sys::SF_FORMAT_DOUBLE => Some(SubtypeFormat::DOUBLE),
sndfile_sys::SF_FORMAT_ULAW => Some(SubtypeFormat::ULAW),
sndfile_sys::SF_FORMAT_ALAW => Some(SubtypeFormat::ALAW),
sndfile_sys::SF_FORMAT_IMA_ADPCM => Some(SubtypeFormat::IMA_ADPCM),
sndfile_sys::SF_FORMAT_MS_ADPCM => Some(SubtypeFormat::MS_ADPCM),
sndfile_sys::SF_FORMAT_GSM610 => Some(SubtypeFormat::GSM610),
sndfile_sys::SF_FORMAT_VOX_ADPCM => Some(SubtypeFormat::VOX_ADPCM),
sndfile_sys::SF_FORMAT_G721_32 => Some(SubtypeFormat::G721_32),
sndfile_sys::SF_FORMAT_G723_24 => Some(SubtypeFormat::G723_24),
sndfile_sys::SF_FORMAT_G723_40 => Some(SubtypeFormat::G723_40),
sndfile_sys::SF_FORMAT_DWVW_12 => Some(SubtypeFormat::DWVW_12),
sndfile_sys::SF_FORMAT_DWVW_16 => Some(SubtypeFormat::DWVW_16),
sndfile_sys::SF_FORMAT_DWVW_24 => Some(SubtypeFormat::DWVW_24),
sndfile_sys::SF_FORMAT_DWVW_N => Some(SubtypeFormat::DWVW_N),
sndfile_sys::SF_FORMAT_DPCM_8 => Some(SubtypeFormat::DPCM_8),
sndfile_sys::SF_FORMAT_DPCM_16 => Some(SubtypeFormat::DPCM_16),
sndfile_sys::SF_FORMAT_VORBIS => Some(SubtypeFormat::VORBIS),
sndfile_sys::SF_FORMAT_ALAC_16 => Some(SubtypeFormat::ALAC_16),
sndfile_sys::SF_FORMAT_ALAC_20 => Some(SubtypeFormat::ALAC_20),
sndfile_sys::SF_FORMAT_ALAC_24 => Some(SubtypeFormat::ALAC_24),
sndfile_sys::SF_FORMAT_ALAC_32 => Some(SubtypeFormat::ALAC_32),
_ => None,
}
}
pub fn flags_to_endian(flags: c_int) -> Option<Endian> {
match flags & sndfile_sys::SF_FORMAT_ENDMASK {
sndfile_sys::SF_ENDIAN_FILE => Some(Endian::File),
sndfile_sys::SF_ENDIAN_LITTLE => Some(Endian::Little),
sndfile_sys::SF_ENDIAN_BIG => Some(Endian::Big),
sndfile_sys::SF_ENDIAN_CPU => Some(Endian::CPU),
_ => None,
}
}
pub fn major_format_to_flags(major_format: MajorFormat) -> c_int {
match major_format {
MajorFormat::WAV => sndfile_sys::SF_FORMAT_WAV,
MajorFormat::AIFF => sndfile_sys::SF_FORMAT_AIFF,
MajorFormat::AU => sndfile_sys::SF_FORMAT_AU,
MajorFormat::RAW => sndfile_sys::SF_FORMAT_RAW,
MajorFormat::PAF => sndfile_sys::SF_FORMAT_PAF,
MajorFormat::SVX => sndfile_sys::SF_FORMAT_SVX,
MajorFormat::NIST => sndfile_sys::SF_FORMAT_NIST,
MajorFormat::VOC => sndfile_sys::SF_FORMAT_VOC,
MajorFormat::IRCAM => sndfile_sys::SF_FORMAT_IRCAM,
MajorFormat::W64 => sndfile_sys::SF_FORMAT_W64,
MajorFormat::MAT4 => sndfile_sys::SF_FORMAT_MAT4,
MajorFormat::MAT5 => sndfile_sys::SF_FORMAT_MAT5,
MajorFormat::PVF => sndfile_sys::SF_FORMAT_PVF,
MajorFormat::XI => sndfile_sys::SF_FORMAT_XI,
MajorFormat::HTK => sndfile_sys::SF_FORMAT_HTK,
MajorFormat::SDS => sndfile_sys::SF_FORMAT_SDS,
MajorFormat::AVR => sndfile_sys::SF_FORMAT_AVR,
MajorFormat::WAVEX => sndfile_sys::SF_FORMAT_WAVEX,
MajorFormat::SD2 => sndfile_sys::SF_FORMAT_SD2,
MajorFormat::FLAC => sndfile_sys::SF_FORMAT_FLAC,
MajorFormat::CAF => sndfile_sys::SF_FORMAT_CAF,
MajorFormat::WVE => sndfile_sys::SF_FORMAT_WVE,
MajorFormat::OGG => sndfile_sys::SF_FORMAT_OGG,
MajorFormat::MPC2K => sndfile_sys::SF_FORMAT_MPC2K,
MajorFormat::RF64 => sndfile_sys::SF_FORMAT_RF64,
}
}
pub fn subtype_format_to_flags(subtype_format: SubtypeFormat) -> c_int {
match subtype_format {
SubtypeFormat::PCM_S8 => sndfile_sys::SF_FORMAT_PCM_S8,
SubtypeFormat::PCM_16 => sndfile_sys::SF_FORMAT_PCM_16,
SubtypeFormat::PCM_24 => sndfile_sys::SF_FORMAT_PCM_24,
SubtypeFormat::PCM_32 => sndfile_sys::SF_FORMAT_PCM_32,
SubtypeFormat::PCM_U8 => sndfile_sys::SF_FORMAT_PCM_U8,
SubtypeFormat::FLOAT => sndfile_sys::SF_FORMAT_FLOAT,
SubtypeFormat::DOUBLE => sndfile_sys::SF_FORMAT_DOUBLE,
SubtypeFormat::ULAW => sndfile_sys::SF_FORMAT_ULAW,
SubtypeFormat::ALAW => sndfile_sys::SF_FORMAT_ALAW,
SubtypeFormat::IMA_ADPCM => sndfile_sys::SF_FORMAT_IMA_ADPCM,
SubtypeFormat::MS_ADPCM => sndfile_sys::SF_FORMAT_MS_ADPCM,
SubtypeFormat::GSM610 => sndfile_sys::SF_FORMAT_GSM610,
SubtypeFormat::VOX_ADPCM => sndfile_sys::SF_FORMAT_VOX_ADPCM,
SubtypeFormat::G721_32 => sndfile_sys::SF_FORMAT_G721_32,
SubtypeFormat::G723_24 => sndfile_sys::SF_FORMAT_G723_24,
SubtypeFormat::G723_40 => sndfile_sys::SF_FORMAT_G723_40,
SubtypeFormat::DWVW_12 => sndfile_sys::SF_FORMAT_DWVW_12,
SubtypeFormat::DWVW_16 => sndfile_sys::SF_FORMAT_DWVW_16,
SubtypeFormat::DWVW_24 => sndfile_sys::SF_FORMAT_DWVW_24,
SubtypeFormat::DWVW_N => sndfile_sys::SF_FORMAT_DWVW_N,
SubtypeFormat::DPCM_8 => sndfile_sys::SF_FORMAT_DPCM_8,
SubtypeFormat::DPCM_16 => sndfile_sys::SF_FORMAT_DPCM_16,
SubtypeFormat::VORBIS => sndfile_sys::SF_FORMAT_VORBIS,
SubtypeFormat::ALAC_16 => sndfile_sys::SF_FORMAT_ALAC_16,
SubtypeFormat::ALAC_20 => sndfile_sys::SF_FORMAT_ALAC_20,
SubtypeFormat::ALAC_24 => sndfile_sys::SF_FORMAT_ALAC_24,
SubtypeFormat::ALAC_32 => sndfile_sys::SF_FORMAT_ALAC_32,
}
}
pub fn endian_to_flags(endian: Endian) -> c_int {
match endian {
Endian::File => sndfile_sys::SF_ENDIAN_FILE,
Endian::Little => sndfile_sys::SF_ENDIAN_LITTLE,
Endian::Big => sndfile_sys::SF_ENDIAN_BIG,
Endian::CPU => sndfile_sys::SF_ENDIAN_CPU,
}
}
pub fn assembly_format_flags(
major_format: MajorFormat,
subtype_format: SubtypeFormat,
endian: Endian,
) -> c_int {
let major_format_flag = major_format_to_flags(major_format);
let subtype_format_flag = subtype_format_to_flags(subtype_format);
let endian_flag = endian_to_flags(endian);
major_format_flag | subtype_format_flag | endian_flag
}
pub fn get_supported_major_format_dict() -> &'static HashMap<MajorFormat, MajorInfo> {
&*MAJOR_FORMAT_LIST
}
pub fn get_supported_subtype_format_dict() -> &'static HashMap<SubtypeFormat, SubtypeInfo> {
&*SUBTYPE_FORMAT_LIST
}
pub fn check_format(
channels: usize,
samplerate: usize,
major_format: MajorFormat,
subtype_format: SubtypeFormat,
endian: Endian,
) -> bool {
let info = sndfile_sys::SF_INFO {
frames: 0,
samplerate: samplerate as c_int,
channels: channels as c_int,
format: assembly_format_flags(major_format, subtype_format, endian),
sections: 0,
seekable: 0,
};
match unsafe { sndfile_sys::sf_format_check(&info as *const sndfile_sys::SF_INFO) } {
sndfile_sys::SF_TRUE => true,
_ => false,
}
}
pub fn default_subtype(major_format: MajorFormat) -> Option<SubtypeFormat> {
match major_format {
MajorFormat::WAV => Some(SubtypeFormat::PCM_16),
MajorFormat::AIFF => Some(SubtypeFormat::PCM_16),
MajorFormat::AU => Some(SubtypeFormat::PCM_16),
MajorFormat::RAW => None,
MajorFormat::PAF => Some(SubtypeFormat::PCM_16),
MajorFormat::SVX => Some(SubtypeFormat::PCM_16),
MajorFormat::NIST => Some(SubtypeFormat::PCM_16),
MajorFormat::VOC => Some(SubtypeFormat::PCM_16),
MajorFormat::IRCAM => Some(SubtypeFormat::PCM_16),
MajorFormat::W64 => Some(SubtypeFormat::PCM_16),
MajorFormat::MAT4 => Some(SubtypeFormat::DOUBLE),
MajorFormat::MAT5 => Some(SubtypeFormat::DOUBLE),
MajorFormat::PVF => Some(SubtypeFormat::PCM_16),
MajorFormat::XI => Some(SubtypeFormat::DPCM_16),
MajorFormat::HTK => Some(SubtypeFormat::PCM_16),
MajorFormat::SDS => Some(SubtypeFormat::PCM_16),
MajorFormat::AVR => Some(SubtypeFormat::PCM_16),
MajorFormat::WAVEX => Some(SubtypeFormat::PCM_16),
MajorFormat::SD2 => Some(SubtypeFormat::PCM_16),
MajorFormat::FLAC => Some(SubtypeFormat::PCM_16),
MajorFormat::CAF => Some(SubtypeFormat::PCM_16),
MajorFormat::WVE => Some(SubtypeFormat::ALAW),
MajorFormat::OGG => Some(SubtypeFormat::VORBIS),
MajorFormat::MPC2K => Some(SubtypeFormat::PCM_16),
MajorFormat::RF64 => Some(SubtypeFormat::PCM_16),
}
}