{"id":13595741,"url":"https://github.com/flipcoder/textbeat","last_synced_at":"2025-04-09T13:33:15.528Z","repository":{"id":43496337,"uuid":"134027732","full_name":"flipcoder/textbeat","owner":"flipcoder","description":"🎹 plaintext music sequencer and midi shell, with vim playback and the powers of music theory  🥁","archived":false,"fork":false,"pushed_at":"2023-03-24T22:44:56.000Z","size":439,"stargazers_count":407,"open_issues_count":1,"forks_count":13,"subscribers_count":16,"default_branch":"master","last_synced_at":"2024-11-06T18:45:46.305Z","etag":null,"topics":["command-line","composition","drum-machine","linux-audio","markup-language","midi","midi-sequencer","midi-tracker","music-composition","music-notation","music-sequencer","music-theory","music-tracker","notation","plaintext","repl","sequencer","shell","vim","vim-plugin"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/flipcoder.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}},"created_at":"2018-05-19T03:57:06.000Z","updated_at":"2024-11-01T19:06:31.000Z","dependencies_parsed_at":"2024-01-14T11:00:52.120Z","dependency_job_id":"ebb67b0b-85ef-4ea7-a2cc-814e274bc221","html_url":"https://github.com/flipcoder/textbeat","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flipcoder%2Ftextbeat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flipcoder%2Ftextbeat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flipcoder%2Ftextbeat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flipcoder%2Ftextbeat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flipcoder","download_url":"https://codeload.github.com/flipcoder/textbeat/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248049639,"owners_count":21039253,"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":["command-line","composition","drum-machine","linux-audio","markup-language","midi","midi-sequencer","midi-tracker","music-composition","music-notation","music-sequencer","music-theory","music-tracker","notation","plaintext","repl","sequencer","shell","vim","vim-plugin"],"created_at":"2024-08-01T16:01:56.781Z","updated_at":"2025-04-09T13:33:15.158Z","avatar_url":"https://github.com/flipcoder.png","language":"Python","readme":"# textbeat\n\nPlaintext music sequencer and interactive shell.\n\nWrite music in vim or your favorite text editor.\n\nOpen-source under MIT License (see LICENSE file for information)\n\n![Screenshot](https://i.imgur.com/HmzNhXf.png)\n\nCopyright (c) 2018 Grady O'Connell\n\n- [Project Board](https://trello.com/b/S8AsJaaA/textbeat)\n- Vim integration: [vim-textbeat](https://github.com/flipcoder/vim-textbeat)\n\n**This project is still very new.  Despite number of features, you may quickly\nrun into issues, especially with editor integration.**\n\n# Overview\n\nCompose music in a plaintext format or type music directly in the shell.\nThe format is vertical and column-based, similar to early music trackers,\nbut with syntax inspired by jazz/music theory.\n\n# Features\n\nTextbeat is still in development, but you can already do lots of cool things:\n\n- Strumming\n- Arpeggiation\n- Tuplets and polyrhythms\n- MIDI CC automation\n- Vibrato, pitch, and mod wheel control\n- Dynamics\n- Accents\n- Velocity\n- Inversions\n- Midi channel stacking\n- Note length\n- Delays\n- Scales and modes by name\n- Markers, repeats, callstack\n\n# Setup\n\n## Linux\n\n```\ngit clone https://github.com/flipcoder/textbeat\ncd textbeat\nsudo python setup.py install\ntextbeat\n```\n\n## Windows\n\n```\ngit clone https://github.com/flipcoder/textbeat\ncd textbeat\npip3 install -r requirements.txt\n./txbt.cmd\n```\n\n## Test it out!\n\nOnce you're in textbeat, try this:\n\n```\nmaj\u0026\n```\n\nIf you don't hear 3 notes, you need to set up midi (this is the case with Linux).\n\n## How to set up midi\n\nYou can use the shell with General Midi out-of-the-box on windows, which is great for learning,\nbut sounds bad without a decent soundfont.\n\nIf you want to use VST instruments, you'll need to route the MIDI out to something that hosts them, like a DAW.\n(I'm currently working on headless VST rack generation.)\n\nFor windows, you can use a virtual midi driver, such as [loopMIDI](http://www.tobias-erichsen.de/software/loopmidi.html) for usage with a VST host or DAW.\n\nIf you're on Linux, you can use soundfonts through qsynth or use a software instrument like helm or dexed.  I recommend qsynth.\n\nVSTs should work here as well but you need to pick a host.\n\nIf you feed the MIDI into a DAW you'll be able to record the output through the DAW itself.\n\nI'm currently looking into export options and recording via a headless host.\n\n# Tutorial\n\nIf you're familiar with trackers, you may pick this up quite easily.\n\nFirst start by creating a .txbt (textbeat) file, inside the file music \nflows vertically, with separate columns that are separated by whitespace or\nmanually setting a column width.\n\nEach column represents a track, which defaults to separate midi channel numbers.\nTracks play sequences of notes.  You'll usually play at least 1 track per instrument.\nThis doesn't mean you're limited to just one note per track though,\nyou can keep notes held down and play chords as you wish.\n\nEach cell row in a track can contain both note data and associated effects.\n\nBy default, any note event in a track will mute previous notes on that track\n\nThe following will play the C major scale using numbered notation:\n```\n; Major Scale -- this is a comment, write whatever you want here!\n\n; 120bpm subdivided into 2 (i.e., eighth notes)\n\n%t120 x2\n\n1\n2\n3\n4\n5\n6\n7\n1'\n```\n\nThe tempo is in BPM, and the grid is based in subdivisions.\nMusicians can think of grid as fractions of quarter note,\nThe grid is the beat/quarter-note subdivision.\n\nBoth Tempo and Grid can be decimal numbers as well.\nFor example, if you made some chords and you only want \none chord to be played per bar (eg 4 beats) \nyou could set `%t120x0.25`.\n\nYou can listen to what you've made by running:\n\n```\ntextbeat \u003cyour file\u003e\n```\n\nConsult the output of `textbeat -h` for further information.\n\n## Note Numbers\n\nBoth note numbers and letters are supported.\nThis tutorial will use 1,2,3,4,5,6,7 instead of C,D,E,F,G,A,B.\nI'm a fan of thinking about notes without implying a key.\nFor this reason, textbeat prefers the relative/transposed note numbers\nover arbitrary note names.\nIf you're writing a song in D minor, you may choose to set the global or track key\nto D, making D note 1. (You could also set D to 6 if you're thinking modally)\nIf this is confusing or not beneficial to you: don't worry, it's optional!\n\nIn this format, flats and sharps are prefixed instead of suffixed (b7 (\"flat 7\") instead of Bb (\"B flat\")).\n\nBe aware that this flexibility introduces a few limits with chord names:\n- B7 chords should not be written as 'b7', because this means flat 7\n- 7 is a note when used alone, not a chord:\n    - Write it as dom7\n    - Alternatively write 1:7, R7, or C7\n- 27 is not a 7 chord on 2, it's note 27\n    - Write it as 2:7 or 2dom7\n\n## Transposing Octaves\n\nIn the first example, the apostrophe character (') was used to play the note in the next octave.\nFor an octave below, use a comma (,).\n\nRepeat these for additional octaves (,,, for 3 down, '' for 2 up, etc).\n\nTo make octave changes persist, use a number for the octave count instead of repeating (,2).\n\n## Holding Muting\n\nNotes will continue playing automatically, until they're muted or another note is played in the same track.\n\nYou can mute all notes in a track with -\n\nTo control releasing of notes, use dash (-).\n```\n\n; hold note 1 until next note\n1\n \n \n \n\n; auto-mute by specifying note value (*):\n1*\n \n \n \n \n; manually mute with '-'\n1\n \n \n-\n\n```\n\nNote durations can be manually controlled by adding * to increase value by powers of two, \nYou can also add a fractional value to multiply this.  These types of fraction\nvalues are used throughout textbeat.\nThe opposite of this is the dot (.) which halves note values\n\n\n```\n; set note based on percentage (this means 30%)\n1*3\n\n; set note based on percentage (33%)\n1*33\n\n; set note based on percentage (33.3%)\n1*333\n\n; etc...\n```\n\nNow with dots for staccato:\n\n```\n1.\n\n1..\n\n1.30\n```\n\nNotes that are played in the same track as other notes mute the previous notes.\nIn order to override this, hold a note by suffixing it with underscore (_).\n\nA (-) character will then mute them all.\n\n```\n; Let's hold some notes\n1_\n3_\n5_\n7_\n-\n```\n\nIf you want to hold a series of notes like a sustain pedal, simply use two underscores (__)\nand all future notes will be held until a mute is received.\n\n## Chords\n\nUnlike traditional trackers, you can write chords directly: 1maj or Cmaj.\n1 ('C') is not required here. as chords without note names are positioned on 1\n('C') (ex. \"maj\" = \"Cmaj\" = \"1maj\").\nOther shorthand names that work: \"ma\", \"major\", \"M\", or roman numeral \"I\"\n\nLet's play a scale with some chords:\n\n```\n%t120 g2\n1maj\n2m\n3m\n4maj\n5maj\n6m\n7dim\n1maj'\n```\n\nThere are lots of chords and voicings (check def/ files) and I'll be adding a lot more.\nAll scales and modes are usable as chords, so arpeggiation and strumming is usable with those as well.\n\nRemember: The note goes *before* the chord, so 7maj is a maj chord on note 7 (i.e. Bmaj), NOT a maj7.\n\n## Arpeggios and Strumming\n\nChords can be walked if they are suffixed by '\u0026'\nBe sure to rest in your song long enough to hear it cycle.\n\n```\nmaj\u0026\n \n \n \n```\n\nAfter the \u0026, you can put a number to denote the number of cycles.\nBy default, it cycles infinitely until muted (or until the song ends)\n\nThe dollar sign is similar, but walks an entire set of notes within a single grid space:\n```\nmaj$\n```\nScales and modes are also accessible the same way:\n\n```\ndorian$\n```\n\nTo strum, use the hold (_) symbol with this.\n\n```\nmaj$_\n```\n\n## Velocity and Accents\n\nUse a ! or ? to accent or soften a note respectively.\n\nYou can use these on arpeggios as well.\n\n```\n1!\n2?\n3\n4?\n1!\n2?\n3\n4?\n```\n\nUse values after accent to set a specific velocity:\n\n```\n1!!    # 100%\n1!90\n2!75\n3!5    # 50%\n4!333  # 33.3%\n5!05   # 5%\n```\n\n## Note grouping\n\nFor readability, notes can be indented to imply downbeat or grouping\n\n```\n1\n 2\n 3\n 4\n1\n 2\n 3\n 4\n```\n\n## Volume\n\nUsually you'll want to control velocity through accenting('!') or softening('?')\nor using values (!30 for 30%)\n\nIf you wish to control volume/gain directly, use @v\n \n```\n1maj@v9\n-\n1maj@v6\n-\n1maj@v4\n-\n1maj@v2\n-\n```\n\nUnlike accents, volume changes persist.\n\nInterpolation is not yet implemented\n\n## Vibrato, Pitch, and Mod Wheel\n\nTo add vibrato to a note, suffix it with a tilda (~).\n\nVibrato uses the mod wheel right now, but will eventually use pitch wheel oscillation.\n\nIn the future, articulation will be programmable, per-track or per-song.\n\n## Arpeggio Modulation\n\nNotes of arpeggios can be modified as they're running,\nby having effects in the grid space they occur, for example:\n\n```\nmaj7\u0026\n .?\n .?\n .?\n!\n .?\n .?\n .?\n```\n\nmaj7\u0026 starts a repeating 4-note arpeggio, and we indent to show this.\n\nCertain notes of the sequence are modulated with short/staccato '.', soft '?', and accent '!'\n\nFor staccato usage w/o a note name, an extra dot is required since '.' is simply a placeholder.\n\n## Tracks\n\nColumns are separate tracks, line them up for more than one instrument.\n\nThe dots are placeholders.\n\n```\n1,2  1\n.    4\n.    5\n.    1'\n.    4'\n.    5'\n.    1''\n```\n\nColumns can be detected (in some cases), but you'll probably want to \nspecify the column width manually at the top,\nwhich allows vim to mark the columns.\n\n```\n# sets column width to 8\n%c=8\n```\n\nFor best view in an editor, it is recommended that you offset the first column by -2:\n\n```\n# sets column width to 8, offset -2\n%c=8,-2\n```\n\n## Patches\n\nAnother useful global var is 'p', which sets midi patches by name or number\nacross the tracks.  The midi names support both patch numbers and partial case-insensitive\nmatches of GM instruments.\n\n```\n%t120 x2 p=piano,guitar,bass,drums c8,-2\n```\n\nFor a full list of GM names, see [def/gm.yaml](https://github.com/flipcoder/textbeat/blob/master/textbeat/def/gm.yaml).\n\n## Tuplets\n\nThe 'T' (tuplet) gives us access to the musical concept of tuplets (called triplets in cases of 3).\nwhich allows note timing and durations to fall along a ratio instead of the usual note subdivisions.\n\nTuplets are marked by 'T' and have an optional value at the first occurrence in that group.\nRatios provided will control expansion.  Default is 3:4.\nIf no denominator is given, it will default to the next power of two\n(so 3:4, 5:8, 7:8, 11:16).\nSo in other words, T5 is the same as T5:8, but if you need a 5:6, you'll need to write T5:6.\nThe ratio of the tuplet persists for the rest of the grouping.\nFor nested tripets, group those by adding an extra 'T'.\n\nThe two tracks below are a basic usage of triplets:\n\n```\n1     1T\n2     2T\n3     3T\n4\n1     1T\n2     2T\n3     3T\n4\n```\n\nThe first column is playing notes along the grid normally, while the\n2nd column is playing 3 notes in the space of the others' 4 notes.\n\nEven though there is visual spacing between the triplet groups, the 'T' value effective\nstretches the notes so they occur along a slower grid according to that ratio.\n\nThe spaces that occur after (and between) tuplet groupings should remain empty,\nsince they are spacers to make the expansion line up.\n\n## Picking\n\n[Currently designing this feature](https://trello.com/c/D01rlTWp/26-picking)\n\n## Key changes\n\n```\n# change key (this will change the key of the current scale to 3 (E))\n%k=3\n\n# to set a relative key, this will go from a major scale to relative minor scale\n%k+6\n\n# you can also go downwards\n%k-6\n\n# scale names are supported, this changes the scale shape to dorian\n%s=dorian\n\n# you can also use mode numbers\n%s=2\n```\n\n## Chords (Advanced)\n\nIn textbeat, slash (/) chords do not imply inversions,\nbut are for spanning chord voicings across octaves.  Additionally, note names alone do no imply chords.\nFor example, C/E means play a C note with an E in a lower octave, whereas a musician might\ninterpret this as a specific chord voicing.  Inversions in textbeat uses shift operator (\u003e) instead (maj\u003e for maj first inversion))\n\n```\nb7maj7#4/sus2/1\n# same thing with note names: Bbmaj7#4/Csus2/C\n# suffix this with \u0026 to hear the notes walked individually\n```\n\nThe above chord voicing spans 3 octaves and contains 9 notes.\nIt is a Bbmaj7 chord w/ an added #4 (relative to Bb, which is E), followed by a lower octave Csus2.\nThen at the bottom, there is a C bass note.\n\n## Examples\n\nCheck out the examples/ folder.  Play them with textbeat from the\ncommand line:\n\n```\n./txbt examples/jazz.txbt\n``` \n\n# Advanced\n\n## Markers / Repeats\n\nHere are the marker/repeat commands:\n\n```\n- |: set marker\n- |name: set marker 'name'\n- :| goes back to last marker, or start\n- :name| goes back to last marker 'name'\n- :N| goes back to last marker N number of times\n- :name*N| goes back to last marker 'name' N number of times\n- || return/pop to last position after marker jump\n- ||| end the song here\n``` \n\n## Command line parameters (use -):\n\n```\n- (default) starts midi shell\n- (filename): plays file\n- c: play a given sequence\n    - Passing \"1 2 3 4 5\" would play those note one after another\n- l: play a single line from the file\n    - Not too useful yet, since it doesn't parse context\n- +: play range, comma-separated (+start,end)\n    - Line numbers and marker names work\n- t: tempo\n- x: grid\n- n: note value\n- c: columns\n    - specify width and optional shift, instead of using auto-detect\n    - positive shift values create a \"gutter\" to the left\n    - negative values eat into the size of the first column\n- p: set midi patches\n    - command-separated list of patches across tracks\n    - GM instruments names fuzzy match (Example: Piano,Organ,Flute)\n- --sharps: Prefer sharps\n- --solfege: Use solfege in output (input not yet supported)\n- --flats: Prefer flats (currently default)\n- --device=DEVICE: Set midi-device (partial match supported)\n```\n\n## Global commands:\n\n```\n- %: set var (ex. %P=piano T=120x2 S=dorian)\n    - K: set key/transpose\n        - Both absolute and relative values supported\n        - Relative values are 1-indexed using numbered note name\n            - whole step: %k+2 whole step\n            - half step: %k+#1 or %k+b2\n            - invalid example (because of 1-index): %k+1\n    - O: set global octave\n    - R: set scale (relative)\n        - Names and numbers supported\n    - S: set scale (parallel)\n        - Names and numbers supported\n    - P: set patch(s) across channels (comma-separated)\n        - Matches GM midi names\n        - Supports midi patch numbers\n        - General MIDI name matching\n- ;: comment\n- ;;: cell comment (not yet impl)\n\nTo do relative values, drop the equals sign:\n%k-2\n```\n\n## Track commands\n\n```\n- ': play in octave above\n    - repeat for each additional octave (''')\n    - for octave shift to persist, use a number instead of repeats ('3)\n- ,: play in octave below\n    - number provided for octave count, default 1 (,,,)\n    - for octave shift to persist, use a number instead of repeats (,3)\n- \u003e: inversion (repeatable)\n    - future: will be moved from track commands to chord parser\n- \u003c: lower inversion (repeatable)\n    - future: will be moved from track commands to chord parser\n- ~: vibrato and pitch wheel\n- `: mod wheel\n- \": repeat last cell (ignoring dots, blanks, mutes, modified repeats don't repeat)\n- *: set note length\n    - defaults to one beat when used (default is hold until mute)\n    - repeating symbol doubles note length\n    - add a number for multiply percentage (*50)\n- .: half note length\n    - halfs note value with each dot\n    - add extra dot for using w/o note event (i.e. during arpeggiator), since lone dots dont mean anything\n    - add a number to do multiplies (i.e. C.2)\n- !: accent a note (or set velocity)\n    - set velocity by provided percentage\n    - !! for louder notes\n    - !! for louder accent\n    - !! w/ number set future velocity\n- ?: play note quietly (or set velocity)\n    - repeat or pass value for quieter notes\n- T: tuplet: triplets by default, provide ratio A:B for subdivisions\n- ): delay: set note delay\n- \\: bend: (not yet implemented)\n- \u0026: arpeggio: plays the given chord in a sequence\n    - infinite sequence unless number given\n    - more params coming soon\n- $: strum\n    - plays the chord in a sequence, held by default\n    - notes automatically fit into 1 grid beat\n- `: mod\n- ch: assign track to a midi channel\n    - midi channels exceeding max value will be spanned across outputs\n- p: program assign\n    - Set program to a given number\n    - Global var (%) p is usually preferred for string matching\n- c: control change (midi CC param)\n    - setting CC5 to 25 would be c5:25\n- q: play recording\n- Q: record\n- midi cc mappings\n    - bs: bank select (not impl)\n    - at: aftertouch\n    - bc: breath controller\n    - fc: foot controller\n    - pt: portamento time\n    - v: volume\n    - bl: balance\n    - pn: pan\n    - e: expression\n    - ga: general purpose CC 16\n    - gb: \" 17\n    - gc: \" 18\n    - gd: \" 19\n    - sp: sustain pedal\n    - ps: portamento switch\n    - st: sostenuto pedal\n    - sf: soft pedal\n    - lg: legato pedal\n    - hd: hold w/ release fade\n    - o: oscillator\n    - R: resonance\n    - r: release\n    - a: attack\n    - f: filter\n    - sa: sound ctrl\n    - sb: \" 2\n    - sc: \" 3\n    - sd: \" 4\n    - se: \" 5\n    - pa: portmento amount\n    - rv: reverb\n    - tr: tremolo\n    - cr: chorus\n    - ph: phaser\n    - mo: mono\n\nTrack commands that start with letters should be separated\nfrom notedata by prefixing '@':\nExample: 1~ is fine, but 1v is not. Use 1@v You only need one to combine: 1@v5e5\n\nNote: Fractional values specified are formatted like numbers after a decimal point:\nExample: 3, 30, and 300 all mean 30% (read like .3, .30, etc.)\n\nCC mapping is customizable inside [def/cc.yaml](https://github.com/flipcoder/textbeat/blob/master/textbeat/def/default.yaml).\n\n```\n\n## Scales, Modes, Chords, Voicings\n\n```\n# note: some of these features are not finished\n\n- \u003c or \u003e: inversion suffix\n    - ex: maj\u003e means maj 1st inversion\n    - repeatable (ex. maj\u003e\u003e means 2nd inversion: 5 1' 3' or G C' E')\n        - or specify a number (like maj\u003e2), meaning 2nd inversion (this will be useful for scale modes later)\n- /: slash: layer chords across octaves (note: different from music theory interpretation)\n    - repeat slash for multiple octaves (ex. maj//1)\n- add (suffix), add note to chord (ex. maj7add11)\n- no (suffix): remove a note by number\n- |: stack: combines chords/notes manually (ex. maj|sus|#11)\n```\n\n## Defs\n\nA majority of the music index is contained in inside these files:\n\n- Default: [def/default.yaml](https://github.com/flipcoder/textbeat/blob/master/textbeatdef/default.yaml).\n- Informal: [def/informal.yaml](https://github.com/flipcoder/textbeat/blob/master/textbeat/def/informal.yaml).\n- Experimental: [def/exp.yaml](https://github.com/flipcoder/textbeat/blob/master/textbeat/def/exp.yaml).\n\nThese lists does not include certain chord modifications (add, no, drop, etc.).\n\n# Plugins\n\nYou may notice there are some incomplete module/plugin systems for integration \nwith different sound outputs and instruments hosts.\nThese plugins are not yet functional.\n\n# What else?\n\nI'm improving this faster than I'm documenting it.  Because of that, not everything is explained.\n\nCheck out the project board for more information on current/upcoming features.\n\nAlso, check out the basic examples in the examples/ and tests/ folder.\n\n# What's the plan?\n\nNot everything is listed here because I just started this project.\nMore to come soon!\n\nThings I'm planning on adding soon:\n\n```\n- Improved chord interpretation\n- MIDI input/output\n- MIDI stabilization\n- Headless VST rack integration\n- Csound and supercollider instrument integration\n- libGME for classic chiptune\n- Text-to-speech and singing (Espeak/Festival)\n```\n\nFeatures I'm adding eventually:\n\n```\n- Recording and encoding output of a project\n- Midi controller input and recording\n- Midi input chord analysis\n- MPE support for temperament and dynamic tonality\n```\n\nI'll be making use of python's multiprocessing or\nseparate processes to achieve as much as I can do for timing critical stuff\nwithout doing a C++ rewrite.\n\n# Can I Help?\n\nYes!  Contact [flipcoder](https://github.com/flipcoder).\n\n","funding_links":[],"categories":["Music","Python","Music Sequencing"],"sub_categories":["Markup"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflipcoder%2Ftextbeat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflipcoder%2Ftextbeat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflipcoder%2Ftextbeat/lists"}