theori-io / nrsc5

NRSC-5 receiver for rtl-sdr
Other
783 stars 100 forks source link

Underruns & cracking noises #330

Open TheDaChicken opened 9 months ago

TheDaChicken commented 9 months ago

I am getting: Underruns / cracking noises. Here is a video: https://youtu.be/XMswC9g92ZY I could send anything like IQ recording etc of any type in the process.

Here is my code model:

This is what I am doing for converting from float to uint8_t:

void IQConverterFUC::Process(const DataBuffer<std::complex<float>> &input, DataBuffer<uint8_t> &output)
{
    output.SetSize(input.GetSize() * 2);
    for (int i = 0; i < input.GetSize(); ++i)
    {
        auto I = static_cast<uint8_t>((input[i].real() * 128.0f) + 127.4f);
        auto Q = static_cast<uint8_t>((input[i].imag() * 128.0f) + 127.4f);
        output[2 * i] = I;
        output[2 * i + 1] = Q;
    }
}
argilo commented 9 months ago

I would guess that this has the same root cause as #261 (and closely related #177).

argilo commented 9 months ago

Basically, the library needs to implement proper buffering & delay, and when given input samples it should produce output samples at a fixed ratio. It will be a fair amount of work to get it all right, which is why I haven't taken a stab at it yet.

TheDaChicken commented 9 months ago

That would be helpful. I am using PortAudio and PortAudio LOVES to grab samples before they are available. Even just exposing some stuff related to buffering could help.

TheDaChicken commented 9 months ago

Plus another thing I was thinking about:

Should buffering be implemented in client code or be implemented in the API? The API can just expose stuff related to buffering like latency etc. That way buffering can be managed in any way needed.

argilo commented 9 months ago

The client code could do some additional buffering of its own if it really needs to, but there will have to be some buffering on the API side to get the latency correct and allow things like analog blending.

TheDaChicken commented 9 months ago

The client code could do some additional buffering of its own if it really needs to, but there will have to be some buffering on the API side to get the latency correct and allow things like analog blending.

The reason i asked that question is because my program does the analog "blending" itself since it's not implemented in nrsc5. There is no way for me to tell any latency. Plus, the amount of silence I have to add for no-blending feels kind of weird.

TheDaChicken commented 9 months ago

I want to make your life easier because you may not have much free time.

TheDaChicken commented 8 months ago

I want to make your life easier because you may not have much free time.

Should I try to make my own implementation? What's best idea here?

argilo commented 8 months ago

You're welcome to take a crack at it. I don't have any immediate plans to work on this.

TheDaChicken commented 8 months ago

Okay here is what I got out of: 1017s.pdf. PDU contains latency Common Delay Per Stream Delay. That's all I could understand.

latency gives the burst range that HDRadio could give bla bla.

I created a simple buffer that just starts outputting frames after latency. I removed the start silence. It cuts out twice or three times at the start. After that, it is already a big improvement apparently. I had a few clickly noises while I was coding this. Afterward, I didn't hear it anymore.

FoxxMD commented 7 months ago

@TheDaChicken have you made any more progress? I'm interested in getting this fixed as well...

TheDaChicken commented 7 months ago

@TheDaChicken have you made any more progress? I'm interested in getting this fixed as well...

I have made some progress. Still working on it. I made something but it outputs fixed packets at a variable rate...

There are so many things that makes this hard. For example, being accurate. Analog bending would be based on whatever is buffered from some average rate that was calculated in the buffer. Which I guess is fine???

TheDaChicken commented 3 months ago

@argilo

Okay, I am trying again pinging since I have a few ideas about solving the problem and it depends.

I did a lot of more testing. Delaying output to output at a fixed ratio would require more delay than a normal receiver. Since there is no easy way of outputting at a fixed ratio since it would require sleeping on another thread, not always accurate, etc unless the library is missing another way to grab packets more quickly. Delaying packets based on maximum latency results in good buffering anyway.

Icecast does a similar thing. It first sends a lot (gives a lot to buffer) and then slows down to "real-time"

Here is what I am proposing:

I think the 3rd one is the best idea.