{"action":"created","issue":{"url":"https://api.github.com/repos/audiojs/contributing/issues/18","repository_url":"https://api.github.com/repos/audiojs/contributing","labels_url":"https://api.github.com/repos/audiojs/contributing/issues/18/labels{/name}","comments_url":"https://api.github.com/repos/audiojs/contributing/issues/18/comments","events_url":"https://api.github.com/repos/audiojs/contributing/issues/18/events","html_url":"https://github.com/audiojs/contributing/issues/18","id":173625132,"number":18,"title":"real-time synchronous streams","user":{"login":"ahdinosaur","id":719605,"avatar_url":"https://avatars.githubusercontent.com/u/719605?v=3","gravatar_id":"","url":"https://api.github.com/users/ahdinosaur","html_url":"https://github.com/ahdinosaur","followers_url":"https://api.github.com/users/ahdinosaur/followers","following_url":"https://api.github.com/users/ahdinosaur/following{/other_user}","gists_url":"https://api.github.com/users/ahdinosaur/gists{/gist_id}","starred_url":"https://api.github.com/users/ahdinosaur/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ahdinosaur/subscriptions","organizations_url":"https://api.github.com/users/ahdinosaur/orgs","repos_url":"https://api.github.com/users/ahdinosaur/repos","events_url":"https://api.github.com/users/ahdinosaur/events{/privacy}","received_events_url":"https://api.github.com/users/ahdinosaur/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/audiojs/contributing/labels/discussion","name":"discussion","color":"006b75"}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":34,"created_at":"2016-08-28T02:13:10Z","updated_at":"2016-08-29T11:12:44Z","closed_at":null,"body":"hey @audiojs/core @audiojs/devs, thanks for the invite.\r\n\r\ni'm Mikey. i do audio / visual programming whenever i feel, i host a local meetup called [Art~Hack Wellington](https://www.facebook.com/groups/714447698702058/), @mmckegg and i collaborate in a [`livejs` org](https://github.com/livejs/), i use [ndarray](https://github.com/scijs/ndarray) as a common data structure between these modules to represent [ndsamples](https://github.com/livejs/ndsamples) or [ndpixels](https://github.com/livejs/ndpixels), and (mostly thanks to Matt playing [Loop Drop](http://loopjs.com/)) it turns out like [this](https://www.youtube.com/watch?v=aIxbJkC9M8k), [this](https://www.youtube.com/watch?v=YkC5Tgv3YaM), or [this](https://www.youtube.com/watch?v=mx6WQgfNha4).\r\n\r\nso anyways, why did i make this issue? basically, i like what's happening here, but i have a tiny concern about exporting modules as node streams, because that's what i used to do as well.\r\n\r\nwhy are node streams bad? [a few reasons](http://dominictarr.com/post/145135293917/history-of-streams), most relevant here is that node streams are meant to be asynchronous over many event ticks. this is a problem in my most common use case, where the moment i read a \"frame\" of audio i want to immediately process it and output pixels to the screen (or LEDs). all of this i want to happen synchronously, because the faster the pixels are displayed the better (enough millisecond delay and everyone will notice it's not \"on time\", even if subconsciously). even a single `process.nextTick` along the pipeline is wasted time, [zalgo be damned](http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony), although i can see y'all have worked around this (set highWaterMark to zero, etc).\r\n\r\nwhat do i recommend instead? so in my modules, i've started doing two things: either a) export a simple function, even if it will commonly be used as a stream. examples: [`pixels-apa102`](https://github.com/livejs/pixels-apa102), [`rainbow-pixels`](https://github.com/ahdinosaur/rainbow-pixels), [`ndsamples-frequencies`](https://github.com/ahdinosaur/ndsamples-frequencies), [`ndpixels-convert`](https://github.com/livejs/ndpixels-convert). or b) export a [`pull-stream`](https://pull-stream.github.io/) which by default are unbuffered synchronous streams (and have [many other benefits](http://dominictarr.com/post/149248845122/pull-streams-pull-streams-are-a-very-simple)). examples: [`read-audio`](https://github.com/livejs/read-audio).\r\n\r\nexporting a simple function is nice, because then it's useful for anyone regardless of which stream implementation they favor (@mmckegg uses [`observ`-style observables](https://github.com/mmckegg/mutant) for performance reasons, i want Matt to use my modules :smile:). this is becoming my preference now. exporting a pull stream is nice because it's a consistent interface, handles back-pressure and error propagation very well, can be used synchronously or asynchronously, and [has an vibrant ecosystem](https://pull-stream.github.io/). luckily it's trivial to wrap simple functions as pull streams (using `pull.map`, `pull.infinite`, `pull.drain`, etc).\r\n\r\nanyways, lots of text. curious to hear what y'all think. thanks again for the invite. :smiley_cat: "},"comment":{"url":"https://api.github.com/repos/audiojs/contributing/issues/comments/243096400","html_url":"https://github.com/audiojs/contributing/issues/18#issuecomment-243096400","issue_url":"https://api.github.com/repos/audiojs/contributing/issues/18","id":243096400,"user":{"login":"dfcreative","id":300067,"avatar_url":"https://avatars.githubusercontent.com/u/300067?v=3","gravatar_id":"","url":"https://api.github.com/users/dfcreative","html_url":"https://github.com/dfcreative","followers_url":"https://api.github.com/users/dfcreative/followers","following_url":"https://api.github.com/users/dfcreative/following{/other_user}","gists_url":"https://api.github.com/users/dfcreative/gists{/gist_id}","starred_url":"https://api.github.com/users/dfcreative/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dfcreative/subscriptions","organizations_url":"https://api.github.com/users/dfcreative/orgs","repos_url":"https://api.github.com/users/dfcreative/repos","events_url":"https://api.github.com/users/dfcreative/events{/privacy}","received_events_url":"https://api.github.com/users/dfcreative/received_events","type":"User","site_admin":false},"created_at":"2016-08-29T11:12:44Z","updated_at":"2016-08-29T11:12:44Z","body":"I am fine to cast errors and to stick with node convention of 2-arg callbacks, that's just fast fix"}}
{"actor":{"display_login":"dfcreative"}}