1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
// Copyright (c) 2024 Lily Lyons
//
// 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::{
ffi::{c_int, c_uint},
mem::MaybeUninit,
};
use fmod_sys::*;
use lanyard::{Utf8CStr, Utf8CString};
use crate::{get_string, Sound, SoundFormat, SoundType, Tag, TimeUnit};
impl Sound {
/// Retrieves the name of a sound.
///
/// If FMOD_LOWMEM has been specified in System::createSound, this function will return "(null)".
pub fn get_name(&self) -> Result<Utf8CString> {
get_string(|name| unsafe {
FMOD_Sound_GetName(self.inner, name.as_mut_ptr().cast(), name.len() as c_int)
})
}
/// Returns format information about the sound.
pub fn get_format(&self) -> Result<(SoundType, SoundFormat, c_int, c_int)> {
let mut kind = 0;
let mut format = 0;
let mut channels = 0;
let mut bits = 0;
unsafe {
FMOD_Sound_GetFormat(self.inner, &mut kind, &mut format, &mut channels, &mut bits)
.to_result()?;
}
let kind = kind.try_into()?;
let format = format.try_into()?;
Ok((kind, format, channels, bits))
}
/// Retrieves the length using the specified time unit.
///
/// A length of `0xFFFFFFFF` means it is of unlimited length, such as an internet radio stream or MOD/S3M/XM/IT file which may loop forever.
///
/// Note: Using a VBR (Variable Bit Rate) source that does not have metadata containing its accurate length (such as un-tagged MP3 or MOD/S3M/XM/IT) may return inaccurate length values.
/// For these formats, use FMOD_ACCURATETIME when creating the sound.
/// This will cause a slight delay and memory increase, as FMOD will scan the whole during creation to find the correct length.
/// This flag also creates a seek table to enable sample accurate seeking.
pub fn get_length(&self, unit: TimeUnit) -> Result<c_uint> {
let mut length = 0;
unsafe {
FMOD_Sound_GetLength(self.inner, &mut length, unit.into()).to_result()?;
}
Ok(length)
}
/// Retrieves the number of metadata tags.
///
/// 'Tags' are metadata stored within a sound file. These can be things like a song's name, composer etc.
///
/// The second tuple field could be periodically checked to see if new tags are available in certain circumstances.
/// This might be the case with internet based streams (i.e. shoutcast or icecast) where the name of the song or other attributes might change.
pub fn get_tag_count(&self) -> Result<(c_int, c_int)> {
let mut tags = 0;
let mut updated = 0;
unsafe {
FMOD_Sound_GetNumTags(self.inner, &mut tags, &mut updated).to_result()?;
}
Ok((tags, updated))
}
/// Retrieves a metadata tag.
///
/// 'Tags' are metadata stored within a sound file. These can be things like a song's name, composer etc.
///
/// The number of tags available can be found with Sound::getNumTags.
///
/// The way to display or retrieve tags can be done in 3 different ways:
/// - All tags can be continuously retrieved by looping from 0 to the numtags value in Sound::getNumTags - 1. Updated tags will refresh automatically, and the 'updated' member of the FMOD_TAG structure will be set to true if a tag has been updated, due to something like a netstream changing the song name for example.
/// - Tags can be retrieved by specifying -1 as the index and only updating tags that are returned. If all tags are retrieved and this function is called the function will return an error of FMOD_ERR_TAGNOTFOUND.
/// - Specific tags can be retrieved by specifying a name parameter. The index can be 0 based or -1 in the same fashion as described previously.
///
/// Note with netstreams an important consideration must be made between songs, a tag may occur that changes the playback rate of the song. It is up to the user to catch this and reset the playback rate with Channel::setFrequency.
/// A sample rate change will be signalled with a tag of type FMOD_TAGTYPE_FMOD.
///```rs
/// while let Ok(tag) = sound->getTag(None, -1)
/// {
/// if matches!(tag.type, TagType::Fmod) {
/// // When a song changes, the sample rate may also change, so compensate here.
/// if tag.name == "Sample Rate Change" && channel {
/// let TagDataType::Float(frequency) = tag.data else {
/// break
/// };
/// result = channel.set_frequency(frequency)?;
/// }
/// }
/// }
///```
pub fn get_tag(&self, name: Option<&Utf8CStr>, index: c_int) -> Result<Tag> {
let mut tag = MaybeUninit::uninit();
unsafe {
FMOD_Sound_GetTag(
self.inner,
name.map_or(std::ptr::null(), Utf8CStr::as_ptr),
index,
tag.as_mut_ptr(),
)
.to_result()?;
let tag = tag.assume_init();
let tag = Tag::from_ffi(tag);
Ok(tag)
}
}
}