sinshu / meltysynth

A SoundFont MIDI synthesizer for .NET
Other
130 stars 15 forks source link

[Question] Arachno SoundFont Drum Kits #41

Closed chaojian-zhang closed 1 week ago

chaojian-zhang commented 8 months ago

Hi, thanks a lot for this amazing library! It's awesome👍, and I've used it in my personal project here (Fluent Synth)😆. In general it is very straightforward and works great out of the box, but I do notice a difference in playback compared to VLC's FluidSynth. At the moment I am still looking into whether it has to do with my setup or it's just the two platforms interpret MIDI files different.

Anyway, my question here is related to Arachno SoundFont - Version 1.0: in the documentation of this sound font it mentioned there are some "drum kits" available:

image

I wonder how we can use those drum kits through Melty Synth? (In the documentation it mentioned General MIDI has Music Box or instrument number 10 used as default for drum kit, but not further information on that) If you have any information on how those drum kits are defined inside a MIDI file that would also be very helpful!

chaojian-zhang commented 8 months ago

By the way, as to the first part of my description above - "sound difference between VLC and Melty Synth", I was using NAudio for play back and testing Clickteam - Klik & Play - Romeo - Medieval Tune (Greensleeves).mid that comes with arachno-soundfont-1.0 inside the "MIDI Files" folder. You can reproduce and hear it using code below (I am using NAudio for playback):

byte[] ConvertChannels(float[] left, float[] right)
{
    var bytes = left
        .Zip(right, (left, right) => (Left: left, Right: right))
        .SelectMany(channels => {
            // This automatically handles both negative and positive spectrum 
            // because channels value could be negative
            var sampleL = (short)(channels.Left * short.MaxValue);
            var sampleR = (short)(channels.Right * short.MaxValue);

            var bytesL = BitConverter.GetBytes(sampleL);
            var bytesR = BitConverter.GetBytes(sampleR);
            // Each sample is just byte sequence of a short
            // Samples for each channel follows each other
            return new byte[] {
                bytesL[0], bytesL[1], 
                bytesR[0], bytesR[1]
            };
        })
        .ToArray();
    return bytes;
}

WaveOutEvent Play(int sampleRate, float[] left, float[] right)
{
    var bytes = ConvertChannels(left, right);
    var memoryStream = new MemoryStream(bytes);
    var waveStream = new RawSourceWaveStream(memoryStream, new WaveFormat(sampleRate, 16, 2));
    var outputDevice = new WaveOutEvent();

    outputDevice.Init(waveStream);
    outputDevice.Play();
    return outputDevice;
}
var sampleRate = 44100;
var synthesizer = new Synthesizer(soundFontFilePath, sampleRate);
var midiFile = new MidiFile(@"Clickteam - Klik & Play - Romeo - Medieval Tune (Greensleeves).mid");

var sequencer = new MidiFileSequencer(synthesizer);
sequencer.Play(midiFile, false);

var left = new float[(int)(sampleRate * midiFile.Length.TotalSeconds)];
var right = new float[(int)(sampleRate * midiFile.Length.TotalSeconds)];
sequencer.Render(left, right);

var waveOutEvent = Play(sampleRate, left);
sinshu commented 8 months ago

If this library is helpful to you, I'd be delighted 😊

To change the type of drum, perform a program change on the drum channel (9). For example, the following code changes the drum to "Room Drum Kit" (No. 8).

synthesizer.ProcessMidiMessage(9, 0xC0, 8, 0);
sinshu commented 8 months ago

Regarding the MIDI file you provided, I listened to it using MeltySynth's MIDI playback sample code and didn't encounter any issues (although the nostalgia of the song almost made me cry). Are you experiencing glitches during playback? Or does the sound quality in specific parts differ compared to other playback software? If you could elaborate a bit more, I might be able to help.

chaojian-zhang commented 8 months ago

If this library is helpful to you, I'd be delighted 😊

To change the type of drum, perform a program change on the drum channel (9). For example, the following code changes the drum to "Room Drum Kit" (No. 8).

synthesizer.ProcessMidiMessage(9, 0xC0, 8, 0);

Thank you very much for quick reply! I tried this and it worked!

Can we have more than one drum channel, or specify custom drum channels (e.g. use channel 11 for drum as well)?

chaojian-zhang commented 8 months ago

Regarding the MIDI file you provided, I listened to it using MeltySynth's MIDI playback sample code and didn't encounter any issues (although the nostalgia of the song almost made me cry). Are you experiencing glitches during playback? Or does the sound quality in specific parts differ compared to other playback software? If you could elaborate a bit more, I might be able to help.

Memory tricks us - hopefully, that's sweetness that you felt.

To be clear, Melty synth handles MIDI synthesization flawlessly without any issues or glitches! I was referring more to the sound quality, when compared to VLC (I don't have other playback software to compare with at the moment).

I have converted the same MIDI into mp3 file and opened the first 10s in Audacity (top is from Melty Synth, bottom is from VLC's Fluid Synth), as you can see, VLC produce in general higher volume. But that's not the only difference. The version from VLC seems to have the violin/cello part enhanced.

image

This is the same samples in spectrogram view:

Spectrogram

I upload them as mp4 because that's the format Github supports.

This is the result from Melty Synth:

https://github.com/sinshu/meltysynth/assets/7077098/a72cbc19-6b59-4229-b955-c5d44e436e31

This is the result from VLC:

https://github.com/sinshu/meltysynth/assets/7077098/15cd7b65-4948-490c-a10a-c6c777675503

First 3 seconds (waveform shown in dB) from Melty Synth:

image

First 3 seconds (waveform shown in dB) from VLC:

image

In general, the base from VLC is stronger and fuller. I don't know whether that's a result of VLC configuration or something from the MIDI file specifies that. Below shows my VLC (version 3.0.11 Vetinari) configuration for Fluid Synth:

image

(Not sure whether it's related to Chorus and Reverb - I tried to turn them off and it doesn't seem to have any effect)

sinshu commented 8 months ago

First, if you want to increase the overall volume, you can do so by setting the Synthesizer.MasterVolume property to a larger value.

Regarding the violin sounding more prominent in VLC, it is believed that the chorus effect implemented in FluidSynth is causing this. The corresponding instrument in Arachno SoundFont is set to have a chorus of 100%, which appears to be pushing up the volume. In fact, if you turn off the chorus in VLC’s settings, you will get roughly the same volume balance as MeltySynth.

The chorus in MeltySynth is different from FluidSynth. This is not a matter of which one is correct, but rather a matter of preference.

sinshu commented 8 months ago

Can we have more than one drum channel, or specify custom drum channels (e.g. use channel 11 for drum as well)?

MeltySynth primarily offers compatibility with General MIDI 1. In General MIDI 1, the drum channel is fixed at 10 and cannot be increased without some kind of extension. However, in SoundFont, drum presets are stored in bank number 128. Therefore, by sending a command to set the bank number to 128 for a specific channel, as shown below, you can use drums on that channel.

// Change channel[0] to drums
synthesizer.ProcessMidiMessage(0, 0xB0, 0, 128);

Note that this method may not work on other synthesizers.