Move MP3 handling to Symphonia

This removes dr_mp3 (and the associated dr_libs) from vendor/.

Change-Id: Ia29d3d07f586644f6c182de6ec8fddc10c085b3c
This commit is contained in:
LennyKappa
2024-03-27 09:39:05 -04:00
committed by hikari_no_yume
parent 72ceffc6b2
commit 8bdb241ef0
12 changed files with 46 additions and 201 deletions

3
.gitmodules vendored
View File

@@ -8,9 +8,6 @@
[submodule "openal-soft"]
path = vendor/openal-soft
url = https://github.com/kcat/openal-soft
[submodule "vendor/dr_libs"]
path = vendor/dr_libs
url = https://github.com/mackron/dr_libs.git
[submodule "vendor/SDL"]
path = vendor/SDL
url = https://github.com/libsdl-org/SDL.git

22
Cargo.lock generated
View File

@@ -602,12 +602,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62e48dba70095f265fdb269b99619b95d04c89e619538138383e63310b14d941"
dependencies = [
"lazy_static",
"symphonia-bundle-mp3",
"symphonia-codec-aac",
"symphonia-core",
"symphonia-format-isomp4",
"symphonia-metadata",
]
[[package]]
name = "symphonia-bundle-mp3"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f31d7fece546f1e6973011a9eceae948133bbd18fd3d52f6073b1e38ae6368a"
dependencies = [
"bitflags",
"lazy_static",
"log",
"symphonia-core",
"symphonia-metadata",
]
[[package]]
name = "symphonia-codec-aac"
version = "0.5.3"
@@ -767,7 +781,6 @@ dependencies = [
"sdl2",
"sdl2-sys",
"symphonia",
"touchHLE_dr_mp3_wrapper",
"touchHLE_dynarmic_wrapper",
"touchHLE_gl_bindings",
"touchHLE_openal_soft_wrapper",
@@ -776,13 +789,6 @@ dependencies = [
"zip",
]
[[package]]
name = "touchHLE_dr_mp3_wrapper"
version = "0.2.2"
dependencies = [
"cc",
]
[[package]]
name = "touchHLE_dynarmic_wrapper"
version = "0.2.2"

View File

@@ -44,11 +44,12 @@ mach_object = "0.1.17"
plist = "1.3.1"
zip = { version = "0.6.4", default-features = false, features = ["deflate"] }
rusttype = "0.9.3"
# Symphonia is only used by src/audio/aac.rs right now, so that determines the
# supported features. Only the AAC-LC profile (the "aac" feature) should be
# enabled, because it's old enough that it *probably* isn't patent-encumbered,
# but IANAL. Newer AAC profiles on the other hand are nightmares.
symphonia = { version = "0.5.3", default-features = false, features = ["aac", "isomp4"] }
# While most Symphonia codecs are (likely) unpatented/have freely licenseable
# patents as of 2024, all of the AAC profiles except AAC-LC (likely) have
# active patent claims. The "aac" feature only enables AAC-LC, so it's should
# be ok.
# (The above statements should not understood as legal claims/advice.)
symphonia = { version = "0.5.3", default-features = false, features = ["aac", "isomp4", "mp3"] }
quick-xml = "0.36.2"
md5 = "0.7.0"
# We currently use a fork of rust-sdl2 because we need a fix for Android builds
@@ -59,7 +60,6 @@ md5 = "0.7.0"
# SDL2 that rust-sdl2 uses, so that the Android JNI interface matches.
sdl2 = { git = "https://github.com/hikari-no-yume/rust-sdl2.git", tag = "touchHLE-2", features = ["hidapi"] }
sdl2-sys = { git = "https://github.com/hikari-no-yume/rust-sdl2.git", tag = "touchHLE-2" }
touchHLE_dr_mp3_wrapper = { path = "src/audio/dr_mp3_wrapper" }
touchHLE_dynarmic_wrapper = { path = "src/cpu/dynarmic_wrapper" }
touchHLE_gl_bindings = { path = "src/gles/gl_bindings" }
touchHLE_openal_soft_wrapper = { path = "src/audio/openal_soft_wrapper" }

View File

@@ -114,7 +114,7 @@ Please note that different licensing terms apply to the bundled dynamic librarie
We stand on the shoulders of giants. Thank you to:
* Everyone who has contributed to the project or supported any of its contributors financially.
* The authors of and contributors to the many libraries used by this project: [dynarmic](https://github.com/merryhime/dynarmic), [rust-macho](https://github.com/flier/rust-macho), [SDL](https://libsdl.org/), [rust-sdl2](https://github.com/Rust-SDL2/rust-sdl2), [stb\_image](https://github.com/nothings/stb), Imagination Technologies' [PVRTC decompressor](https://github.com/powervr-graphics/Native_SDK/blob/master/framework/PVRCore/texture/PVRTDecompress.cpp), [openal-soft](https://github.com/kcat/openal-soft), [hound](https://github.com/ruuda/hound), [caf](https://github.com/rustaudio/caf), [dr\_mp3](https://github.com/mackron/dr_libs), [Symphonia](https://github.com/pdeljanov/Symphonia), [RustType](https://gitlab.redox-os.org/redox-os/rusttype), [the Liberation fonts](https://github.com/liberationfonts/liberation-fonts), [the Noto CJK fonts](https://github.com/googlefonts/noto-cjk), [rust-plist](https://github.com/ebarnard/rust-plist), [quick-xml](https://github.com/tafia/quick-xml), [gl-rs](https://github.com/brendanzab/gl-rs), [cargo-license](https://github.com/onur/cargo-license), [cc-rs](https://github.com/rust-lang/cc-rs), [cmake-rs](https://github.com/rust-lang/cmake-rs), [cargo-ndk](https://github.com/bbqsrc/cargo-ndk), [cargo-ndk-android-gradle](https://github.com/willir/cargo-ndk-android-gradle), [md5](https://github.com/stainless-steel/md5), and the Rust standard library.
* The authors of and contributors to the many libraries used by this project: [dynarmic](https://github.com/merryhime/dynarmic), [rust-macho](https://github.com/flier/rust-macho), [SDL](https://libsdl.org/), [rust-sdl2](https://github.com/Rust-SDL2/rust-sdl2), [stb\_image](https://github.com/nothings/stb), Imagination Technologies' [PVRTC decompressor](https://github.com/powervr-graphics/Native_SDK/blob/master/framework/PVRCore/texture/PVRTDecompress.cpp), [openal-soft](https://github.com/kcat/openal-soft), [hound](https://github.com/ruuda/hound), [caf](https://github.com/rustaudio/caf), [Symphonia](https://github.com/pdeljanov/Symphonia), [RustType](https://gitlab.redox-os.org/redox-os/rusttype), [the Liberation fonts](https://github.com/liberationfonts/liberation-fonts), [the Noto CJK fonts](https://github.com/googlefonts/noto-cjk), [rust-plist](https://github.com/ebarnard/rust-plist), [quick-xml](https://github.com/tafia/quick-xml), [gl-rs](https://github.com/brendanzab/gl-rs), [cargo-license](https://github.com/onur/cargo-license), [cc-rs](https://github.com/rust-lang/cc-rs), [cmake-rs](https://github.com/rust-lang/cmake-rs), [cargo-ndk](https://github.com/bbqsrc/cargo-ndk), [cargo-ndk-android-gradle](https://github.com/willir/cargo-ndk-android-gradle), [md5](https://github.com/stainless-steel/md5), and the Rust standard library.
* The Skyline emulator project (RIP), for [writing the tedious boilerplate needed to replace file management on newer Android versions](https://github.com/skyline-emu/skyline/blob/dc20a615275f66bee20a4fd851ef0231daca4f14/app/src/main/java/emu/skyline/provider/DocumentsProvider.kt).
* The [Rust project](https://www.rust-lang.org/) generally.
* The various people out there who've documented the iPhone OS platform, officially or otherwise. Much of this documentation is linked to within this codebase!

View File

@@ -6,17 +6,16 @@
//! Audio file decoding and OpenAL bindings.
//!
//! The audio file decoding support is an abstraction over various libraries
//! (currently [caf], [hound], and dr_mp3), usage of which should be confined to
//! this module.
//! (currently [caf], [hound], and [symphonia]), usage of which should be
//! confined to this module.
//!
//! Resources:
//! - [Apple Core Audio Format Specification 1.0](https://developer.apple.com/library/archive/documentation/MusicAudio/Reference/CAFSpec/CAF_intro/CAF_intro.html)
mod aac;
mod ima4;
mod symphonia_formats;
pub use ima4::decode_ima4;
use touchHLE_dr_mp3_wrapper as dr_mp3;
pub use touchHLE_openal_soft_wrapper as openal;
use crate::fs::{Fs, GuestPath};
@@ -54,8 +53,7 @@ pub struct AudioFile(AudioFileInner);
enum AudioFileInner {
Wave(hound::WavReader<Cursor<Vec<u8>>>),
Caf(caf::CafPacketReader<Cursor<Vec<u8>>>),
Mp3(dr_mp3::Mp3DecodedToPcm),
Aac(aac::AacDecodedToPcm),
Symphonia(symphonia_formats::SymphoniaDecodedToPcm),
}
impl AudioFile {
@@ -75,28 +73,19 @@ impl AudioFile {
// trying both. This is worked around here by using temporary readers
// for checking if the file is the supported format, then recreating the
// reader if that works.
if hound::WavReader::new(Cursor::new(&bytes)).is_ok() {
let reader = hound::WavReader::new(Cursor::new(bytes)).unwrap();
Ok(AudioFile(AudioFileInner::Wave(reader)))
} else if caf::CafPacketReader::new(Cursor::new(&bytes), vec![]).is_ok() {
let reader = caf::CafPacketReader::new(Cursor::new(bytes), vec![]).unwrap();
Ok(AudioFile(AudioFileInner::Caf(reader)))
// TODO: Real MP3 container handling. Currently we are immediately
// decoding the entire file to PCM and acting as if it's a PCM file,
// simply because because this is easier. Full MP3 support would require
// a lot of changes in Audio Toolbox.
} else if let Ok(pcm) = dr_mp3::decode_mp3_to_pcm(&bytes) {
Ok(AudioFile(AudioFileInner::Mp3(pcm)))
// TODO: Real MP4 container handling for AAC. The situation is the same
// as for MP3.
} else if let Ok(pcm) = aac::decode_aac_to_pcm(Cursor::new(bytes)) {
Ok(AudioFile(AudioFileInner::Aac(pcm)))
// TODO: Real MP3/MP4/Non-linear PCM container handling. Currently we
// are immediately decoding the entire file to PCM and acting as if
// it's a PCM file, simply because because this is easier. Full MP3
// support would require a lot of changes in Audio Toolbox.
} else if let Ok(pcm) = symphonia_formats::decode_symphonia_to_pcm(Cursor::new(bytes)) {
Ok(AudioFile(AudioFileInner::Symphonia(pcm)))
} else {
log!(
"Could not decode audio file at path {:?}, likely an unimplemented file format.",
path.as_ref()
);
Err(AudioFileOpenError::FileDecodeError)
}
}
@@ -167,12 +156,7 @@ impl AudioFile {
bits_per_channel,
}
}
AudioFileInner::Mp3(dr_mp3::Mp3DecodedToPcm {
sample_rate,
channels,
..
})
| AudioFileInner::Aac(aac::AacDecodedToPcm {
AudioFileInner::Symphonia(symphonia_formats::SymphoniaDecodedToPcm {
sample_rate,
channels,
..
@@ -214,16 +198,17 @@ impl AudioFile {
// variable size not implemented
u64::from(self.packet_size_fixed()) * self.packet_count()
}
AudioFileInner::Mp3(dr_mp3::Mp3DecodedToPcm { ref bytes, .. })
| AudioFileInner::Aac(aac::AacDecodedToPcm { ref bytes, .. }) => bytes.len() as u64,
AudioFileInner::Symphonia(symphonia_formats::SymphoniaDecodedToPcm {
ref bytes,
..
}) => bytes.len() as u64,
}
}
pub fn packet_count(&self) -> u64 {
match self.0 {
AudioFileInner::Wave(_)
| AudioFileInner::Mp3(dr_mp3::Mp3DecodedToPcm { .. })
| AudioFileInner::Aac(aac::AacDecodedToPcm { .. }) => {
| AudioFileInner::Symphonia(symphonia_formats::SymphoniaDecodedToPcm { .. }) => {
// never variable-size
self.byte_count() / u64::from(self.packet_size_fixed())
}
@@ -316,8 +301,10 @@ impl AudioFile {
}
Ok(byte_offset)
}
AudioFileInner::Mp3(dr_mp3::Mp3DecodedToPcm { ref bytes, .. })
| AudioFileInner::Aac(aac::AacDecodedToPcm { ref bytes, .. }) => {
AudioFileInner::Symphonia(symphonia_formats::SymphoniaDecodedToPcm {
ref bytes,
..
}) => {
let bytes = bytes.get(offset as usize..).ok_or(())?;
let bytes_to_read = buffer.len().min(bytes.len());
let bytes = &bytes[..bytes_to_read];

View File

@@ -1,16 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
[package]
name = "touchHLE_dr_mp3_wrapper"
version = { workspace = true }
edition = { workspace = true }
license = { workspace = true }
authors = { workspace = true }
homepage = { workspace = true }
[lib]
path = "lib.rs"
[build-dependencies]
cc = { workspace = true }

View File

@@ -1,21 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
use std::path::Path;
fn rerun_if_changed(path: &Path) {
println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
}
fn main() {
let package_root = Path::new(env!("CARGO_MANIFEST_DIR"));
let workspace_root = package_root.join("../../..");
cc::Build::new()
.file(package_root.join("lib.c"))
.compile("dr_mp3_wrapper");
rerun_if_changed(&package_root.join("lib.c"));
rerun_if_changed(&workspace_root.join("vendor/dr_libs/dr_mp3.h"));
}

View File

@@ -1,29 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#define DR_MP3_IMPLEMENTATION
#define DR_MP3_NO_STDIO
#include "../../../vendor/dr_libs/dr_mp3.h"
#include <stdint.h>
#include <stdlib.h>
int16_t *touchHLE_decode_mp3_to_pcm(const uint8_t *data, size_t data_size,
uint32_t *channels, uint32_t *sample_rate,
uint64_t *frame_count) {
drmp3_config config;
int16_t *samples = drmp3_open_memory_and_read_pcm_frames_s16(
data, data_size, &config, (drmp3_uint64 *)frame_count,
/* pAllocationCallbacks: */ NULL);
if (samples) {
*channels = config.channels;
*sample_rate = config.sampleRate;
}
return samples;
}
void touchHLE_free_decoded_mp3_pcm(int16_t *samples) {
drmp3_free(samples, /* pAllocationCallbacks: */ NULL);
}

View File

@@ -1,68 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
//! This is separated out into its own package so that we can avoid rebuilding
//! dr_mp3 more often than necessary, and to improve build-time parallelism.
// Allow the crate to have a non-snake-case name (touchHLE).
// This also allows items in the crate to have non-snake-case names.
#![allow(non_snake_case)]
// See build.rs and lib.c
extern "C" {
fn touchHLE_decode_mp3_to_pcm(
data: *const u8,
data_size: usize,
channels: *mut u32,
sample_rate: *mut u32,
frame_count: *mut u64,
) -> *mut i16;
fn touchHLE_free_decoded_mp3_pcm(samples: *mut i16);
}
/// PCM data decoded from an MP3 file.
pub struct Mp3DecodedToPcm {
/// 16-bit little-endian PCM samples, grouped in frames (one sample per
/// channel in each frame).
pub bytes: Vec<u8>,
/// Sample rate in Hz.
pub sample_rate: u32,
/// Channel count.
pub channels: u32,
}
#[allow(clippy::result_unit_err)]
pub fn decode_mp3_to_pcm(data: &[u8]) -> Result<Mp3DecodedToPcm, ()> {
let mut channels = 0;
let mut sample_rate = 0;
let mut frame_count = 0;
let samples_ptr = unsafe {
touchHLE_decode_mp3_to_pcm(
data.as_ptr(),
data.len(),
&mut channels,
&mut sample_rate,
&mut frame_count,
)
};
if samples_ptr.is_null() {
return Err(());
}
let bytes = unsafe {
std::slice::from_raw_parts(
samples_ptr as *const _,
std::mem::size_of::<i16>() * (frame_count as usize) * (channels as usize),
)
}
.to_vec();
unsafe { touchHLE_free_decoded_mp3_pcm(samples_ptr) };
Ok(Mp3DecodedToPcm {
bytes,
sample_rate,
channels,
})
}

View File

@@ -11,11 +11,11 @@
use std::io::Cursor;
use symphonia::core::audio::{RawSampleBuffer, SignalSpec};
use symphonia::core::codecs::CODEC_TYPE_AAC;
use symphonia::core::codecs::{CODEC_TYPE_AAC, CODEC_TYPE_MP3};
use symphonia::core::io::MediaSourceStream;
/// PCM data decoded from an AAC file.
pub struct AacDecodedToPcm {
pub struct SymphoniaDecodedToPcm {
/// 16-bit little-endian PCM samples, grouped in frames (one sample per
/// channel in each frame).
pub bytes: Vec<u8>,
@@ -25,7 +25,7 @@ pub struct AacDecodedToPcm {
pub channels: u32,
}
pub fn decode_aac_to_pcm(file: Cursor<Vec<u8>>) -> Result<AacDecodedToPcm, ()> {
pub fn decode_symphonia_to_pcm(file: Cursor<Vec<u8>>) -> Result<SymphoniaDecodedToPcm, ()> {
let mss = MediaSourceStream::new(Box::new(file), Default::default());
// If this failed, the container format is not supported.
@@ -43,7 +43,7 @@ pub fn decode_aac_to_pcm(file: Cursor<Vec<u8>>) -> Result<AacDecodedToPcm, ()> {
let track = format
.tracks()
.iter()
.find(|t| t.codec_params.codec == CODEC_TYPE_AAC)
.find(|t| t.codec_params.codec == CODEC_TYPE_AAC || t.codec_params.codec == CODEC_TYPE_MP3)
.ok_or(())?;
let track_id = track.id;
@@ -91,8 +91,7 @@ pub fn decode_aac_to_pcm(file: Cursor<Vec<u8>>) -> Result<AacDecodedToPcm, ()> {
}
}
let signal_spec = signal_spec.ok_or(())?;
Ok(AacDecodedToPcm {
Ok(SymphoniaDecodedToPcm {
bytes: out_pcm,
sample_rate: signal_spec.rate,
channels: signal_spec.channels.count().try_into().unwrap(),

View File

@@ -127,13 +127,6 @@ const PVRTD_LICENSE: &str = include_str!(concat!(
"/vendor/PVRTDecompress/LICENSE.md"
));
const DR_MP3: &str = "
touchHLE, and therefore this executable, incorporates the library dr_mp3,
which is available either under The Unlicense (which is a public domain
dedication) or under the terms of the MIT license. dr_mp3 is in turn derived
from the library minimp3, which is licensed under the Creative Commons CC0 1.0
Universal Public Domain Dedication.
";
// When resource files are bundled with touchHLE in such a way that the user can
// read their license files directly, use this caveat.
@@ -215,8 +208,6 @@ fn print(out: &mut String, resources_are_external_files: bool) -> Result<(), std
divider(out)?;
writeln!(out, "{}", PVRTD_DESCRIPTION)?;
writeln!(out, "{}", PVRTD_LICENSE.trim_end())?;
divider(out)?;
writeln!(out, "{}", DR_MP3)?;
if !resources_are_external_files {
divider(out)?;
writeln!(out, "{}", INTERNAL_DYLIBS_DESCRIPTION)?;

1
vendor/dr_libs vendored

Submodule vendor/dr_libs deleted from dd762b861e