musikr: add format-specific file api

This commit is contained in:
Alexander Capehart 2025-02-08 15:27:17 -07:00
parent 005898d776
commit 16fc14a4da
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
4 changed files with 188 additions and 32 deletions

View file

@ -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);

View file

@ -8,6 +8,14 @@
#include <taglib/tstring.h>
#include <taglib/audioproperties.h>
#include <cstdint>
#include <taglib/mpegfile.h>
#include <taglib/flacfile.h>
#include <taglib/mp4file.h>
#include <taglib/oggfile.h>
#include <taglib/opusfile.h>
#include <taglib/wavfile.h>
#include <taglib/wavpackfile.h>
#include <taglib/apefile.h>
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<const TagLib::MPEG::File*>(&file) != nullptr;
}
bool File_isFLAC(const TagLib::File& file) {
return dynamic_cast<const TagLib::FLAC::File*>(&file) != nullptr;
}
bool File_isMP4(const TagLib::File& file) {
return dynamic_cast<const TagLib::MP4::File*>(&file) != nullptr;
}
bool File_isOgg(const TagLib::File& file) {
return dynamic_cast<const TagLib::Ogg::File*>(&file) != nullptr;
}
bool File_isOpus(const TagLib::File& file) {
return dynamic_cast<const TagLib::Ogg::Opus::File*>(&file) != nullptr;
}
bool File_isWAV(const TagLib::File& file) {
return dynamic_cast<const TagLib::RIFF::WAV::File*>(&file) != nullptr;
}
bool File_isWavPack(const TagLib::File& file) {
return dynamic_cast<const TagLib::WavPack::File*>(&file) != nullptr;
}
bool File_isAPE(const TagLib::File& file) {
return dynamic_cast<const TagLib::APE::File*>(&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);

View file

@ -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;
}

View file

@ -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<String>,
audio_properties: Option<AudioProperties>,
pub enum File {
Unknown {
title: Option<String>,
audio_properties: Option<AudioProperties>,
},
MP3 {
title: Option<String>,
audio_properties: Option<AudioProperties>,
},
FLAC {
title: Option<String>,
audio_properties: Option<AudioProperties>,
},
MP4 {
title: Option<String>,
audio_properties: Option<AudioProperties>,
},
OGG {
title: Option<String>,
audio_properties: Option<AudioProperties>,
},
Opus {
title: Option<String>,
audio_properties: Option<AudioProperties>,
},
WAV {
title: Option<String>,
audio_properties: Option<AudioProperties>,
},
WavPack {
title: Option<String>,
audio_properties: Option<AudioProperties>,
},
APE {
title: Option<String>,
audio_properties: Option<AudioProperties>,
},
}
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 })
}