Haematite
Haematite is port of MeltySynth by Sinshu to Crystal. It is a library that provides MIDI music playback using SoundFonts for Crystal projects with almost no dependencies. It is similar to my CL-MeltySynth library for Common Lisp, except that it's written in pure Crystal, and is more advanced.
Information about releases can be found in the wiki.
Wanna support me? Buy me a coffee on Ko-Fi, or support me through Liberapay.
Example videos
These were played using midi123, a command-line MIDI player that uses Haematite.
- Warcraft 2's "Human 1" by Glenn Stafford (midi123 v2.2.0)
- Rise of The Triad's "How'd I Do?" by Lee Jackson (midi123 v2.2.0)
- Virtua Racing's title theme, by Takenobu Mitsuyoshi, Naofumi Hataya, and Tomoko Sasaki (midi123 v2.2.0)
- The Secret of Monkey Island's intro theme by Michael Land and Patrick Mundy (midi123 v2.2.0)
- Sonic the Hedgehog's Green Hill Zone by Masato Nakamura (midi123 v2.0.0)
- Sonic the Hedgehog's Spring Yard Zone by Masato Nakamura (midi123 v2.0.0)
- Rise of The Triad's "Smoke and Mirros" by Lee Jackson (midi123 v2.0.0)
- Mega Man 2's Airman stage music by Takashi Tateishi (midi123 v2.0.0)
Features
- Wave synthesis and Sound
- [x] 64-bit internal audio engine
- [x] High quality interpolation
- [x] Loads SoundFont files
- [x] Waveform and Envelope generators
- [x] Multiple lowpass filter choices for the voices
- [x] Vibrato and Modulation LFOs
- MIDI processing
- [x] Note on/off
- [x] Bank/patch selection with optional remapping (remaps unknown presets to bank 0/128)
- [x] Modulation
- [x] Volume control and Panning
- [x] Expression
- [x] Hold pedal
- [x] Pitch bend
- [x] Tuning
- [x] NRPN support
- [x] Support for MIDI controllers 71 and 74
- Effects
- [x] Multiple reverb choices
- [x] Chorus effect inspired by an 80s synth with model number ending in "-60"
- [x] Stereo enhancer effect
- [x] Reverb, Chorus, and Stereo Enhancer can all be enabled/disabled individually
- [x] Filters on the voices can be changed to non-standard models
- [x] Filters on the channels are selectable
- Other things
- [x] Standard MIDI file support
- [x] RIFF-based MIDI file support (RMI, only the MIDI data is loaded)
- [x] MUS format support
- [x] Loop extension support
- [x] Performance optimizations
How do I get set up?
Add this to your shard.yml
:
dependencies:
haematite:
fossil: https://chiselapp.com/user/MistressRemilia/repository/Haematite
This has mostly been tested with Crystal 1.4.x and 1.5.0. You will need Fossil installed to clone this repo and the dependency. If you use Crystal versions before 1.5.0, you will need to build the latest version of Shards by hand to get Fossil support.
Usage
There is an included program, simple-player
, that acts as an example of how to
use the library together with CrSFML, as
well as how to dump rendered audio to a WAV file. Study that to see how to use
it in a non-trivial way.
The important parts are:
# The SynthesizerSettings class is used to hold the setup parameters.
settings = Haematite::SynthesizerSettings.new(sampleRate: 44100)
# Create a Synthesizer using the settings, and a path to a SoundFont.
synth = Haematite::Synthesizer.new("/path/to/soundfont.sf2", settings)
# Create a MidiFileSequencer for the synth.
seq = Haematite::Sequencer.new(synth)
# Create a Slice to render into.
batch = Slice(Float64).new(2 * (0.05 * 44100).round.to_i32!, 0.0)
# Start playing a MIDI file. The False is to disable looping.
seq.play("/path/to/midi.mid", false)
# Repeatedly render to batch within a loop of some sort. The rendering methods
# will return false when looping is disabled and the MIDI has finished playing.
while seq.render(block)
# batch now holds a block of rendered audio
# Maybe write it to a WAV or an audio device?
end
Example Programs
examples/dump-sf2.cr
: Dumps samples from a SoundFont as WAVs.examples/crsfml-player
: A basic player using CrSFML for the backend.
Development
Running Tests
You will need to place the following SoundFonts into the specs
directory with these exact filenames:
- TimGM6mb (already included in this repo, copy to
specs
asTimGM6mb.sf2
) - Arachno SoundFont v1.0 (
Arachno SoundFont - Version 1.0.sf2
) - The GeneralUser GS MuseScore SoundFont v1.442 (
GeneralUser GS MuseScore v1.442.sf2
) - Shan's GM SoundFont v2.01 (
SGM-V2.01.sf2
)
Style info
I use a somewhat non-standard style for my code.
- Keep lines 118 characters or shorter. Obviously sometimes you can't, but please try. Use 80 or 115 characters for Markdown files, though.
- Please use pascalCase for variable and method names. Use CamelCase for type names. Use UPPER_SNAKE_CASE for constants.
- Put parentheses around method parameters, except for these methods:
puts
,pp
,p
,raise
,sleep
,spawn
,loop
, andexit
. - Always the full
do |foo|...end
syntax with blocks, except when it's all on one line or an anonymous function, then use { and } or the normaldo |foo|...end
. - The type name for exceptions end with Error. For example,
ExternalProgramError
.
How do I contribute?
- Go to https://chiselapp.com/user/MistressRemilia/repository/Haematite/ and clone the Fossil repository.
- Create a new branch for your feature.
- Push locally to the new branch.
- Create a bundle with Fossil that contains your changes.
- Get in contact with me.
Contributors
- Remilia Scarlet - creator and maintainer
- Homepage: https://alexa.partition36.com/
- Mastodon: @MistressRemilia@mastodon.sdf.org
- Email: zremiliaz@postzeoz.jpz My real address does not contain Z's
Links and Licenses
- MeltySynth by Sinshu (MIT License)
- CL-MeltySynth by Remilia Scarlet (AGPLv3 License)
- midi123 by Remilia Scarlet (AGPLv3 License, full command-line MIDI player using CL-MeltySynth)
- TimGM6mb.sf2 by Tim Brechbill (GPLv2 License)
- Zita-Rev1 by Fons Adriaensen (GPLv3 License)
- YK Chorus by Spotlightkid (GPLv2 License)
Haematite itself is mostly under the GNU Affero General Public License version 3, except for the port of Zita-Rev1, which is under the GNU General Public License version 3, and the port of YK Chorus, which is under the GNU General Public License version 2