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

Psuedocode for doing fast cubic spline interpolation (for better resampling quality) #2

Open
8bitbubsy opened this issue Dec 16, 2022 · 2 comments

Comments

@8bitbubsy
Copy link

8bitbubsy commented Dec 16, 2022

So I saw the talk about a possible cubic spline interpolator mode for PicoGUS, which would result in crisper audio with less treble being cut off from linear interpolation.

Here's some code I wrote that should work: https://pastebin.com/raw/Yvyh63VP

The only problem is that you need to input the correct sample points for the s0..s3 function parameters. This is slightly tricker than having to deal with just one extra sample (like with linear interpolation).

Here's what s0..s3 should be based on a few conditions (could be off, but something like this anyway).

Some notes first:

  • Pos is the current integer sampling position
  • End is the end point for a non-looping sample
  • s is a pointer to the sample data (either 8-bit or 16-bit samples)
  • HasLooped is a flag for having reached the end of a loop on a looping sample. Set it to false when a voice is starting to play a sample (sample trigger), and set it to true when you have looped at least once (sample is looping its loop now). I'm sure it has to be set to false in other situations as well.

Non-looping sample:

  • s0 = if (Pos == 0) s[0] else s[Pos-1];
  • s1 = s[Pos]
  • s2 = if (Pos+1 >= End) s[End-1] else s[Pos+1]; (yes, End-1. As in the last sample point)
  • s3 = if (Pos+2 >= End) s[End-1] else s[Pos+2];

Forward-looping sample:

  • s0 = if (HasLooped) { if (Pos == LoopStart) s[LoopEnd-1] else s[Pos-1]; } else if (Pos == 0) s[0] else s[Pos-1]; }
  • s1 = s[Pos]
  • s2 = if (Pos+1 >= LoopEnd) s[LoopStart+((Pos+1)-LoopEnd)] else s[Pos+1];
  • s3 = if (Pos+2 >= LoopEnd) s[LoopStart+((Pos+2)-LoopEnd)] else s[Pos+2];

Bidirectional-looping sample:

  • s0 = if (HasLooped) { if (Pos == LoopStart) s[LoopStart+1] else s[Pos-1]; } else if (Pos == 0) s[0] else s[Pos-1]; }
  • s1 = s[Pos]
  • s2 = if (Pos+1 >= LoopEnd) s[LoopEnd-((Pos+2)-LoopEnd)] else s[Pos+1]; (do Pos+2/Pos+3 for an extra -1)
  • s3 = if (Pos+2 >= LoopEnd) s[LoopEnd-((Pos+3)-LoopEnd)] else s[Pos+2];

There could be some off-by-one (or bigger) errors here, so do experiment with it. If it's possible to sample backwards in "forward loop" mode, then it would also need more logic.

PS: I totally understand if this is too bothersome to implement, and that's fine. :-)

@ramapcsx2
Copy link

Hey, I'm not part of this project, but I wonder what you think the performance / RAM impact of this will be :)

@8bitbubsy
Copy link
Author

8bitbubsy commented Dec 17, 2022

It ought to be quite faster than doing cubic spline without a table. RAM usage for the table is 4x512x2 (4096) bytes.

EDIT: Naturally it's slower than linear interpolation, but the quality improvement is quite good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants