![]() |
VOOZH | about |
dotnet add package MeltySynth --version 2.4.1
NuGet\Install-Package MeltySynth -Version 2.4.1
<PackageReference Include="MeltySynth" Version="2.4.1" />
<PackageVersion Include="MeltySynth" Version="2.4.1" />Directory.Packages.props
<PackageReference Include="MeltySynth" />Project file
paket add MeltySynth --version 2.4.1
#r "nuget: MeltySynth, 2.4.1"
#:package MeltySynth@2.4.1
#addin nuget:?package=MeltySynth&version=2.4.1Install as a Cake Addin
#tool nuget:?package=MeltySynth&version=2.4.1Install as a Cake Tool
MeltySynth is a SoundFont synthesizer written in C#. The purpose of this project is to provide a MIDI music playback functionality for any .NET applications without complicated dependencies. The codebase is lightweight and can be applied to any audio drivers which support streaming audio, such as SFML.Net, Silk.NET, OpenTK, and NAudio.
The entire code is heavily inspired by the following projects:
An example code to synthesize a simple chord:
// Create the synthesizer.
var sampleRate = 44100;
var synthesizer = new Synthesizer("TimGM6mb.sf2", sampleRate);
// Play some notes (middle C, E, G).
synthesizer.NoteOn(0, 60, 100);
synthesizer.NoteOn(0, 64, 100);
synthesizer.NoteOn(0, 67, 100);
// The output buffer (3 seconds).
var left = new float[3 * sampleRate];
var right = new float[3 * sampleRate];
// Render the waveform.
synthesizer.Render(left, right);
Another example code to synthesize a MIDI file:
// Create the synthesizer.
var sampleRate = 44100;
var synthesizer = new Synthesizer("TimGM6mb.sf2", sampleRate);
// Read the MIDI file.
var midiFile = new MidiFile("flourish.mid");
var sequencer = new MidiFileSequencer(synthesizer);
sequencer.Play(midiFile, false);
// The output buffer.
var left = new float[(int)(sampleRate * midiFile.Length.TotalSeconds)];
var right = new float[(int)(sampleRate * midiFile.Length.TotalSeconds)];
// Render the waveform.
sequencer.Render(left, right);
The NuGet package is available:
Install-Package MeltySynth
All the classes are in the MeltySynth namespace:
using MeltySynth;
If you don't like DLLs, copy all the .cs files to your project.
MeltySynth can only generate PCM waveforms; MeltySynth itself does not have the ability to play sound from speakers. To make the sound audible, export the generated waveform as an audio file (e.g., WAV file) or pass it to some audio driver (e.g., NAudio). If you are not very familiar with how to handle PCM audio, NAudio's tutorials should be helpful.
Note that MeltySynth does not provide thread safety. If you want to send notes and render the waveform in separate threads, you must ensure that the related methods will not be called simultaneously.
https://www.youtube.com/watch?v=xNgsIJKxPkI
https://www.youtube.com/watch?v=_j1izHgIT4U
https://www.youtube.com/watch?v=a8vuIq4JKhs
https://www.youtube.com/watch?v=BiFxvzs0jUI
https://www.youtube.com/watch?v=IUKIEWvw6Ik
To enumerate samples in the SoundFont:
var soundFont = new SoundFont("TimGM6mb.sf2");
foreach (var sample in soundFont.SampleHeaders)
{
Console.WriteLine(sample.Name);
}
To enumerate instruments in the SoundFont:
var soundFont = new SoundFont("TimGM6mb.sf2");
foreach (var instrument in soundFont.Instruments)
{
Console.WriteLine(instrument.Name);
}
To enumerate presets in the SoundFont:
var soundFont = new SoundFont("TimGM6mb.sf2");
foreach (var preset in soundFont.Presets)
{
var bankNumber = preset.BankNumber.ToString("000");
var patchNumber = preset.PatchNumber.ToString("000");
Console.WriteLine($"{bankNumber}:{patchNumber} {preset.Name}");
}
To change the instrument to play, send a program change command (0xC0) to the synthesizer:
// Create the synthesizer.
var sampleRate = 44100;
var synthesizer = new Synthesizer("TimGM6mb.sf2", sampleRate);
// Change the instrument to electric guitar (#30).
synthesizer.ProcessMidiMessage(0, 0xC0, 30, 0);
// Play some notes (middle C, E, G).
synthesizer.NoteOn(0, 60, 100);
synthesizer.NoteOn(0, 64, 100);
synthesizer.NoteOn(0, 67, 100);
// The output buffer (3 seconds).
var left = new float[3 * sampleRate];
var right = new float[3 * sampleRate];
// Render the waveform.
synthesizer.Render(left, right);
To play a melody, render the sound as a sequence of short blocks:
// Create the synthesizer.
var sampleRate = 44100;
var synthesizer = new Synthesizer("TimGM6mb.sf2", sampleRate);
// The length of a block is 0.1 sec.
var blockSize = sampleRate / 10;
// The entire output is 3 sec.
var blockCount = 30;
// Define the melody.
// A single row indicates the start timing, end timing, and pitch.
var data = new int[][]
{
new int[] { 5, 10, 60 },
new int[] { 10, 15, 64 },
new int[] { 15, 25, 67 }
};
// The output buffer.
var left = new float[blockSize * blockCount];
var right = new float[blockSize * blockCount];
for (var t = 0; t < blockCount; t++)
{
// Process the melody.
foreach (var row in data)
{
if (t == row[0]) synthesizer.NoteOn(0, row[2], 100);
if (t == row[1]) synthesizer.NoteOff(0, row[2]);
}
// Render the block.
var blockLeft = left.AsSpan(blockSize * t, blockSize);
var blockRight = right.AsSpan(blockSize * t, blockSize);
synthesizer.Render(blockLeft, blockRight);
}
To change the playback speed:
// Create the synthesizer.
var sampleRate = 44100;
var synthesizer = new Synthesizer("TimGM6mb.sf2", sampleRate);
// Read the MIDI file.
var midiFile = new MidiFile(@"C:\Windows\Media\flourish.mid");
var sequencer = new MidiFileSequencer(synthesizer);
// Play the MIDI file.
sequencer.Play(midiFile, false);
// Change the playback speed.
sequencer.Speed = 1.5F;
// The output buffer.
var left = new float[(int)(sampleRate * midiFile.Length.TotalSeconds / sequencer.Speed)];
var right = new float[(int)(sampleRate * midiFile.Length.TotalSeconds / sequencer.Speed)];
// Render the waveform.
sequencer.Render(left, right);
To mute a certain track:
// Create the synthesizer.
var sampleRate = 44100;
var synthesizer = new Synthesizer("TimGM6mb.sf2", sampleRate);
// Read the MIDI file.
var midiFile = new MidiFile(@"C:\Windows\Media\flourish.mid");
var sequencer = new MidiFileSequencer(synthesizer);
// Discard MIDI messages if its channel is the percussion channel.
sequencer.OnSendMessage = (synthesizer, channel, command, data1, data2) =>
{
if (channel == 9)
{
return;
}
synthesizer.ProcessMidiMessage(channel, command, data1, data2);
};
// Play the MIDI file.
sequencer.Play(midiFile, false);
// The output buffer.
var left = new float[(int)(sampleRate * midiFile.Length.TotalSeconds)];
var right = new float[(int)(sampleRate * midiFile.Length.TotalSeconds)];
// Render the waveform.
sequencer.Render(left, right);
To change the instruments used in the MIDI file:
// Create the synthesizer.
var sampleRate = 44100;
var synthesizer = new Synthesizer("TimGM6mb.sf2", sampleRate);
// Read the MIDI file.
var midiFile = new MidiFile(@"C:\Windows\Media\flourish.mid");
var sequencer = new MidiFileSequencer(synthesizer);
// Turn all the instruments into electric guitars.
sequencer.OnSendMessage = (synthesizer, channel, command, data1, data2) =>
{
if (command == 0xC0)
{
data1 = 30;
}
synthesizer.ProcessMidiMessage(channel, command, data1, data2);
};
// Play the MIDI file.
sequencer.Play(midiFile, false);
// The output buffer.
var left = new float[(int)(sampleRate * midiFile.Length.TotalSeconds)];
var right = new float[(int)(sampleRate * midiFile.Length.TotalSeconds)];
// Render the waveform.
sequencer.Render(left, right);
MeltySynth is available under .
SoundFont® Technical Specification
http://www.synthfont.com/SFSPEC21.PDF
Polyphone Soundfont Editor
Some of the test cases were generated with Polyphone.
https://www.polyphone-soundfonts.com/
Freeverb by Jezar at Dreampoint
The implementation of the reverb effect is based on Freeverb.
https://music.columbia.edu/pipermail/music-dsp/2001-October/045433.html
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 was computed. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 was computed. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 netstandard2.1 is compatible. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
Showing the top 3 NuGet packages that depend on MeltySynth:
| Package | Downloads |
|---|---|
|
Spice86
Reverse engineer and rewrite real mode dos programs |
|
|
Spice86.Core
Reverse engineer and rewrite real mode dos programs |
|
|
Gondwana.Audio.Midi
MIDI audio playback support for the Gondwana Game Engine, including integration for loading and playing MIDI files through the engine's audio system. |
Showing the top 5 popular GitHub repositories that depend on MeltySynth:
| Repository | Stars |
|---|---|
|
OpenRakis/Spice86
Reverse engineer and rewrite real mode DOS programs!
|
|
|
sinshu/managed-doom
A Doom port written in C#
|
|
|
hankmorgan/UnderworldGodot
Engine recreation for Ultima Underworld and Ultima Underworld 2 using the Godot Engine
|
|
|
ImAxel0/Openthesia
Customizable midi visualization software kinda like Synthesia for Windows (Wine-compatible on Linux)
|
|
|
MeltyPlayer/MeltyTool
Multitool for viewing/extracting assets from various N64/GCN/3DS/PC games en-masse.
|
| Version | Downloads | Last Updated |
|---|---|---|
| 2.4.1 | 49,593 | 5/12/2023 |
| 2.4.0 | 1,321 | 10/29/2022 |
| 2.3.0 | 856 | 8/24/2022 |
| 2.2.3 | 931 | 6/3/2022 |
| 2.2.2 | 1,194 | 5/6/2022 |
| 2.2.1 | 918 | 4/15/2022 |
| 2.2.0 | 949 | 1/7/2022 |
| 2.1.0 | 928 | 9/30/2021 |
| 2.0.0 | 866 | 8/4/2021 |
| 2.0.0-alpha | 653 | 8/4/2021 |
| 1.1.3 | 851 | 6/18/2021 |
| 1.1.2 | 837 | 6/5/2021 |
| 1.1.1 | 787 | 6/4/2021 |
| 1.1.0 | 853 | 5/16/2021 |
| 1.0.3 | 724 | 5/3/2021 |
| 1.0.2 | 771 | 4/29/2021 |
| 1.0.1 | 762 | 4/29/2021 |
| 1.0.0 | 754 | 4/29/2021 |
| 0.9.1 | 725 | 4/25/2021 |
| 0.9.0 | 1,037 | 4/24/2021 |