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

Modulation envelope is not convex and has the wrong duration #55

Open
spessasus opened this issue Nov 12, 2024 · 3 comments
Open

Modulation envelope is not convex and has the wrong duration #55

spessasus opened this issue Nov 12, 2024 · 3 comments

Comments

@spessasus
Copy link

Hi sinshu,

I've found a bug in the soundfont implementation of meltysynth. It is not related to modulators or unsupported/unplanned features, so I'm opening an issue.

SF Specification, section 8.1.2:

26 attackModEnv
This is the time, in absolute timecents, from the end of the Modulation Envelope
Delay Time until the point at which the Modulation Envelope value reaches its peak.
Note that the attack is “convex”; the curve is nominally such that when applied to a
decibel or semitone parameter, the result is linear in amplitude or Hz respectively.

As you can see below, meltysynth uses linear attack instead of convex, and it is too short, compared to fluidsynth:
image

This was tested using the soundfont specification test

This code was used to render the file:

using MeltySynth;
using NAudio;
using NAudio.Wave;

class Program
{
    static void Main(string[] args)
    {
        Synthesizer synth =
            new Synthesizer("/home/spessasus/Desktop/SoundFont-Spec-Test/sf_spec_test.sf2", 44100);
        MidiFileSequencer seq = new MidiFileSequencer(synth);
        MidiFile mid = new MidiFile("/home/spessasus/Desktop/SoundFont-Spec-Test/sf_spec_test.mid");
        seq.Play(mid, false); ;
        var audioLeft = new float[(int)(44100 * mid.Length.TotalSeconds / seq.Speed)];
        var audioRight = new float[(int)(44100 * mid.Length.TotalSeconds / seq.Speed)];
        Console.WriteLine(audioLeft.Length);
        seq.Render(audioLeft, audioRight);
        WaveFormat waveFormat = new WaveFormat(44100, 16, 2); // 44100 Hz, 16-bit, Stereo
        using (WaveFileWriter writer = new WaveFileWriter("/home/spessasus/Desktop/meltysynth.wav", waveFormat))
        {
            for (int i = 0; i < audioLeft.Length; i++)
            {
                writer.WriteSample(audioLeft[i]);
                writer.WriteSample(audioRight[i]);
            }
        }
    }
}
@sinshu
Copy link
Owner

sinshu commented Nov 15, 2024

Thank you for the report.

It seems that this issue happens because MeltySynth was made based on TinySoundFont. Below is a similar issue reported for TinySoundFont:
schellingb/TinySoundFont#94

About the problem with the short attack time, it looks like TinySoundFont changes the attack based on velocity. It can probably be fixed by just removing this process:

// According to the implementation of TinySoundFont, the attack time should be adjusted by the velocity.

For the problem of the attack being linear, would it work to use a function like the release curve of the volume envelope, but flipped upside down? 🤔

image

@spessasus
Copy link
Author

Here's the fluidsynth's convex and concave lookup tables. I've implemented them in spessasynth and everything works correctly:
https://github.com/FluidSynth/fluidsynth/blob/168183c3b63efdf43ec07449a1a921c2c7b63868/src/gentables/gen_conv.c#L41-L60

@sinshu
Copy link
Owner

sinshu commented Nov 15, 2024

Thank you for the information. However, I cannot use FluidSynth's code because it is under the LGPL, and I want to maintain the MIT license. I'll do some more research on this.

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