Coder Social home page Coder Social logo

libfmod's People

Contributors

lebedec avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

libfmod's Issues

Dsp::get_parameter_data usage for getting the FFT spectrum of a channel

There doesn't seem to be an easy way of accessing FFT spectrum information of a channel.

Dereferencing pointers to libfmod::ffi::FMOD_DSP_PARAMETER_FFT after receiving them via calls to Dsp::get_parameter_data() in unsafe blocks doesn't sound like the best idea (it doesn't even return any data anyway, which renders the whole procedure useless), while the FFT DSP feature of FMOD is one that does come in handy and should, in my opinion, be properly implemented as part of the binding.

Is there something that could be done here to fix this?

A lot of functions do not return the correct types or take incorrect parameters

I noticed that a lot of functions are returning types or results they should not be-

For example: All is_valid functions return FMOD_BOOL (a typedef for c_int) which libfmod interprets as Result<(), libfmod::Error>, rather than a bool.

Other functions, like libfmod::Studio::load_bank_memory take a String when they really should take bytes. Functions like these are expecting a char* as bytes, not a string. This relegates these functions to be practically useless.

    pub fn load_bank_memory(
        &self,
        buffer: &str,
        length: i32,
        mode: LoadMemoryMode,
        flags: ffi::FMOD_STUDIO_LOAD_BANK_FLAGS,
    ) -> Result<Bank, Error> {
        unsafe {
            let mut bank = null_mut();
            match ffi::FMOD_Studio_System_LoadBankMemory(
                self.pointer,
                CString::new(buffer)?.as_ptr(),
                length,
                mode.into(),
                flags,
                &mut bank,
            ) {
                ffi::FMOD_OK => Ok(Bank::from(bank)),
                error => Err(err_fmod!("FMOD_Studio_System_LoadBankMemory", error)),
            }
        }
    }

Should be:

    pub fn load_bank_memory(
        &self,
        buffer: Vec<u8>,
        mode: LoadMemoryMode,
        flags: ffi::FMOD_STUDIO_LOAD_BANK_FLAGS,
    ) -> Result<Bank, Error> {
        unsafe {
            let mut bank = null_mut();
            match ffi::FMOD_Studio_System_LoadBankMemory(
                self.pointer,
                CString::from_vec_unchecked(buffer).as_ptr(),
                buffer.len(),
                mode.into(),
                flags,
                &mut bank,
            ) {
                ffi::FMOD_OK => Ok(Bank::from(bank)),
                error => Err(err_fmod!("FMOD_Studio_System_LoadBankMemory", error)),
            }
        }
    }

There's also some functions like libfmod::Bank::get_path which take in the length of a String? and do nothing with it which makes no sense.

    pub fn get_path(&self, size: i32) -> Result<(String, i32), Error> {
        unsafe {
            let path = CString::from_vec_unchecked(b"".to_vec()).into_raw();
            let mut retrieved = i32::default();
            match ffi::FMOD_Studio_Bank_GetPath(self.pointer, path, size, &mut retrieved) {
                ffi::FMOD_OK => Ok((
                    CString::from_raw(path)
                        .into_string()
                        .map_err(Error::String)?,
                    retrieved,
                )),
                error => Err(err_fmod!("FMOD_Studio_Bank_GetPath", error)),
            }
        }
    }

This should be converted to something like this: (matching the C# API pretty much)

    // Please excuse my crude indentation -_-
    pub fn get_path(&self) -> Result<String, Error> {
        unsafe {
            let mut retrieved = i32::default();
            match ffi::FMOD_Studio_Bank_GetPath(self.pointer, std::ptr::null(), 0, &mut retrieved)
            {
                ffi::FMOD_OK => Ok("".to_string()),
                ffi::FMOD_ERR_TRUNCATED => {
                   let path = CString::from_vec_unchecked(vec![b""; retrieved as usize]).into_raw();
                   match ffi::FMOD_Studio_Bank_GetPath(self.pointer, path, retrieved, &mut retrieved) {
                      ffi::FMOD_OK => Ok(CString::from_raw(path)
                        .into_string()
                        .map_err(Error::String)?,
                      ),
                      error => Err(err_fmod!("FMOD_Studio_Bank_GetPath", error)),
                   }
                }
                error => Err(err_fmod!("FMOD_Studio_Bank_GetPath", error)),
            }
        }
    }

It may be a good idea to parse the C# bindings as they more closely rusty style bindings or instead to use libfmod-gen to bootstrap most of the boilerplate code and manually edit the bindings from there.

Generated code handling value conversions and pointers is incorrect

Hello, I just started using the libfmod crate today. Thank you for the work that you've put into it!

Problem

Methods accepting Option<Vector> pass invalid pointers to FMOD, causing errors.

Description

When calling the function System::set_3d_listener_attributes, I kept getting nonsense error messages from fmod about my vectors being incorrect. When I added assertions about my vector values before calling the function, the errors would go away. I inspected the code, linked above.

The generated code casts the input Vector values to FMOD_VECTOR, takes a reference to them, then casts that reference to a pointer, like this:

pos.map(|value| &value.into() as *const _).unwrap_or(null())

This immediately causes a use-after-free. In practice it seems to cause all of the pointers passed to FMOD to point at the same address, which contains garbage. The correct way to approach this problem is to cast the values beforehand, keeping them owned, then taking references to those values and casting them to pointers:

// at the beginning of the function
let pos: Option<ffi::FMOD_VECTOR> = pos.map(Into::into);

// FFI callsite
pos.as_ref().map(|p| p as *const _).unwrap_or(null())

Here is a playground link that reproduces this issue. The function I created to replace FMOD_System_Set3DListenerAttributes simply prints the address of each of the pointers. In the version based on the code in libfmod, all of the addresses are the same. In the fixed version, each address is different, which is correct.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e29edeb154adc0e8b37a330be6c35be7

I searched the codebase for &\w+\.into\(\) as \*const _ and found 12 total occurrences of this pattern. Those functions are likely also impacted.

Solution

The simple fix would be to change the generated code to fix these conversions.

I think it would also be reasonable to unify the FMOD_VECTOR and Vector types, which would eliminate this conversion completely.

Linux/macOS support, idiomatic linkage

Hi there!

Firstly, thanks so much for putting together this fantastic crate; I've been able to integrate fmod on my Windows machine and successfully get sounds playing from fmod studio in Rust - this is a huge win!

However, there are a couple of quirks about this crate that I'd like to understand more about:

  • It's very unusual for a Rust crate that depends on some external library to have a hard coded requirement on where those libraries are located. Compare with OpenXRs or Ash which have flexible and runtime configurable linkage
  • Given fmod's support for macOS and Linux, do you have any plans on supporting these platforms? This is a hard requirement for us as our team use both platforms as part of their developer requirements.

I am more than happy to contribute the required changes and assist with maintenance, if that's required. ๐Ÿ˜„

failed to select a version for the requirement libfmod

Since September 2023 library version number generation has been changed to simplify support for multiple versions and make choosing a specific one even simpler.

For example for FMOD Engine 2.02.06 just use

libfmod = "2.206"

instead of

libfmod = "2.2.607"

Cannot create sound from byte array

I am currently trying to create a sound from an in-memory byte array in OGG format, using System::create_sound with Mode::OPENMEMORY to load the array. The first parameter of the function takes a &str though, which means that it has to be valid UTF-8 and also not contain any null bytes in it.
I have taken a look at the source code for this crate, and identified what should be changed in order for this to work:
https://github.com/lebedec/libfmod-gen/blob/main/src/generators/lib.rs#L714-L715
I don't know much about Rust FFI or C types so any help is appreciated :)

Get location of Fmod libraries from environment

It is idiomatic to use an environment variable in a build script to determine the location of dependencies not provided, and then produce a build error if the environment variable is not set. I would recommend doing this.

Unsafe precondition violations in Rust 1.78.0

Rust 1.78.0 started correctly surfacing some unsafe assertions within the standard library as panics. Since upgrading to Rust 1.78.0, I've started hitting panics when calling some libfmod functions due to unaligned pointers.

I hit this issue calling System::get_advanced_settings, which calls AdvancedSettings::try_from, which uses the to_vec macro, that invokes slice::from_raw_parts on a pointer that Rust is asserting is invalid.

The error that Rust panics with in this case is:

unsafe precondition(s) violated: slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed isize::MAX

Destination is always `../libfmod`

I think this line consumes the iterator
let source = args.nth(1).unwrap_or(FMOD_SDK_PATH.to_string());

thus this unwrap always defaults to ../libfmod
let destination = args.nth(2).unwrap_or("../libfmod".to_string());

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.