{"id":13657984,"url":"https://github.com/ddj231/Handel","last_synced_at":"2025-04-24T08:30:59.735Z","repository":{"id":54831686,"uuid":"325683743","full_name":"ddj231/Handel","owner":"ddj231","description":"a procedural programming language for writting songs in browser","archived":false,"fork":false,"pushed_at":"2025-04-09T01:50:51.000Z","size":14976,"stargazers_count":212,"open_issues_count":0,"forks_count":7,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-14T05:38:02.267Z","etag":null,"topics":["handel","music-composition","procedural-programming-language","programming-language","tonejs"],"latest_commit_sha":null,"homepage":"https://handel-pl.github.io","language":"JavaScript","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/ddj231.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"Contributing.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-12-31T01:20:46.000Z","updated_at":"2025-04-09T01:50:54.000Z","dependencies_parsed_at":"2022-08-14T04:10:38.353Z","dependency_job_id":null,"html_url":"https://github.com/ddj231/Handel","commit_stats":null,"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddj231%2FHandel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddj231%2FHandel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddj231%2FHandel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddj231%2FHandel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ddj231","download_url":"https://codeload.github.com/ddj231/Handel/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250591935,"owners_count":21455466,"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":["handel","music-composition","procedural-programming-language","programming-language","tonejs"],"created_at":"2024-08-02T05:00:54.781Z","updated_at":"2025-04-24T08:30:59.721Z","avatar_url":"https://github.com/ddj231.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# Handel\n\nHandel is a procedural programming language for writting songs in browser. \n\nThe Handel Interpreter interprets Handel programs and plays compositions in browser, thanks to [Tone.js](https://tonejs.github.io/).\n\nTry the Handel Web Editor here: [Handel Web Editor](https://ddj231.github.io/Handel-Web-Editor/)\n\nSee the language documentation (including latest features): [Handel Documentation](https://ddj231.github.io/Handel-Documentation/)\n\nJoin the [Handel forum](https://groups.google.com/g/handel-pl) to ask questions and showcase compositions. Also check out the [Contributing](./Contributing.md) guidelines.\n\n*soli deo gloria*\n\n# Installation\n\nAdd the below to your html document: \n```\n\u003cscript src=\"https://unpkg.com/handel-pl\"\u003e\u003c/script\u003e\n```\n\nYou're all set!\n\n**Alternatively** \n\nInstall Handel with the following: \n\n```\nnpm i handel-pl\n```\n\nAnd import Handel with the following:\n\n```\nimport * as Handel from 'handel-pl';\n```\n\n\n# Usage\n\n## Example Handel Snippet\n\n```\nstart\n    chunk example \n        play E3, C3, G3 for 2b\n    endchunk\n    run example with sound piano, loop for 5 \nfinish\n```\n\nSee the Examples folder [here](./Examples/) for example Handel programs and inspiration.\n\n## Example Using Handel In Browser\n\n```\nfunction clicked(){\n    Handel.RunHandel(`\n        start\n            chunk example using somePlayable \n                play somePlayable \n                rest for 1b\n            endchunk\n            save myPlayable = Eb3 for 1b\n            run example using myPlayable with sound piano, loop for 5 \n        finish\n    `)\n}\ndocument.addEventListener(\"click\", clicked);\n```\n\nNote that you pass the Handel code into the **RunHandel** function ```Handel.RunHandel(someHandelCode)```.\n\nTo compile to midi, pass a config object to the RunHandel function with **outputMidi** set to true. \n\n```\nconst config = {outputMidi: true};\nHandel.RunHandel(`start play E4 for 1b finish`, config);\n```\n\nAdditionally, you can use the **StopHandel** function to stop a running Handel program. ```Handel.StopHandel()```\n\n\n# Getting started\n\nHandel programs are contained within the **start** and **finish** keywords. Below is a complete Handel program:\n\n```\nstart\n    play E4 for 1b\nfinish\n```\n\nThe program above only plays 1 note. But it's a start!\n\n\n# Let's play something\n\nYou can be play notes and chords using the play command. Below is an example program that plays a note, then a chord:\n\n```\nstart\n    play C#3 for 1b\n    play E3, G3, A4 for 1b\nfinish\n```\n\nNote the syntax above. A **play** command begins with the **play** keyword, then a note or chord (a list of notes separated by commas) follows.\n\nLastly play commands need a duration. The play commands above end with 'for 1b'. This states how long the particular note or notelist (chord) should be held.  \n\nPhew! We're getting somewhere.\n\n\n# Let's rest\n\nSimilar to the play command, a rest can played using the rest command. Below is an example program that rests for 1 beat then plays a note for 2 beats.\n\n```\nstart\n    rest for 1b\n    play G5 for 2b\nfinish\n```\n\n\n# But are there Variables?\n\ntl;dr\nHere is a code snippet showing variables in Handel \n\n```\nstart\nsave mynotelist = Cb3, D3\nsave myduration = for 1b\nsave myplayable = E4, F4, G3 for 3b\n\nsave myotherplayable = mynotelist for myduration\n\nplay myplayable\nrest myduration\nplay myotherplayable\nfinish\n```\n\nYou can declare Variables in Handel. Variables store three builtin types in Handel: Notelists, Notegroups, Durations, Playables.\n\nA **Digit** is a positive or negative integer.\n\nA **Notelist** is a single note name, or a list of note names separated by commas.\n\nFor example:\n\n```\nBb3\nG#2, A2\n```\n\nA **Notegroup** is a group of notelists (or conceptually an array of notelists). Each notelist is separated by a vertical line.\n\nFor example:\n\n```\nBb3|G#2, A2\n```\n\nA **Duration** is the keyword **for** followed by a beat.\n\nHere are some example durations: \n\n```\nfor 1b\nfor 2b\nfor 16b\nfor 32b\n```\n\nLastly, we've already seen **Playables** above. Playables are a note or notelist (chord) followed by a duration.\nHere are some example playables.\n\n```\nBb3 for 1b\nD#6, E#6, G3 for 1b\n```\n\n*no promises that the above chord sounds pleasing to the ear :p*\n\nFinally variables!\n\nTo store a notelist, playable or a duration use the **save** keyword, followed by a variable name, an equal sign and a notelist, playable, duration (or another variable which stores on of these values).\n\nVariable names must contain only lowercase letters, and no numbers. Variable names must also not be any of the reserved keywords in Handel. eSee the [Reserved Keywords](https://ddj231.github.io/Handel-Documentation/docs/keywords)). \n\nBelow is an example program using variables.\n\n```\nstart\n    save mynote = E2\n    save myplayablenote = mynote for 2b\n    save myrest = for 2b\n\n    play myplayablenote\n    rest myrest\n    play myplayablenote\n    rest myrest\nfinish\n```\n\nWhen saving variables, Handel now also provides expressions for **generating random numbers** and for **evaluating expressions**.\n\nTo generate a random number when setting a variable, use the ```randint``` keyword, followed by a range ```start to end```\n\nTo evaluate an expression use the ```eval``` keyword followed by a mathematical expression (note division is integer division).\n\nHere is an example of the syntax:\n\n```\nsave somerandomdigit = randint -5 to 5\nsave someint = eval 5 * 5 / (1 + 1) % 6\n```\n\nOK! So far so good!\n\n# Variable Reassignment\nHandel now supports variable reassignment. Variables can be reassigned using the ```update``` keyword.\n\nFor example:\n\n```\nsave mynotelist = B3\nupdate mynotelist = Bb3\n```\n\n## Reassignment and Shifting values\n\nAll variables in Handel can be shifted using the ```rshift``` and ```lshift``` keywords. You can think of this as the equivalent of ```+=``` and ```-=``` respectively. \n\nFor variables storing digits, this shifting is exactly the equivalent of addition and subtraction.\n\nFor variables storing notelists and notegroups, shifting changes the notes, left or right by a number of semitones.\n\nThe following example reassigns (or shifts) ```mynotelist`` left by one semitone. Then right by two semitones.\n\n```\nstart\n    save mynotelist = B3 \n\n    update mynotelist lshift 1\n    play mynotelist for 1b\n\n    save somenum = randint 1 to 5\n    update mynotelist rshift somenum \n    play mynotelist for 1b\nfinish\n```\n\nVariables storing **Durations** and **Playables** can also be shifted. \n\nShifting a duration increases or decreases its beat value.\n\nShifting a playable (which contains a notelist) increases or decreass its notelist.\n\nFor example:\n\n```\nstart\n    save duration = for 1b\n    save playable = E3, G3 for 2b\n    \n    update duration rshift 1 \n    update playable lshift 2 \n\n    play playable\n    rest duration\n    play playable\nfinish\n```\n\n# Blocks loops\n\nHandel supports block loops.  Block loops begin with the **block** keyword and end with the **endblock** keyword and a ```loop for digit``` or ```loop while condition``` customization.\n\nHere is an example two block loops in Handel.\n```\nstart\n    block \n        play C3, E3, G3 for 1b \n        play D3, F3, A3 for 1b \n    endblock loop for 2 \n\n    save note = C2\n    block \n        play note for 1b \n        update note rshift 1\n    endblock loop while note lessthan C3\nfinish\n```\n\nBlock loops are blocking (no pun intended), and should not be confused with Handel's procedures (chunks).\n\nMore on procedures below.\n\n# Conditionals (if - else blocks)\nThough booleans are not built in types in Handel, Handel now supports conditonals. ```\u003e \u003c \u003e= \u003c= ==```\n\nThe syntax for an if - else block is as follows.\n\n```\nstart\n    if E4 \u003e Cb3 then\n        play E4 for 1b \n    else\n        play Cb3 for 1b\n    endif\n\n    save mydigit = 5\n    if mydigit == 5 then\n        play C2 for 5b\n    endif\nfinish\n```\n\nThe above plays E4 for 1 beat. Note that else blocks are optional.\n\n# Procedures (I thought this was a procedural programming language?)\n\nProcedures in Handel are called chunks. You can conceptualize a **chunk** as a song track. When ran,\nchunks play at the same time as other run chunks and the global track. Chunks must begin with the **chunk**\nkeyword and end with the **endchunk** keyword.\n\nBelow is an example program with a kick drum and a piano, playing together.\n\n```\nstart\n    chunk backbeat using myplayable\n        play myplayable \n    endchunk\n\n    chunk mykeys \n        play E3, G3, A3 for 1b\n        play G3, A2, C3 for 1b\n        play F3, A3, C3 for 1b\n        play D3, F2, A3 for 1b\n    endchunk\n\n    run mykeys with sound piano, loop for 2\n\n    save myplayable = A1 for 1b\n\n    run backbeat using myplayable with sound kick, loop for 8\nfinish\n```\n\nBoth the 'backbeat' chunk and the 'mykeys' chunk above play together (not one after the other). This\nbehavior allows multitrack songs to be created with Handel. \n\nNote that each chunk has its own scope.\n\n\n# More on procedures (chunks) and their syntax\n\n\n## Procedure declaration (creating chunks) \n\nAs noted above you can create chunks with the **chunk** keyword. The name of the **chunk** (the chunk name) follows the keyword.\n\nThis chunk name must be all lowercase letters, no numbers and cannot be one of Handel's reserved keywords. (See the [Reserved Keywords](https://ddj231.github.io/Handel-Documentation/docs/keywords)). \n\nAfter the chunk name, you can optionally add parameters. A list of comma separated parameters can follow the **using** keyword.\n\nTogether you get the following: `chunk somechunkname using someparam, anotherparam`\n\nAfter the optional parameter list, you can add a body to the chunk. This is a function body (what you would like to happen when the chunk is ran).\n\nLastly the chunk must be ended with the **endchunk** keyword.\n\n\n## Running Procedures \n\nThere are two ways to run a chunk in Handel. \n\nYou can run a chunk using the **run** keyword. This conceptually creates a new song track, and plays the chunk synchronously with all running chunks.\n\nYou can also run a chunk using the **call** keyword. This runs the chunk in place (in the songtrack the chunk is called in).\n\nThe syntax for running a chunk is the **run** or **call** command followed by the name of the chunk. \n\nIf the chunk has parameters, a you must use the ```using`` keyword followed by a matching number of comma separated arguments. \n\nHere is an example running two chunks. One chunk requires arguments the other does not.\n\n```\nstart\n    chunk playtwo using argone, argtwo\n        play argone\n        play argtwo\n    endchunk\n\n    chunk noargs\n        play C4 for 1b\n        call playtwo using E4 for 1b, Cb6 for 1b \n    endchunk\n\n    run noargs with sound piano\nfinish\n```\n\nThe run command is used to run noargs in its own conceptual song track. \n\nWithin (```noargs```), 1 note plays, and the playtwo chunk is called in place.\n\nNote that saved variables (containing any built-in type in Handel), digits, playables, durations, can be used as arguments when running a chunk.\n\nOK! Now to configuring a run of a chunk.\n\n\n## Configuring a run of a chunk\n\nYou can configure a run of chunk by adding the **with** keyword and a comma separated list of customizations to the end of a run command. (customizations cannot be used with the call command as the chunk is being played in place)\n\nThere are three main customizations: **bpm**, **sound**, and **loop**.\n\nYou can use **bpm** keyword to set the bpm of a run of a chunk.\n\nFor example ```bpm 120```\n\nYou can use the **sound** keyword to set the instrument of a run of a chunk.\n\nFor example ```sound piano```\n\nThe current available sounds to choose from are: piano, synth, casio, kick, snare, hihat\n\nYou can use the **loop** keyword to set the amount of times the run of a chunk shoud loop for.\n\nFor example ```loop for 10```\n\nAll together you can configure a run of a chunk as follows:\n\n```\nstart\n    chunk withargs using somechord \n        play somechord \n    endchunk\n\n    run withargs using E3, G3, F3 for 1b with bpm 100, loop for 8, sound piano \nfinish\n```\n\nAbove we've got a chord, played with a piano, looping 8 times, with a bpm of 100!\n\n(see the [Language Features reference](https://ddj231.github.io/Handel-Documentation/docs/language-features) for additional customizations)\n\n## Custom Instruments\nHandel allows custom instruments to be loaded into Handel Programs. Instruments can be created and added to a run of a Handel program as follows.\n\n```\nlet myinst = Handel.MakeInstrument({\n    A1: 'https://tonejs.github.io/audio/casio/A1.mp3', \n    A2: 'https://tonejs.github.io/audio/casio/A2.mp3'\n})\nlet config = {}\nconfig.instruments = {funkyinst: myinst} \nHandel.RunHandel(`\n    start\n        load funkyinst as funky \n        chunk example \n            play E4 for 4b\n        endchunk\n        run example with sound funky\n    finish\n`, config)\n```\n\nThe ```MakeInstrument``` function wraps Tone.js's sampler constructor. It takes a urls object as its argument. This urls object, maps note names matched to their location (locally or not). One or more mappings can be used.\n\nAfter making an instrument above, we add it to our config object and run the Handel program with that config.\n\nWithin the Handel program we load the instrument as follows: ```\nload configInstrumentName as nameOfInstrumentWithinHandel``` \n\n**Note**: this feature makes your Handel program less portable but gives you the freedom of using arbitrary instruments in your Handel program.\n\n# Inspiration\n\n[Sonic Pi](https://sonic-pi.net)\n\n[Tone.js](https://tonejs.github.io)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fddj231%2FHandel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fddj231%2FHandel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fddj231%2FHandel/lists"}