Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Signed/unsigned is reversed #39

Closed
ruuda opened this issue Apr 27, 2015 · 3 comments
Closed

Signed/unsigned is reversed #39

ruuda opened this issue Apr 27, 2015 · 3 comments
Labels

Comments

@ruuda
Copy link
Contributor

ruuda commented Apr 27, 2015

I believe signed and unsigned samples are handled in precisely the opposite way of how they should be handled. For instance, the beep example produces a very sharp sound, whereas it should produce a sine wave of exactly one frequency, which sounds very soft.

On the other hand, I modified the example to produce signed samples instead:

extern crate cpal;

fn main() {
    let mut channel = cpal::Voice::new();

    let amplitude = std::i16::MAX as f32;
    let mut data_source = (0u64..).map(|t| t as f32 * 0.03)
                                  .map(|t| (t.sin() * amplitude) as i16);

    loop {
        {
            let mut buffer: cpal::Buffer<i16> =
                channel.append_data(1, cpal::SamplesRate(44100), 32768);

            for (sample, value) in buffer.iter_mut().zip(&mut data_source) {
                *sample = value;
            }
        }

        channel.play();
    }
}

This again produces the sharp sound that sounds like a square wave. When the last two occurences of i16 are replaced by u16 — effectively rendering a signed sine wave but casting it to u16 — the sound sounds like a sine again. I verified the above code on Windows as well as Linux.

On a side note, when I ran the beep example on Windows I could sometimes hear large fluctuations in the frequency, even though it should be constant. The frequency would jump abrubtly after a few seconds.

@tomaka tomaka added the bug label Apr 27, 2015
@mitchmindtree
Copy link
Member

How large were the fluctuations in frequency? Around 30-40hz? If they were small fluctuations, they might be because of the phase's resolution (32-bit floating point) changing to a f64 might fix this?

As for the signed/unsigned, I'm not sure (don't have time to check atm).

@ruuda
Copy link
Contributor Author

ruuda commented Apr 27, 2015

I don’t know how big the fluctuations are in Hz, but it is all pretty much in the range of one note difference. Thinking about it again, I now know exactly what the problem is: it is indeed a floating-point problem. You get rounding errors, because the accumulator grows very rapidly, so 0.03 becomes small in comparison with the accumulator quickly, and precision is lost when adding. The proper way to deal with this is to use compensated summation, but in this case there is an easier solution, which I happened to implement accidentally: use multiplication by a counter instead of addition. So I opened #40 because I thought this was neater than the manual Iterator implementation, and it happens to fix this fluctuation as well!

@ruuda
Copy link
Contributor Author

ruuda commented Jul 22, 2015

This has been fixed in #51.

@ruuda ruuda closed this as completed Jul 22, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants