The balafon is a gourd-resonated xylophone, a type of struck idiophone. It is closely associated with the neighbouring Mandé, Senoufo and Gur peoples of West Africa, particularly the Guinean branch of the Mandinka ethnic group, but is now found across West Africa from Guinea to Mali. Its common name, balafon, is likely a European coinage combining its Mandinka name ߓߟߊ bala with the word ߝߐ߲ fôn 'to speak' or the Greek root phono.
Balafon - From Wikipedia, the free encyclopedia
balafon is a multitrack MIDI sequencer language and interpreter. It consists of a live shell, player and a linter.
To install the balafon
command from source, go
and rtmidi
are required.
Not tested on platforms other than Linux.
go install github.com/mgnsk/balafon/cmd/balafon@latest
- The default command lists the available MIDI ports. The default port is the 0 port.
balafon
0: Midi Through:Midi Through Port-0 14:0
1: Hydrogen:Hydrogen Midi-In 135:0
2: VMPK Input:in 128:0
- Play a file through a specific port. The port name must contain the passed in flag value:
balafon play --port "VMPK" examples/bach.bal
- Port can also be specified by its number:
balafon play --port 2 examples/bonham.bal
- Enter live mode:
balafon live --port hydro examples/live_drumset.bal
Live mode is an unbuffered input mode in the shell. Whenever an assigned key is pressed, a note on message is sent to the port.
- Help.
$ balafon --help
balafon is a MIDI control language and interpreter.
Usage:
[flags]
[command]
Available Commands:
completion Generate the autocompletion script for the specified shell
fmt Format a file
help Help about any command
lint Lint a file
live Load a file and continue in a live shell
play Play a file
smf Convert a file to SMF2
Flags:
-h, --help help for this command
Use " [command] --help" for more information about a command.
The language consists of commands and note lists.
Only block comments are supported for now.
/* This is a block comment. */
/*
This is a multi line block comment.
*/
Commands begin with a :
.
// Assign a note.
:assign c 60
// Start message.
:start
// Stop message.
:stop
// Key signature change on the current channel.
:Key Cmaj
// Set time signature.
:time 4 4
// Set tempo.
:tempo 120
// Set channel.
:channel 10
// Set voice.
:voice 1
// Set velocity.
:velocity 127
// Program change message on the current channel.
:program 0
// Control change message on the current channel.
:control 1 127
Assign a MIDI note number to a note letter.
// Kick drum (on the drum channel).
:assign k 36
// Middle C (on other channels).
:assign c 60
Notes are written as a letter symbol (must be assigned first) plus properties. The available properties are
- sharp (
#
) - flat (
$
) - staccato (
`
) shorten note by 50% - accent (
>
) +5 velocity - marcato (
^
) +10 velocity - ghost (
)
) -5 velocity - dot (
.
) - numeric note value (
1
,2
,4
,8
and so on) - tuplet (
/3
) (only triplet/3
or quintuplet/5
) - let ring (
*
)
// Whole note.
x1
// Half note.
x2
// Quarter note (same as x4).
x
// 8th note.
x8
// 16th note.
x16
// 32th note.
x32
// And so on...
// A quarter rest.
-
// An 8th rest.
-8
// Dotted quarter note.
x.
// Double-dotted note.
x..
// Triple-dotted note.
x...
// Dotted 8th note.
x8.
// Quarter triplet note.
x/3
// Dotted 8th quintuplet note.
x8./5
// A note.
c
// A sharp note (MIDI note number + 1).
c#
// A flat note (MIDI note number - 1).
c$
Notes can be arbitrarily grouped and properties applied to multiple notes at once.
// Ti-Tiri.
x8 x16 x16
// Can be written as:
x8[xx]16
// Three 8th triplet notes.
[xxx]8/3
// Expands to
x8/3 x8/3 x8/3
// Nested groups are also supported:
[[fcg] [fcg]#]8
// Expands to
f8 c8 g8 f#8 c#8 g#8
When used on note groups, these properties are added to the notes' already existing properties:
- staccato (
`
) - accent (
>
) - marcato (
^
) - ghost (
)
) - dot (
.
)
When used on note groups, these properties override the notes' existing properties of the same type:
- sharp (
#
) - flat (
$
) - numeric note value (
1
,2
,4
,8
and so on) - tuplet (
/3
) (only triplet/3
or quintuplet/5
) - let ring (
*
)
The sharp and flat properties are mutually exclusive and may appear only once per note.
Bars are used to specify multiple tracks playing at once.
Only time
, velocity
, channel
and voice
commands are scoped to the bar.
Other commands, when used inside a bar, have global effect when the bar is played back.
The bar is executed with the play
command.
// Define a bar.
:bar RockBeat
// Setting `time` makes the interpreter validate the bar length.
// Incomplete bars are filled with silence.
:time 4 4
[xx xx xx xx]8
// Using braces for nice alignment.
[k s k s]
:end
// You can also write the same bar as:
:bar SameBeat
[xxxxxxxx]8
ksks
:end
// Play the bar.
:play RockBeat
vim.api.nvim_create_autocmd({ "BufNewFile", "BufRead" }, {
pattern = "*.bal",
callback = function()
vim.bo.filetype = "balafon"
end,
})
vim.g.neomake_balafon_lint_maker = {
exe = "balafon",
args = "lint",
errorformat = "%f:%l:%c: error: %m",
}
vim.g.neomake_balafon_enabled_makers = { "lint" }
Example configuration for lazy.nvim:
{
"mgnsk/tree-sitter-balafon",
dependencies = {
"nvim-treesitter/nvim-treesitter",
},
build = function(plugin)
local parser_config = require("nvim-treesitter.parsers").get_parser_configs()
parser_config["balafon"] = {
install_info = {
url = plugin.dir,
files = { "src/parser.c" },
generate_requires_npm = true,
requires_generate_from_grammar = false,
},
filetype = "bal",
}
vim.cmd("TSUpdateSync balafon")
end
},
To play into the default port, run
balafon play examples/bonham.bal
To play into the default port, run
balafon play examples/bach.bal
To play into the default port, run
balafon play examples/bach.bal
- Tie (a curved line connecting the heads of two notes of the same pitch) - no idea about the syntax. Can be partially emulated by using dotted notes if the rhythm is simple enough.
- WebAssembly support with Web MIDI for running in browsers.
- Accelerando/Ritardando.