{"id":19297247,"url":"https://github.com/markc/midicomp","last_synced_at":"2025-05-16T16:14:14.021Z","repository":{"id":1221223,"uuid":"1139693","full_name":"markc/midicomp","owner":"markc","description":"A MIDI Compiler - convert SMF MIDI files to and from plain text","archived":false,"fork":false,"pushed_at":"2024-02-17T19:51:27.000Z","size":60,"stargazers_count":96,"open_issues_count":3,"forks_count":16,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-04-22T08:43:42.319Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/markc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null}},"created_at":"2010-12-05T03:59:42.000Z","updated_at":"2025-03-13T13:11:16.000Z","dependencies_parsed_at":"2025-04-22T08:36:02.203Z","dependency_job_id":"83189ef8-8f93-4bd3-9934-6bacca045647","html_url":"https://github.com/markc/midicomp","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markc%2Fmidicomp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markc%2Fmidicomp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markc%2Fmidicomp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markc%2Fmidicomp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/markc","download_url":"https://codeload.github.com/markc/midicomp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254564073,"owners_count":22092124,"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":[],"created_at":"2024-11-09T23:01:49.270Z","updated_at":"2025-05-16T16:14:13.992Z","avatar_url":"https://github.com/markc.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"# midicomp\n\n##### v0.0.8 20170315 markc@renta.net (AGPL-3.0)\n\nA program to manipulate SMF (Standard MIDI File) files. `midicomp` will\nboth read and write SMF files in 0 or format 1 and also read and write\nits own plain text format. This means a SMF file can be turned into\neasily parseable text, edited with any text editor or filtered through\nany script language, and \"recompiled\" back into a binary SMF file.\n\n* Copyright (C) 2003-2017 Mark Constable \u003cmarkc@renta.net\u003e \n* License: AGPL-3.0 - http://www.gnu.org/licenses/agpl.html\n* Originally based on mf2t/t2fm by Piet van Oostrum\n\n### To Build from Source\n```\ngit clone https://github.com/markc/midicomp\nmkdir midicomp/build\ncd midicomp/build\ncmake ..\nmake\nsudo make install #(optional)\n```\n### Changes\n\n* v0.0.8 20170315 Added unistd.h include to yyread.c\n* v0.0.7 20120724 Added incremental option for time tags [Alexandre Oberlin]\n* v0.0.6 20110727 Compile as a CMake project, remove QMake pro files\n* v0.0.5 20101205 Set up to compile from Qt Creator\n* v0.0.4 20080115 Unknown changes\n* v0.0.2 20070722 Fixed gcc4+ compiler bug and exit warnings\n* v0.0.1 20031129 Initial release, combined mf2t+t2fm, added getopt args\n\n## Usage\n\n    -d  --debug     send any debug output to stderr\n    -v  --verbose   output in columns with notes on\n    -c  --compile   compile ascii input into SMF\n    -n  --note      note on/off value as note|octave\n    -t  --time      use absolute time instead of ticks\n    -fN --fold=N    fold sysex data at N columns\n\nTo translate a SMF file to plain ascii format\n\n    midicomp some.mid                   # to view as plain text\n    midicomp some.mid \u003e some.asc        # to create a text version\n\nTo translate a plain ascii formatted file to SMF\n\n    midicomp -c some.asc some.mid       # input and output filenames\n    midicomp -c some.mid \u003c some.asc     # input from stdin with one arg\n\n    midicomp some.mid | somefilter | midicomp -c some2.mid\n\n## Format of the textfile\n\n    File header:            Mfile \u003cformat\u003e \u003cntrks\u003e \u003cdivision\u003e\n    Start of track:         MTrk\n    End of track:           TrkEnd\n\n    Note On:                On \u003cch\u003e \u003cnote\u003e \u003cvol\u003e\n    Note Off:               Off \u003cch\u003e \u003cnote\u003e \u003cvol\u003e\n    Poly Pressure:          PoPr[PolyPr] \u003cch\u003e \u003cnote\u003e \u003cval\u003e\n    Channel Pressure:       ChPr[ChanPr] \u003cch\u003e \u003cval\u003e\n    Controller parameter:   Par[Param] \u003cch\u003e \u003ccon\u003e \u003cval\u003e\n    Pitch bend:             Pb \u003cch\u003e \u003cval\u003e\n    Program change:         PrCh[ProgCh] \u003cch\u003e \u003cprog\u003e\n    Sysex message:          SysEx \u003chex\u003e\n    Arbutrary midi bytes:   Arb \u003chex\u003e\n\n    Sequence nr:            Seqnr \u003cnum\u003e\n    Key signature:          KeySig \u003cnum\u003e \u003cmanor\u003e\n    Tempo:                  Tempo \u003cnum\u003e\n    Time signature:         TimeSig \u003cnum\u003e/\u003cnum\u003e \u003cnum\u003e \u003cnum\u003e\n    SMPTE event:            SMPTE \u003cnum\u003e \u003cnum\u003e \u003cnum\u003e \u003cnum\u003e \u003cnum\u003e\n\n    Meta text events:       Meta \u003ctexttype\u003e \u003cstring\u003e\n    Meta end of track:      Meta TrkEnd\n    Sequencer specific:     SeqSpec \u003ctype\u003e \u003chex\u003e\n    Misc meta events:       Meta \u003ctype\u003e \u003chex\u003e\n\n### The \u003c\u003e have the following meaning\n\n    \u003cch\u003e                    ch=\u003cnum\u003e\n    \u003cnote\u003e                  n=\u003cnoteval\u003e  [note=\u003cnoteval\u003e]\n    \u003cvol\u003e                   v=\u003cnum\u003e [vol=\u003cnum\u003e]\n    \u003cval\u003e                   v=\u003cnum\u003e [val=\u003cnum\u003e]\n    \u003ccon\u003e                   c=\u003cnum\u003e [con=\u003cnum\u003e]\n    \u003cprog\u003e                  p=\u003cnum\u003e [prog=\u003cnum\u003e]\n    \u003cmanor\u003e                 minor or major\n    \u003cnoteval\u003e               either a \u003cnum\u003e or A-G optionally followed by #,\n                            followed by \u003cnum\u003e without intermediate spaces.\n    \u003ctexttype\u003e              Text Copyright SeqName TrkName InstrName Lyric Marker Cue\n    \u003ctype\u003e                  a hex number of the form 0xab\n    \u003chex\u003e                   a sequence of 2-digit hex numbers (without 0x)\n                            separated by space\n    \u003cstring\u003e                a string between double quotes (like \"text\").\n\n## Misc notes\n\nChannel numbers are 1-based, all other numbers are as they appear in the\nmidifile.\n\n`\u003cdivision\u003e` is either a positive number (giving the time resolution in\nclicks per quarter note) or a negative number followed by a positive\nnumber (giving SMPTE timing).\n\n`\u003cformat\u003e \u003cntrks\u003e \u003cnum\u003e` are decimal numbers.\n\nThe `\u003cnum\u003e` in the Pb is the real value (two midibytes combined)\n\nIn Tempo it is a long (32 bits) value. Others are in the interval 0-127\n\nThe SysEx sequence contains the leading F0 and the trailing F7.\n\nIn a string certain characters are escaped:\n\n\" and \\ are escaped with a \\\na zero byte is written as \\0\nCR and LF are written as \\r and \\n respectively\nother non-printable characters are written as `\\x\u003c2 hex digits\u003e`\nWhen -f is given long strings and long hex sequences are folded by inserting\n`\\\u003cnewline\u003e\u003ctab\u003e`. If in a string the next character would be a space or\ntab it will be escaped by \\\n\nmidicomp will accept all formats that mf2t can produce, plus a number of\nothers. Input is case insensitive (except in strings) and extra tabs and\nspaces are allowed. Newlines are required but empty lines are allowed.\nComment starts with # at the beginning of a lexical item and continues\nto the end of the line. The only other places where a # is legal are\ninsides strings and as a sharp symbol in a symbolic note.\n\nIn symbolic notes + and # are allowed for sharp, b and - for flat.\n\nIn bar:beat:click time the : may also be /\n\nOn input a string may also contain \\t for a tab, and in a folded\nstring any whitespace at the beginning of a continuation line is skipped.\n\nHex sequences may be input without intervening spaces if each byte is\ngiven as exactly 2 hex digits.\n\nHex sequences may be given where a string is required and vice versa.\n\nHex numbers of the form 0xaaa and decimal numbers are equivalent.\nAlso allowed as numbers are \"bank numbers\" of the form '123. In fact\nthis is equivalent to the octal number 012 (subtract 1 from each\ndigit, digits 1-8 allowed). The letters a-h may also be used for 1-8.\n\nThe input is checked for correctness but not extensively. An\nerrormessage will generally imply that the resulting midifile is illegal.\n\nchannel number can be recognized by the regular expression `/ch=/`.\nnote numbers by `/n=/` or `/note=/`, program numbers by `/p=/` or `/prog=/`.\nMeta events by `/^Meta/` or `/^SeqSpec/`.\nText events by `/\"/`, continued lines by `/\\\\$/`, continuation lines by `/$\\t/`\n(that was a TAB character).\n\n## Examples\n\nTo convert a huge number of MID files try some variation of this command...\n\n    find /path/to/MIDIs -type f -name '*.mid' | while read i; do midicomp $i \u003e ${i}_output.txt; done\n\n---\n\nIn awk each parameter is a field, in perl you can use split to get the\nparameters (except for strings).\n\nThe following perl script changes note off messages to note on with\nvol=0, deletes controller 3 changes, makes some note reassignments on\nchannel 10, and changes the channel numbers from channel 1 depending\non the track number.\n\n    ------------------------------- test.pl -------------------------------\n    %drum = (62, 36, 63, 47, 65, 61, 67, 40, 68, 54);\n\n    while (\u003c\u003e) {\n        next if /c=3/;\n        s/Off(.*)v=[0-9]*/On\\1v=0/;\n        if (/ch=10/ \u0026\u0026 /n=([0-9]*)/ \u0026\u0026 $drum{$1}) {\n            s/n=$1/\"n=\".$drum{$1}/e;\n        }\n        if (/^MTrk/) {++$trknr ; print \"track $trknr\\n\";}\n        if ($trknr \u003e 2) { s/ch=1\\b/ch=3/; }\n        else  { s/ch=1\\b/ch=4/; }\n        print || die \"Error: $!\\n\";\n    }\n    ------------------------------------------------------------------------\n\nand this is the corresponding awk script.\n\n    ------------------------------- test.awk -------------------------------\n    BEGIN { drum[62] = 36; drum[63] = 47; drum[65] = 61; \\\n        drum[67] = 40; drum[68] = 54 }\n    /c=3/ { next }\n    ($2 == \"Off\") { $2 = \"On\"; $5 = \"v=0\" }\n    /ch=10/ { n = substr($4, 3); if (n in drum) $4 = \"n=\" drum[n] }\n    /^MTrk/ { trknr++ }\n    /ch=1 / { if (trknr \u003e 2) { $3 = \"ch=2\" } else { $3 = \"ch=3\" } }\n    { print }\n    ------------------------------------------------------------------------\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkc%2Fmidicomp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarkc%2Fmidicomp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkc%2Fmidicomp/lists"}