{"id":17245500,"url":"https://github.com/bobbicodes/mecca-piano","last_synced_at":"2025-03-26T05:09:07.301Z","repository":{"id":101319753,"uuid":"219082836","full_name":"bobbicodes/mecca-piano","owner":"bobbicodes","description":"Horizontally scrolling \"piano grid\" style music editor","archived":false,"fork":false,"pushed_at":"2023-12-20T09:43:05.000Z","size":34569,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-31T06:42:43.109Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","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/bobbicodes.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}},"created_at":"2019-11-02T00:32:10.000Z","updated_at":"2023-12-20T08:21:56.000Z","dependencies_parsed_at":null,"dependency_job_id":"88a780c2-f34d-46fe-aeeb-dd5ec56c4b6e","html_url":"https://github.com/bobbicodes/mecca-piano","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/bobbicodes%2Fmecca-piano","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bobbicodes%2Fmecca-piano/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bobbicodes%2Fmecca-piano/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bobbicodes%2Fmecca-piano/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bobbicodes","download_url":"https://codeload.github.com/bobbicodes/mecca-piano/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245591625,"owners_count":20640692,"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-10-15T06:29:44.742Z","updated_at":"2025-03-26T05:09:07.280Z","avatar_url":"https://github.com/bobbicodes.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MECCA Music Platform\n\nThe Music Education, Composition, Creation Application\n\nMECCA is a sample-based music editor inspired by Mario Paint written in Clojurescript and re-frame.\n\nIt was originally meant to be a chiptune tracker that would simply emulate the 4 channels of the NES. But then I started playing around with alternative interfaces and while working on an SVG music notation rendering engine I realized that my priorities were definitely out of whack, and what my program really needed was a jumping Mario and animal noises.\n\nI found that the specific subset of musical features used in the Mario Paint music maker provides a delightful scope of creative possibilities while remaining very approachable. And by using distinctively styled note heads that play samples of a common length, a whole set of elements to implement goes away, like rests, stems, beams, and the need for multiple staves for each voice.\n\nCheck out the inspiring paper [Mario Paint: An Accessible Environment of Musical Creativity\nand Sound Exploration](docs/Mario_Paint_An_Accessible_Environment_of.pdf).\n\n[Live app in its current state](https://porkostomus.github.io/mecca/)\n\n![Screenshot](mecca.png)\n\nI ended up getting a bit carried away with the pixel art, after trying every SVG tool I could find I was still unsatisfied with the results, so ended up coding it all by hand as basic lines, shapes and paths. For example, the castle in the picture above is actually a function that outputs staggered rows of dashed lines representing bricks and mortar organized in a [stretcher bond](https://en.wikipedia.org/wiki/Brickwork#Stretcher,_or_running_bond) masonry pattern. And that Mario is not even a sprite - he's a group of vector paths connected to form his limbs, hat and [moustache](https://laughingsquid.com/origin-of-marios-mustache-and-his-name/). And once this app blows up and I get sued by Nintendo, a new version will be out with a character called *Mr. Moustache*, who will in fact be nothing more than a bouncing moustache on a stick with a red hat on.\n\nThe EDN code representing your music data is output below Data-Robot. It's a sequence of Clojure maps, one for each note. Copy and paste into your favorite text editor to save your composition. Actual save function coming soon.\n\n## Progress\n\nImplemented [Undodog](https://www.mariowiki.com/Undodog) and Redo-Rabbit. The second one I made up. Actually I think it's supposed to be a frog but that's neither a pun nor alliterative so whatevs. It was a highly emotional fight between Redo-Robot, Redo-Wombat and Redo-'rangutan for the position, but the frog thing won out due to ~~me not having to design another button~~ seniority.\n\nAdded a sharp button, expanding it to all 12 chromatic tones. Editor scrolls mostly right. Animation... not so much. While it might be reasonable to place visual elements at a lower priority than the app's audio scheduling system, they are closely related since both deal with coordination of time and reaction to events.\n\nCurrently working on MusicXML import feature. That means I had to actually use proper midi-numbers which broke the Mario Ghost House theme and Zelda Overworld sample songs. Which will be fine once I'm done because then we'll be able to import any number of songs.\n\nI'm able to parse a score into proper note data, the current challenge is to provide effective import options for instrument selection for the various parts, or some sort of reliable strategy for assigning voices. This is very exciting because I can already sense the hilarity that is to ensue from the ability to hear a piece of music with such ridiculous sounds. Random animal noises, anyone? And it's going to be a long, fun-filled path of finding endless edge cases.\n\n## Future ideas\n\nIt would be cool to be able to record, link or upload your own samples. However, when [Koji Kondo](https://en.wikipedia.org/wiki/Koji_Kondo) said that composing for the SNES is 1000 times harder than composing for the NES, he was warning us about the *choose-a-phone* problem. Being sample based, the SNES can play any sound you throw at it, while the NES only plays one set of built-in sounds. See, once you have no idea what instrument you are composing for, all bets are off. The nature of art is defined at least in part by the limitations of the medium. \n\nAs [Rich Hickey said](https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/DesignCompositionPerformance.md), \"no one wants to compose for a choose-a-phone ensemble\".\n\nSee the paper, [Game Scoring: Towards a Broader Theory](/docs/game-scoring.pdf) for a fantastic treatment of the specific musical inventions that came about through creatively overcoming the technological limitations historically involved in the development of game music.\n\nSo how can we expand the sonic pallet without turning it into a choose-a-phone?\n\nThis question goes right to the heart of a creative platform's design philosophy, and mine is something like (to put it in one line): \"to subtly encourage the use of effective idioms while maintaining maximal expressivity.\"\n\nOne idea is to make an 8-bit / 16-bit switch that will transform the whole UI respectively from synth oscillator to sample mode.\n\nFor the synths, I believe that by using the very efficient algorithms from Blargg's [blip-buf](https://github.com/nesbox/blip-buf) library, a full emulation can be done in the browser quite easily. Since the [NES APU](https://wiki.nesdev.com/w/index.php/APU) produces sound via a [sample/hold](https://en.wikipedia.org/wiki/Sample_and_hold) circuit, it is only necessary to generate the ends of the waveforms (the transitions) since the middle part is the same regardless of frequency, differing only in length.\n\n* Noise channel produces pseudo-random bits by [linear feedback shift register](https://en.wikipedia.org/wiki/Linear-feedback_shift_register) method. This is then played back at 16 possible sample rates to produce hihats, snares and other percussive sounds. A much shorter bit sequence is also possible, which produces a metallic tone.\n\n* The triangle channel (for bass and kick drums) is actually a 16 step quantized triangle-ish wave with a slight shark fin shape that also has tiny sawteeth on it. Gotta get this stuff right. That's what gives the Nintendo basslines those really sweet whirling harmonic overtones.\n\n* The 2 pulse-wave channels offer a variable duty cycle, so the standard Web Audio square wave will also not do here. However, we do have the option of using a wavetable, which can produce an arbitrary periodic waveform defined by a list of sin/cosine terms for the Fourier coefficients, which can be easily derived for any sound by playing it through the FFT provided by the analyzer node.\n\n* Linear-interpolated bandlimiting will be good enough, since we have the ability to use the hardware clock exposed by the Web Audio API to oversample at an extremely high rate, supressing aliasing far below perceptible limits.\n\nAlso very exciting is the possibility of an SVG pixel art / animation studio. Like the way it was in Mario Paint but more better because stuff like custom color pallets, upload your own coloring books, etc.\n\nWhen I'm personally building a song with this, the biggest feature that I wish I could reach for is a kind of pattern looping system which would facilitate and encourage working with smaller sections to be composed via a \"song\" track, which could be as simple as `A B A B` or something. I'm going to look back to the tracker paradigm for inspiration here.\n\nThis is the perfect job for Data-Robot, who is currently just sitting there waiting to be put to use. His job is to be concerned with the loading and saving of song data, which can be further divided into:\n\n* *Pattern data* - content to be looped, whether at the \"beat\" level i.e. drum/bass patterns, or the \"song\" level (verse/chorus).\n\n* *Song data* - A \"conductor\" track listing the order of repetitions of the various loops, and\n\n* *File data* - Load/save of entire song.\n\nThen again, if I were to refine the editor scrolling experience by, for example, adding buttons to \"page forward/back\", or notational constructs for creating inline loops, working with the entire score at once might not feel so cumbersome.\n\n## Start local development server:\n\nI use [Figwheel Main](https://github.com/bhauman/figwheel-main) with the [Clojure CLI tools](https://clojure.org/reference/deps_and_cli). Audio samples are fetched with [core.async](https://github.com/clojure/core.async), and while the app generally follows the [re-frame](https://github.com/Day8/re-frame) pattern, it still does lots of yucky stuff like perform logic in views, side-effecting event handlers, etc. \n\nOh and I'm still working on a proper note scheduling system. It currently just plays the entire song and there's no way to stop or adjust it once you press play...\n\n```\nclojure -A:fig -b dev -r\n```\n\nYou'll need to change the line in `music.cljs` to point to the directory with the samples:\n\n```\n(defn load-samples []\n  (go-loop [result {}\n            sounds (range 1 27)]\n    (if-not (nil? (first sounds))\n      (let [sound (first sounds)\n            decoded-buffer (\u003c! (get-and-decode {:url (str \"/audio/\" sound \".mp3\")\n                                                :sound sound}))]\n        (prn sound)\n        (prn decoded-buffer)\n        (recur (assoc result sound decoded-buffer)\n               (rest sounds)))\n      result)))\n```\n\n## Compile with advanced optimizations:\n\n```\nclj -m figwheel.main -O advanced -bo dev\n```\n\nThanks to [Bruce Hauman](https://github.com/bhauman), [Chris Ford](https://github.com/ctford) and [Dave Yarwood](https://github.com/daveyarwood) for blazing the CLJS Web Audio trail. No way could I have figured this all out myself.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbobbicodes%2Fmecca-piano","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbobbicodes%2Fmecca-piano","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbobbicodes%2Fmecca-piano/lists"}