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

[ENCHANCEMENT] Rework SF3 Logic To Preserve Compressed Samples #204

Open
spessasus opened this issue Jul 28, 2024 · 2 comments
Open

[ENCHANCEMENT] Rework SF3 Logic To Preserve Compressed Samples #204

spessasus opened this issue Jul 28, 2024 · 2 comments

Comments

@spessasus
Copy link
Contributor

spessasus commented Jul 28, 2024

The Issue

SF3 uses Ogg Vorbis compression, which is lossy. This poses a problem because loading an SF3 into Polyphone and saving it again decompresses and then recompresses the samples, leading to a loss in quality.

The Solution

I propose that Polyphone should preserve compressed samples instead of decompressing them. With issue #201 now fixed, here’s how the logic could be adjusted:

Loading an .sf3 Soundfont

  1. Load the Soundfont: Load the soundfont with compressed samples, but decompress them only into memory for playback.
  2. Adding Samples: When a user adds a sample, save it as uncompressed. SF3 format supports a mix of compressed and uncompressed samples so this shouldn't be a problem.
  3. Saving the Soundfont: When saving, keep the compressed samples unchanged and save the new uncompressed samples as is. The exported format will be .sf3. To export an .sf2, user should use the export menu which is described below.

Exporting an .sf3 Soundfont

When Exporting .sf3

  • Preserve compressed samples and compress uncompressed samples.

When Exporting .sf2

  • Decompress compressed samples and preserve uncompressed samples. Additionally, update ifil to 2 and adjust sampleType to remove the compression flag.

This approach avoids unnecessary decompression and recompression, thus preserving sample quality.

Let me know what you think!

@davy7125
Copy link
Owner

I will delay a bit the work on the sf2 / sf3 parser since I need more time to do and test it:

  • the original input parser must be updated so that it can load OGG data
  • the musescore's parser will be deleted
  • the output parser must be redesigned
  • an internal attribute must be added for all samples to know if they have been modified, so that when saving the soundfont we choose to use the input data or a compression of the new data.

When clicking on a sample in the tree, I'll also add a checkbox (which will be also a warning) so that we can decide if we want the compressed or raw version of the waveform.

@spessasus
Copy link
Contributor Author

Hi Davy,

I have a slightly different idea on handling the samples. Instead of a modified attribute, I think a sample would have a compressed boolean. And two data arrays: compressed data and uncompressed data. When polyphone loads the soundfont, it loads the compressed data and decompresses it into another table and uses it for playback. For the uncompressed samples, the compressed data table is empty.

When I open a sample in Polyphone, it could show at the bottom "sample type: compressed" or something like that. It would not decompress the sample.

Editing behavior

  • Renaming the sample, changing loop points, key or pitch correction do not decompress the sample.
  • Trimming the sample decompresses the sample, preferably with a warning like "Trimming this sample will decompress it with a slight quality loss. Are you sure you want to continue?"

Once the user clicks yes, the compressed flag is set to false and the compressed array gets deleted, leaving only the uncompressed array.

When saving the soundfont, simply check for the compressed boolean. If true, copy the compressed data (and adjust the sample index and loop points) and add the compressed flag to sampleType. If the boolean is false, copy the uncompressed data and save as an usual sf2 sample (and always zero the 4th bit of sampleType because the sample might've been compressed)

I've implemented this logic in my soundfont code

This function returns the "raw data" which gets directly copied into the file. As you can see, it copies the compressed data if the sample is compressed and uncompressed data otherwise.

Let me know what you think about my version and thanks for considering this feature!

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

No branches or pull requests

2 participants