Skip to content

Commit

Permalink
Add av::AudioFile. Refs #24
Browse files Browse the repository at this point in the history
  • Loading branch information
yury committed Nov 5, 2024
1 parent 0f3f33d commit 02fd567
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 0 deletions.
2 changes: 2 additions & 0 deletions cidre/pomace/av/av.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ Class AV_AUDIO_PCM_BUFFER;
Class AV_AUDIO_COMPRESSED_BUFFER;
Class AV_AUDIO_FORMAT;
Class AV_AUDIO_CONVERTER;
Class AV_AUDIO_FILE;

Class AV_PLAYER;

Expand Down Expand Up @@ -172,6 +173,7 @@ static void av_initializer(void)
AV_AUDIO_PCM_BUFFER = [AVAudioPCMBuffer class];
AV_AUDIO_COMPRESSED_BUFFER = [AVAudioCompressedBuffer class];
AV_AUDIO_CONVERTER = [AVAudioConverter class];
AV_AUDIO_FILE = [AVAudioFile class];

AV_PLAYER = [AVPlayer class];

Expand Down
1 change: 1 addition & 0 deletions cidre/src/av.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ pub use audio::Converter as AudioConverter;
pub use audio::ConverterInputBlock as AudioConverterInputBlock;
pub use audio::ConverterInputStatus as AudioConverterInputStatus;
pub use audio::Engine as AudioEngine;
pub use audio::File as AudioFile;
pub use audio::Format as AudioFormat;
pub use audio::FrameCount as AudioFrameCount;
pub use audio::FramePos as AudioFramePos;
Expand Down
3 changes: 3 additions & 0 deletions cidre/src/av/audio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ mod format;
pub use format::CommonFormat;
pub use format::Format;

mod file;
pub use file::File;

mod channel_layout;
pub use channel_layout::ChannelLayout;

Expand Down
188 changes: 188 additions & 0 deletions cidre/src/av/audio/file.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
use crate::{arc, av, define_cls, define_obj_type, ns, objc};

define_obj_type!(
#[doc(alias = "AVAudioFile")]
pub File(ns::Id)
);

impl arc::A<File> {
#[objc::msg_send(initForReading:error:)]
pub unsafe fn init_for_reading_err<'ear>(
self,
file_url: &ns::Url,
err: *mut Option<&'ear ns::Error>,
) -> Option<arc::R<File>>;

#[objc::msg_send(initForReading:commonFormat:interleaved:error:)]
pub unsafe fn init_for_reading_common_format_err<'ear>(
self,
file_url: &ns::Url,
common_format: av::audio::CommonFormat,
interleaved: bool,
err: *mut Option<&'ear ns::Error>,
) -> Option<arc::R<File>>;

#[objc::msg_send(initForWriting:settings:error:)]
pub unsafe fn init_for_writing_err<'ear>(
self,
file_url: &ns::Url,
settings: &ns::Dictionary<ns::String, ns::Id>,
err: *mut Option<&'ear ns::Error>,
) -> Option<arc::R<File>>;

#[objc::msg_send(initForWriting:settings:commonFormat:interleaved:error:)]
pub unsafe fn init_for_writing_common_format_err<'ear>(
self,
file_url: &ns::Url,
settings: &ns::Dictionary<ns::String, ns::Id>,
common_format: av::audio::CommonFormat,
interleaved: bool,
err: *mut Option<&'ear ns::Error>,
) -> Option<arc::R<File>>;
}

impl File {
define_cls!(AV_AUDIO_FILE);

pub fn open_read<'ear>(file_url: &ns::Url) -> ns::Result<'ear, arc::R<Self>> {
ns::if_none(|err| unsafe { Self::alloc().init_for_reading_err(file_url, err) })
}

pub fn open_read_common_format<'ear>(
file_url: &ns::Url,
common_format: av::audio::CommonFormat,
interleaved: bool,
) -> ns::Result<'ear, arc::R<Self>> {
ns::if_none(|err| unsafe {
Self::alloc().init_for_reading_common_format_err(
file_url,
common_format,
interleaved,
err,
)
})
}

pub fn open_write<'ear>(
file_url: &ns::Url,
settings: &ns::Dictionary<ns::String, ns::Id>,
) -> ns::Result<'ear, arc::R<Self>> {
ns::if_none(|err| unsafe { Self::alloc().init_for_writing_err(file_url, settings, err) })
}

pub fn open_write_common_format<'ear>(
file_url: &ns::Url,
settings: &ns::Dictionary<ns::String, ns::Id>,
common_format: av::audio::CommonFormat,
interleaved: bool,
) -> ns::Result<'ear, arc::R<Self>> {
ns::if_none(|err| unsafe {
Self::alloc().init_for_writing_common_format_err(
file_url,
settings,
common_format,
interleaved,
err,
)
})
}

#[objc::msg_send(close)]
pub fn close(&mut self);

#[objc::msg_send(readIntoBuffer:error:)]
pub unsafe fn read_err<'ear>(
&mut self,
buffer: &mut av::audio::PcmBuf,
err: *mut Option<&'ear ns::Error>,
) -> bool;

pub fn read(&mut self, buffer: &mut av::audio::PcmBuf) -> ns::Result {
ns::if_false(|err| unsafe { self.read_err(buffer, err) })
}

#[objc::msg_send(readIntoBuffer:frameCount:error:)]
pub unsafe fn read_n_err<'ear>(
&mut self,
buffer: &mut av::audio::PcmBuf,
frame_count: av::AudioFrameCount,
err: *mut Option<&'ear ns::Error>,
) -> bool;

pub fn read_n<'ear>(
&mut self,
buffer: &mut av::audio::PcmBuf,
frame_count: av::AudioFrameCount,
) -> ns::Result {
ns::if_false(|err| unsafe { self.read_n_err(buffer, frame_count, err) })
}

#[objc::msg_send(writeFromBuffer:error:)]
pub unsafe fn write_err<'ear>(
&mut self,
buffer: &av::audio::PcmBuf,
err: *mut Option<&'ear ns::Error>,
) -> bool;

pub fn write<'ear>(&mut self, buffer: &av::audio::PcmBuf) -> ns::Result {
ns::if_false(|err| unsafe { self.write_err(buffer, err) })
}

/// Whether the file is open or not.
#[objc::msg_send(isOpen)]
pub fn is_open(&self) -> bool;

/// The URL the file is reading or writing.
#[objc::msg_send(url)]
pub fn url(&self) -> arc::R<ns::Url>;

/// The on-disk format of the file.
#[objc::msg_send(fileFormat)]
pub fn file_format(&self) -> arc::R<av::audio::Format>;

/// The processing format of the file.
#[objc::msg_send(processingFormat)]
pub fn processing_format(&self) -> arc::R<av::audio::Format>;

/// The number of sample frames in the file.
///
/// This can be expensive to compute for the first time.
#[objc::msg_send(length)]
pub fn len(&self) -> av::audio::FramePos;

/// The position in the file at which the next read or write will occur.
#[objc::msg_send(framePosition)]
pub fn frame_pos(&self) -> av::audio::FramePos;

#[objc::msg_send(setFramePosition:)]
pub fn set_frame_pos(&mut self, val: av::audio::FramePos);
}

extern "C" {
static AV_AUDIO_FILE: &'static objc::Class<File>;
}

#[cfg(test)]
mod tests {
use crate::{av, ns};

#[test]
fn basics() {
let _ = std::fs::remove_file("/tmp/foo.caf");
let url = ns::Url::with_fs_path_str("/tmp/foo.caf", false);
let _err = av::AudioFile::open_read(&url).expect_err("Should fail");

let settings = ns::Dictionary::new();
let mut file = av::AudioFile::open_write_common_format(
&url,
&settings,
av::AudioCommonFormat::PcmF32,
true,
)
.expect("Error creating file");
assert!(file.is_open());
assert_eq!(0, file.len());
file.close();
assert!(!file.is_open());
}
}
1 change: 1 addition & 0 deletions cidre/src/ns/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ define_obj_type!(
);

unsafe impl Send for Error {}
unsafe impl Sync for Error {}

impl std::error::Error for Error {}

Expand Down

0 comments on commit 02fd567

Please sign in to comment.