From 16fc14a4da78a039368122867c1a7eacc37eb717 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Sat, 8 Feb 2025 15:27:17 -0700 Subject: [PATCH] musikr: add format-specific file api --- musikr/src/main/jni/shim/iostream_shim.cpp | 21 +++++ musikr/src/main/jni/shim/iostream_shim.hpp | 65 +++++++++---- musikr/src/main/jni/src/taglib/ffi.rs | 30 ++++++ musikr/src/main/jni/src/taglib/mod.rs | 104 ++++++++++++++++++--- 4 files changed, 188 insertions(+), 32 deletions(-) diff --git a/musikr/src/main/jni/shim/iostream_shim.cpp b/musikr/src/main/jni/shim/iostream_shim.cpp index e48b4cbf7..d14813eb6 100644 --- a/musikr/src/main/jni/shim/iostream_shim.cpp +++ b/musikr/src/main/jni/shim/iostream_shim.cpp @@ -54,6 +54,27 @@ const TagLib::String& File_tag_title(const TagLib::File& file) { return empty_string; } +// Audio Properties methods +const TagLib::AudioProperties* File_audioProperties(const TagLib::File& file) { + return file.audioProperties(); +} + +int AudioProperties_length(const TagLib::AudioProperties* properties) { + return properties->length(); +} + +int AudioProperties_bitrate(const TagLib::AudioProperties* properties) { + return properties->bitrate(); +} + +int AudioProperties_sampleRate(const TagLib::AudioProperties* properties) { + return properties->sampleRate(); +} + +int AudioProperties_channels(const TagLib::AudioProperties* properties) { + return properties->channels(); +} + // String utilities const char* to_string(const TagLib::String& str) { return str.toCString(true); diff --git a/musikr/src/main/jni/shim/iostream_shim.hpp b/musikr/src/main/jni/shim/iostream_shim.hpp index dc931f5da..781bf6d63 100644 --- a/musikr/src/main/jni/shim/iostream_shim.hpp +++ b/musikr/src/main/jni/shim/iostream_shim.hpp @@ -8,6 +8,14 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include namespace taglib_shim { @@ -50,26 +58,45 @@ const TagLib::File& FileRef_file(const TagLib::FileRef& ref); bool File_tag(const TagLib::File& file); const TagLib::String& File_tag_title(const TagLib::File& file); +// File type checking functions +bool File_isMPEG(const TagLib::File& file) { + return dynamic_cast(&file) != nullptr; +} + +bool File_isFLAC(const TagLib::File& file) { + return dynamic_cast(&file) != nullptr; +} + +bool File_isMP4(const TagLib::File& file) { + return dynamic_cast(&file) != nullptr; +} + +bool File_isOgg(const TagLib::File& file) { + return dynamic_cast(&file) != nullptr; +} + +bool File_isOpus(const TagLib::File& file) { + return dynamic_cast(&file) != nullptr; +} + +bool File_isWAV(const TagLib::File& file) { + return dynamic_cast(&file) != nullptr; +} + +bool File_isWavPack(const TagLib::File& file) { + return dynamic_cast(&file) != nullptr; +} + +bool File_isAPE(const TagLib::File& file) { + return dynamic_cast(&file) != nullptr; +} + // Audio Properties methods -const TagLib::AudioProperties* File_audioProperties(const TagLib::File& file) { - return file.audioProperties(); -} - -int AudioProperties_length(const TagLib::AudioProperties* properties) { - return properties->length(); -} - -int AudioProperties_bitrate(const TagLib::AudioProperties* properties) { - return properties->bitrate(); -} - -int AudioProperties_sampleRate(const TagLib::AudioProperties* properties) { - return properties->sampleRate(); -} - -int AudioProperties_channels(const TagLib::AudioProperties* properties) { - return properties->channels(); -} +const TagLib::AudioProperties* File_audioProperties(const TagLib::File& file); +int AudioProperties_length(const TagLib::AudioProperties* properties); +int AudioProperties_bitrate(const TagLib::AudioProperties* properties); +int AudioProperties_sampleRate(const TagLib::AudioProperties* properties); +int AudioProperties_channels(const TagLib::AudioProperties* properties); // String utilities const char* to_string(const TagLib::String& str); diff --git a/musikr/src/main/jni/src/taglib/ffi.rs b/musikr/src/main/jni/src/taglib/ffi.rs index e435ba1f2..b7d479742 100644 --- a/musikr/src/main/jni/src/taglib/ffi.rs +++ b/musikr/src/main/jni/src/taglib/ffi.rs @@ -36,6 +36,24 @@ pub(crate) mod bindings { #[namespace = "taglib_shim"] fn File_tag_title(file: &File) -> &TagString; + // File type checking functions + #[namespace = "taglib_shim"] + fn File_isMPEG(file: &File) -> bool; + #[namespace = "taglib_shim"] + fn File_isFLAC(file: &File) -> bool; + #[namespace = "taglib_shim"] + fn File_isMP4(file: &File) -> bool; + #[namespace = "taglib_shim"] + fn File_isOgg(file: &File) -> bool; + #[namespace = "taglib_shim"] + fn File_isOpus(file: &File) -> bool; + #[namespace = "taglib_shim"] + fn File_isWAV(file: &File) -> bool; + #[namespace = "taglib_shim"] + fn File_isWavPack(file: &File) -> bool; + #[namespace = "taglib_shim"] + fn File_isAPE(file: &File) -> bool; + // Audio Properties methods #[namespace = "taglib_shim"] unsafe fn File_audioProperties(file: &File) -> *const AudioProperties; @@ -55,3 +73,15 @@ pub(crate) mod bindings { fn isEmpty(s: &TagString) -> bool; } } + +extern "C" { + // File type checking functions + pub fn File_isMPEG(file: *const bindings::File) -> bool; + pub fn File_isFLAC(file: *const bindings::File) -> bool; + pub fn File_isMP4(file: *const bindings::File) -> bool; + pub fn File_isOgg(file: *const bindings::File) -> bool; + pub fn File_isOpus(file: *const bindings::File) -> bool; + pub fn File_isWAV(file: *const bindings::File) -> bool; + pub fn File_isWavPack(file: *const bindings::File) -> bool; + pub fn File_isAPE(file: *const bindings::File) -> bool; +} diff --git a/musikr/src/main/jni/src/taglib/mod.rs b/musikr/src/main/jni/src/taglib/mod.rs index 28aa1cd0c..828f7ea19 100644 --- a/musikr/src/main/jni/src/taglib/mod.rs +++ b/musikr/src/main/jni/src/taglib/mod.rs @@ -13,22 +13,83 @@ pub struct AudioProperties { pub channels: i32, } -// Store extracted tag data instead of C++ reference -#[derive(Default)] -pub struct File { - title: Option, - audio_properties: Option, +pub enum File { + Unknown { + title: Option, + audio_properties: Option, + }, + MP3 { + title: Option, + audio_properties: Option, + }, + FLAC { + title: Option, + audio_properties: Option, + }, + MP4 { + title: Option, + audio_properties: Option, + }, + OGG { + title: Option, + audio_properties: Option, + }, + Opus { + title: Option, + audio_properties: Option, + }, + WAV { + title: Option, + audio_properties: Option, + }, + WavPack { + title: Option, + audio_properties: Option, + }, + APE { + title: Option, + audio_properties: Option, + }, +} + +impl Default for File { + fn default() -> Self { + File::Unknown { + title: None, + audio_properties: None, + } + } } impl File { /// Get the title of the file, if available pub fn title(&self) -> Option<&str> { - self.title.as_deref() + match self { + File::Unknown { title, .. } | + File::MP3 { title, .. } | + File::FLAC { title, .. } | + File::MP4 { title, .. } | + File::OGG { title, .. } | + File::Opus { title, .. } | + File::WAV { title, .. } | + File::WavPack { title, .. } | + File::APE { title, .. } => title.as_deref() + } } /// Get the audio properties of the file, if available pub fn audio_properties(&self) -> Option<&AudioProperties> { - self.audio_properties.as_ref() + match self { + File::Unknown { audio_properties, .. } | + File::MP3 { audio_properties, .. } | + File::FLAC { audio_properties, .. } | + File::MP4 { audio_properties, .. } | + File::OGG { audio_properties, .. } | + File::Opus { audio_properties, .. } | + File::WAV { audio_properties, .. } | + File::WavPack { audio_properties, .. } | + File::APE { audio_properties, .. } => audio_properties.as_ref() + } } } @@ -88,15 +149,32 @@ impl FileRef { } }; + // Determine file type and create appropriate variant + let file = { + if ffi::bindings::File_isMPEG(file_ptr) { + File::MP3 { title, audio_properties } + } else if ffi::bindings::File_isFLAC(file_ptr) { + File::FLAC { title, audio_properties } + } else if ffi::bindings::File_isMP4(file_ptr) { + File::MP4 { title, audio_properties } + } else if ffi::bindings::File_isOpus(file_ptr) { + File::Opus { title, audio_properties } + } else if ffi::bindings::File_isOgg(file_ptr) { + File::OGG { title, audio_properties } + } else if ffi::bindings::File_isWAV(file_ptr) { + File::WAV { title, audio_properties } + } else if ffi::bindings::File_isWavPack(file_ptr) { + File::WavPack { title, audio_properties } + } else if ffi::bindings::File_isAPE(file_ptr) { + File::APE { title, audio_properties } + } else { + File::Unknown { title, audio_properties } + } + }; + // Clean up C++ objects - they will be dropped when inner is dropped drop(inner); - // Create File with extracted data - let file = File { - title, - audio_properties, - }; - Some(FileRef { file }) }