lichen-community-systems / Flocking

Flocking - Creative audio synthesis for the Web
GNU General Public License v2.0
697 stars 60 forks source link

Remove support for Node.js #253

Closed colinbdclark closed 5 years ago

colinbdclark commented 5 years ago

While it's painful to consider, I think the writing is on the wall for Node.js support in Flocking. The node-speaker library has always been flaky, high-latency, and CPU intensive. node-midi is buggy on platforms such as Linux, and its underlying use of Rtmidi prevents coming anywhere close to parity on Node.js with the Web MIDI API, and often breaks with newer versions of Node.js. Both code bases have devolved into a wild set of dozens of overlapping forks and ignored issues.

As we move to implement deeper support for the Web Audio API—including both native nodes and AudioWorklets—greater asymmetries will emerge between environments, and continuing to maintain Node.js support will likely increase Flocking's overall complexity.

At the same time, technologies such as headless Chrome and Firefox, as well as Electron, open up the possibility of running web platform applications "natively", including on small devices.

Perhaps it's time to move on from Node.js and focus on a web-only implementation?

MylesBorins commented 5 years ago

Could you maybe embed headless chrome in the node version? 😇

In all seriousness I'd be up for putting a bit of time in to seeing if there is a more sustainable solution... The node version could also be a standalone release.

On Sun, Nov 18, 2018, 6:53 PM Colin Clark <notifications@github.com wrote:

While it's painful to consider, I think the writing is on the wall for Node.js support in Flocking. The node-speaker library has always been flaky, high-latency, and CPU intensive. node-midi is buggy on platforms such as Linux, and its underlying use of Rtmidi prevents coming anywhere close to parity on Node.js with the Web MIDI API, and often breaks with newer versions of Node.js. Both code bases have devolved into a wild set of dozens of overlapping forks and ignored issues.

As we move to implement deeper support for the Web Audio API—including both native nodes and AudioWorklets—greater asymmetries will emerge between environments, and continuing to maintain Node.js support will likely increase Flocking's overall complexity.

At the same time, technologies such as headless Chrome and Firefox, as well as Electron, open up the possibility of running web platform applications "natively", including on small devices.

Perhaps it's time to move on from Node.js and focus on a web-only implementation?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/colinbdclark/Flocking/issues/253, or mute the thread https://github.com/notifications/unsubscribe-auth/AAecV07Qxl3miU2cHOABzFlNkOfTweBKks5uwfMGgaJpZM4YoNtb .

colinbdclark commented 5 years ago

Thanks, @MylesBorins, that's awesome. What kinds of more sustainable solutions do you have in mind? What would a "standalone release" be like?

MylesBorins commented 5 years ago

I tried playing with headless chrome but got some errors related to urls

code ( assuming you have puppeteer and flocking installed in a project

index.js

const puppeteer = require('puppeteer');
const {join} = require('path');

const flocking = join(
  __dirname,
  'node_modules',
  'flocking',
  'dist',
  'flocking-all.js'
);

const entry = join(__dirname, 'synth.js');

puppeteer.launch().then(async browser => {
  const page = await browser.newPage();

  page.on('console', (message) => {
    console.log(message._text);
  });

  await page.addScriptTag({
    path: flocking
  });

  await page.addScriptTag({
    path: entry
  });
  // // other actions...
  await browser.close();
});

synth.js

const enviro = flock.init();
// A table-lookup sine wave oscillator.

flock.synth({
    synthDef: {
        ugen: "flock.ugen.sinOsc",
        freq: 440,
        mul: 0.25
    }
});
colinbdclark commented 5 years ago

Hi @MylesBorins! I played around with your demo, and it looks like the URL errors you saw are related to a bug in Puppeteer 1.10.0 where scripts can't be loaded by path in headless mode. Using 1.9.0 instead worked for me. Also, Puppeteer mutes audio by default, so you need something like this:

puppeteer.launch({
    ignoreDefaultArgs: ["--mute-audio"]
})

After that, I was able to hear your sine tone, no problem.

But here's the thing. If we take this further, how would we handle communication between the Node process and the Flocking process running inside the headless Chrome process? Like, say you want to be using Node.js because you're receiving messages over a UDP socket with osc.js. You probably want to be able to change the inputs of your synth dynamically in response to those messages. How would you get a message across to the "other universe" of the Chrome process? And what if that message needed a response back? It seems pretty likely that you'd have to roll your own IPC system. I don't see any primitives in Puppeteer that do this for free, and it's of course a fairly complex thing to get right. Whereas, Electron already provides a very good IPC implementation between its Main and Renderer processes that covers this scenario, plus all of the generalized workflow for starting and stopping Chrome processes, etc. So why wouldn't a Flocking user just want to use Electron instead?

Thinking through other use cases, if a user didn't need things that Node.js does particularly well—like, say, sockets or file I/O—then why would they want to use Node.js at all, instead of just straight-up headless (or headful) Chrome and a web application?

MylesBorins commented 5 years ago

There is another project we can explore called Carlo, which has a very slim rpc system on top of puppeteer

Re client / server... I wonder if we could explore a client server model similar to what is offered by super collider. Although this is starting to smell like a different project now 😇

On Thu, Nov 22, 2018, 7:09 PM Colin Clark <notifications@github.com wrote:

Hi @MylesBorins https://github.com/MylesBorins! I played around with your demo, and it looks like the URL errors you saw are related to a bug in Puppeteer 1.10.0 where scripts can't be loaded by path in headless mode https://github.com/GoogleChrome/puppeteer/issues/3463. Using 1.9.0 instead worked for me. Also, Puppeteer mutes audio by default, so you need something like this:

puppeteer.launch({ ignoreDefaultArgs: ["--mute-audio"] })

After that, I was able to hear your sine tone, no problem.

But here's the thing. If we take this further, how would we handle communication between the Node process and the Flocking process running inside the headless Chrome process? Like, say you want to be using Node.js because you're receiving messages over a UDP socket with osc.js. You probably want to be able to change the inputs of your synth dynamically in response to those messages. How would you get a message across to the "other universe" of the Chrome process? And what if that message needed a response back? It seems pretty likely that you'd have to roll your own IPC system. I don't see any primitives in Puppeteer that do this for free, and it's of course a fairly complex thing to get right. Whereas, Electron already provides a very good IPC implementation between its Main and Renderer processes that covers this scenario, plus all of the generalized workflow for starting and stopping Chrome processes, etc. So why wouldn't a Flocking user just want to use Electron instead?

Thinking through other use cases, if a user didn't need things that Node.js does particularly well—like, say, sockets or file I/O—then why would they want to use Node.js at all, instead of just straight-up headless (or headful) Chrome and a web application?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/colinbdclark/Flocking/issues/253#issuecomment-441136103, or mute the thread https://github.com/notifications/unsubscribe-auth/AAecV8D2iyE2QvlvWA27qtBl_-fmzmTmks5uxzyxgaJpZM4YoNtb .

colinbdclark commented 5 years ago

I think this always was a different project! :smile: Carlo looks interesting, though probably still a bit too raw to invest in. It sounds like the best option for today is to go ahead and remove the "native" Node.js backend from Flocking and recommend that people who want to build "local" or Node.js-based applications use Electron

I've built several Flocking-based Electron sound installations that have run continuously for months at a time without trouble, either headlessly with xvfb on a Pi or, more robustly, on macOS.

colinbdclark commented 5 years ago

This has been resolved with #258. We'll keep a close eye out for other options to support Node.js (in addition to Electron). Thanks for your investigatory efforts, @MylesBorins—much appreciated!

MylesBorins commented 5 years ago

🎉

On Sun, Dec 30, 2018, 3:23 PM Colin Clark <notifications@github.com wrote:

This has been resolved with #258 https://github.com/colinbdclark/Flocking/pull/258. We'll keep a close eye out for other options to support Node.js (in addition to Electron). Thanks for your investigatory efforts, @MylesBorins https://github.com/MylesBorins—much appreciated!

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/colinbdclark/Flocking/issues/253#issuecomment-450584332, or mute the thread https://github.com/notifications/unsubscribe-auth/AAecVx-jZkXo8Y_we94yw1qpTsOEdfdfks5u-SCigaJpZM4YoNtb .