{"id":25815740,"url":"https://github.com/mgnsk/balafon","last_synced_at":"2025-07-14T08:09:55.151Z","repository":{"id":46630282,"uuid":"410662324","full_name":"mgnsk/balafon","owner":"mgnsk","description":"balafon is a multitrack MIDI sequencer language and interpreter.","archived":false,"fork":false,"pushed_at":"2024-11-24T15:42:05.000Z","size":1045,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-02T17:53:09.269Z","etag":null,"topics":["bnf","drum-machine","drums","go","golang","interpreter","midi","multichannel","percussion","piano","rtmidi","sequencer","smf"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mgnsk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-09-26T21:04:38.000Z","updated_at":"2024-11-24T15:41:02.000Z","dependencies_parsed_at":"2025-02-28T04:43:33.643Z","dependency_job_id":"b1bc5aa0-e70f-4a96-a729-5d45d526f2aa","html_url":"https://github.com/mgnsk/balafon","commit_stats":null,"previous_names":["mgnsk/gong"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/mgnsk/balafon","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgnsk%2Fbalafon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgnsk%2Fbalafon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgnsk%2Fbalafon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgnsk%2Fbalafon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mgnsk","download_url":"https://codeload.github.com/mgnsk/balafon/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgnsk%2Fbalafon/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265262552,"owners_count":23736411,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bnf","drum-machine","drums","go","golang","interpreter","midi","multichannel","percussion","piano","rtmidi","sequencer","smf"],"created_at":"2025-02-28T04:32:51.556Z","updated_at":"2025-07-14T08:09:55.093Z","avatar_url":"https://github.com/mgnsk.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Balafon\n\n\u003e 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.\n\u003e\n\u003e [Balafon](https://en.wikipedia.org/wiki/Balafon) - From Wikipedia, the free encyclopedia\n\n## Introduction\n\nbalafon is a multitrack MIDI sequencer language and interpreter. It consists of a live shell, player and a linter.\n\n## Install\n\nTo install the `balafon` command from source, `go` and `rtmidi` are required.\nNot tested on platforms other than Linux.\n\n```sh\ngo install github.com/mgnsk/balafon/cmd/balafon@latest\n```\n\n## Running\n\n- The default command lists the available MIDI ports. The default port is the 0 port.\n\n```sh\nbalafon\n0: Midi Through:Midi Through Port-0 14:0\n1: Hydrogen:Hydrogen Midi-In 135:0\n2: VMPK Input:in 128:0\n```\n\n- Play a file through a specific port. The port name must contain the passed in flag value:\n\n```sh\nbalafon play --port \"VMPK\" examples/bach.bal\n```\n\n- Port can also be specified by its number:\n\n```sh\nbalafon play --port 2 examples/bonham.bal\n```\n\n- Enter live mode:\n\n```sh\nbalafon live --port hydro examples/live_drumset.bal\n```\n\nLive mode is an unbuffered input mode in the shell. Whenever an assigned key is pressed,\na note on message is sent to the port.\n\n- Help.\n\n```sh\n$ balafon --help\nbalafon is a MIDI control language and interpreter.\n\nUsage:\n   [flags]\n   [command]\n\nAvailable Commands:\n  completion  Generate the autocompletion script for the specified shell\n  fmt         Format a file\n  help        Help about any command\n  lint        Lint a file\n  live        Load a file and continue in a live shell\n  play        Play a file\n  smf         Convert a file to SMF2\n\nFlags:\n  -h, --help   help for this command\n\nUse \" [command] --help\" for more information about a command.\n```\n\n## Syntax\n\nThe language consists of commands and note lists.\n\n### Comments\n\nOnly block comments are supported for now.\n\n```\n/* This is a block comment. */\n\n/*\nThis is a multi line block comment.\n*/\n```\n\n### Commands\n\nCommands begin with a `:`.\n\n```\n// Assign a note.\n:assign c 60\n\n// Start message.\n:start\n\n// Stop message.\n:stop\n\n// Key signature change on the current channel.\n:Key Cmaj\n\n// Set time signature.\n:time 4 4\n\n// Set tempo.\n:tempo 120\n\n// Set channel.\n:channel 10\n\n// Set voice.\n:voice 1\n\n// Set velocity.\n:velocity 127\n\n// Program change message on the current channel.\n:program 0\n\n// Control change message on the current channel.\n:control 1 127\n```\n\n### Note assignment\n\nAssign a MIDI note number to a note letter.\n\n```\n// Kick drum (on the drum channel).\n:assign k 36\n// Middle C (on other channels).\n:assign c 60\n```\n\n### Notes\n\nNotes are written as a letter symbol (must be assigned first) plus properties.\nThe available properties are\n\n- sharp (`#`)\n- flat (`$`)\n- staccato (`` ` ``) shorten note by 50%\n- accent (`\u003e`) +5 velocity\n- marcato (`^`) +10 velocity\n- ghost (`)`) -5 velocity\n- dot (`.`)\n- numeric note value (`1`, `2`, `4`, `8` and so on)\n- tuplet (`/3`) (only triplet `/3` or quintuplet `/5`)\n- let ring (`*`)\n\n### Note values\n\n```\n// Whole note.\nx1\n// Half note.\nx2\n// Quarter note (same as x4).\nx\n// 8th note.\nx8\n// 16th note.\nx16\n// 32th note.\nx32\n// And so on...\n```\n\n### Rests\n\n```\n// A quarter rest.\n-\n// An 8th rest.\n-8\n```\n\n### Dotted notes and tuplets\n\n```\n// Dotted quarter note.\nx.\n// Double-dotted note.\nx..\n// Triple-dotted note.\nx...\n// Dotted 8th note.\nx8.\n// Quarter triplet note.\nx/3\n// Dotted 8th quintuplet note.\nx8./5\n```\n\n### Flat and sharp notes\n\n```\n// A note.\nc\n// A sharp note (MIDI note number + 1).\nc#\n// A flat note (MIDI note number - 1).\nc$\n```\n\n### Note grouping\n\nNotes can be arbitrarily grouped and properties applied to multiple notes at once.\n\n```\n// Ti-Tiri.\nx8 x16 x16\n// Can be written as:\nx8[xx]16\n\n// Three 8th triplet notes.\n[xxx]8/3\n// Expands to\nx8/3 x8/3 x8/3\n\n// Nested groups are also supported:\n[[fcg] [fcg]#]8\n// Expands to\nf8 c8 g8 f#8 c#8 g#8\n```\n\n### Additive properties\n\nWhen used on note groups, these properties are added to the notes' already existing properties:\n\n- staccato (`` ` ``)\n- accent (`\u003e`)\n- marcato (`^`)\n- ghost (`)`)\n- dot (`.`)\n\n### Unique properties\n\nWhen used on note groups, these properties override the notes' existing properties of the same type:\n\n- sharp (`#`)\n- flat (`$`)\n- numeric note value (`1`, `2`, `4`, `8` and so on)\n- tuplet (`/3`) (only triplet `/3` or quintuplet `/5`)\n- let ring (`*`)\n\nThe sharp and flat properties are mutually exclusive and may appear only once per note.\n\n### Bars\n\nBars are used to specify multiple tracks playing at once.\nOnly `time`, `velocity`, `channel` and `voice` commands are scoped to the bar.\nOther commands, when used inside a bar, have global effect when the bar is played back.\nThe bar is executed with the `play` command.\n\n```\n// Define a bar.\n:bar RockBeat\n// Setting `time` makes the interpreter validate the bar length.\n// Incomplete bars are filled with silence.\n:time 4 4\n  [xx xx xx xx]8\n  // Using braces for nice alignment.\n  [k  s  k  s]\n:end\n\n// You can also write the same bar as:\n:bar SameBeat\n  [xxxxxxxx]8\n  ksks\n:end\n\n// Play the bar.\n:play RockBeat\n```\n\n## Neovim configuration\n\n### Filetype detection:\n\n```lua\nvim.api.nvim_create_autocmd({ \"BufNewFile\", \"BufRead\" }, {\n    pattern = \"*.bal\",\n    callback = function()\n        vim.bo.filetype = \"balafon\"\n    end,\n})\n```\n\n### Neomake\n\n```lua\nvim.g.neomake_balafon_lint_maker = {\n    exe = \"balafon\",\n    args = \"lint\",\n    errorformat = \"%f:%l:%c: error: %m\",\n}\n\nvim.g.neomake_balafon_enabled_makers = { \"lint\" }\n```\n\n### Treesitter\n\nExample configuration for lazy.nvim:\n\n```lua\n{\n    \"mgnsk/tree-sitter-balafon\",\n    dependencies = {\n        \"nvim-treesitter/nvim-treesitter\",\n    },\n    ft = \"balafon\",\n    build = function(plugin)\n        local parser_config = require(\"nvim-treesitter.parsers\").get_parser_configs()\n\n        parser_config[\"balafon\"] = {\n            install_info = {\n                url = plugin.dir,\n                files = { \"src/parser.c\" },\n                generate_requires_npm = true,\n                requires_generate_from_grammar = false,\n            },\n            filetype = \"bal\",\n        }\n\n        vim.cmd(\"TSUpdateSync balafon\")\n    end,\n},\n```\n\n## Examples\n\n### The Bonham Half Time Shuffle\n\n[examples/bonham.bal](examples/bonham.bal)\n\nTo play into the default port, run\n\n```sh\nbalafon play examples/bonham.bal\n```\n\n### J.S. Bach - Musikalisches Opfer - 6. Canon A 2 Per Tonos\n\n[examples/bach.bal](examples/bach.bal)\n\nTo play into the default port, run\n\n```sh\nbalafon play examples/bach.bal\n```\n\n### Multichannel\n\n[examples/multichannel.bal](examples/multichannel.bal)\n\nTo play into the default port, run\n\n```sh\nbalafon play examples/bach.bal\n```\n\n## Possible features in the future\n\n- 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.\n- WebAssembly support with Web MIDI for running in browsers.\n- Accelerando/Ritardando.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmgnsk%2Fbalafon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmgnsk%2Fbalafon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmgnsk%2Fbalafon/lists"}