lrbalt / libsoxr-rs

Rust wrapper for libsoxr (resampling library for sounds)
Other
8 stars 2 forks source link

split channels are not working, only interleaved #7

Open daniellga opened 1 year ago

daniellga commented 1 year ago

Hi! Thanks for your work.

I have the following example and I am obtaining the error on the title. Could you help me finding out what's going wrong? It works pretty well with Float32I but when I change to Float32S it crashes. I already tried changing to [[f32;48];2] and [[0.0; 96]; 2] for both source and target respectively, to no avail...

        let io_spec = IOSpec::new(Datatype::Float32S, Datatype::Float32S);
        // upscale factor 2, one channel with all the defaults
        let soxr = Soxr::create(1.0, 2.0, 2, Some(&io_spec), None, None).unwrap();

        // source data, taken from 1-single-block.c of libsoxr examples.
        let source: [f32; 96] = [
            0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0,
            0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0,
            0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0,
            0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0,
            0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0,
            0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0,
        ];

        // create room for 2*48 = 96 samples
        let mut target: [f32; 192] = [0.0; 192];

        // Two runs. First run will convert the source data into target.
        // Last run with None is to inform resampler of end-of-input so it can clean up
        soxr.process(Some(&source), &mut target).unwrap();
        soxr.process::<f32, _>(None, &mut target[0..]).unwrap();

        // just print the values in target
        println!("{:?}", target);
        println!("{:?}", target.len());
lrbalt commented 1 year ago

I've been able to reproduce this with your example. Also Foat64S results in a SIGSEGV while the FloatxxI variants all work. I cannot see in the Rust code paths why this is not working correctly. Also used Box and Pin to make sure that using the stack was not a problem, but it still SISSEGV'd. I'll continue the search

lrbalt commented 1 year ago

ok, I've found the problem. For split channels I need to pass a different buffer than for interleaved channels. This means that all split channel calls do not work, only interleaved will currently work

lrbalt commented 1 year ago

@daniellga I think it is fixed now, could you confirm?

daniellga commented 1 year ago

It works pretty well! Thanks a lot!!!

I just have a question, in the following code, should nsamples_output return 96 or 96*nchannels? I am getting 96 but the docs say The result contains number of input samples used and number of output samples placed in ‘buf_out’ so I think 192 would be the expected output.

        let io_spec = IOSpec::new(Datatype::Float32S, Datatype::Float32S);

        let soxr = Soxr::create(1., 2., 2, Some(&io_spec), None, None).unwrap();

        let source: [f32; 96] = [
            0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0,
            0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0,
            0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0,
            0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0,
            0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0,
            0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0,
        ];

        let mut v_out: Vec<f32> = vec![0.; 192];

        let (_, _) = soxr.process(Some(&source), &mut v_out).unwrap();
        let (_, nsamples_output) = soxr.process::<f32, _>(None, &mut v_out[..]).unwrap();
        println!("{:?}", nsamples_output);
lrbalt commented 1 year ago

you are calling soxr.process twice, so I think you need to add nsamples of both calls.

let (_, nsamples_first) = soxr.process(Some(&source), &mut v_out).unwrap();
let (_, nsamples_second) = soxr.process::<f32, _>(None, &mut v_out[..]).unwrap();
println!("{} + {} = {}", nsamples_first, nsamples_second, nsamples_first+nsamples_second);
lrbalt commented 1 year ago

It seems that `soxr.output' suffers from the same problem with split channels. Reopening to fix that

daniellga commented 1 year ago

I actually am getting nsamples_first = 0. Also, aren't we supposed to call it 2 times, in which only the first one makes the resample (check comments in code below, that are taken from the crate's documentation)?

By the way, shouldn't x also be 48*2 = 96? It seems in both cases it's giving the number of frames instead of number of samples both in input and output.

    #[test]
    fn aaa() {
        let io_spec = IOSpec::new(Datatype::Float32S, Datatype::Float32S);

        let soxr = Soxr::create(1., 2., 2, Some(&io_spec), None, None).unwrap();

        let source: [f32; 96] = [
            0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0,
            0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0,
            0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0,
            0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0,
            0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0,
            0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0,
        ];

        let mut v_out: Vec<f32> = vec![0.; 192];

        // Two runs. First run will convert the source data into target.
        // Last run with None is to inform resampler of end-of-input so it can clean up
        let (x, nsamples_first) = soxr.process(Some(&source), &mut v_out).unwrap();
        let (y, nsamples_second) = soxr.process::<f32, _>(None, &mut v_out[..]).unwrap();

        println!(
            "{} + {} = {}",
            nsamples_first,
            nsamples_second,
            nsamples_first + nsamples_second
        );

        println!("x = {:?}, y = {:?}", x, y);
    }

Output:

running 1 test
0 + 96 = 96
x = 48, y = 0
test resample::tests::aaa ... ok
lrbalt commented 1 year ago

I'm seeing the same behavior, thus the first call will use 48 samples (2 channels, so 48 not 96) and the second call will produce output for those 48 samples, i.e. 96 samples or 192 f32 values. I'm not sure why libsoxr works like that. So I think you need to keep using soxr_output until you have received all needed samples?

lrbalt commented 1 year ago

I think the bug is in https://github.com/chirlu/soxr/blob/master/src/soxr.c#L716 where it does not take into account the fact that out is a pointer to an array of pointers in the case of separated channels. I've posted on the discussion forum there, but keeping this note here too

lrbalt commented 1 year ago

https://sourceforge.net/p/soxr/discussion/general/thread/fe41a19fa5/ for reference