leolabs/ableton-js

get_prop() timeout on large dataset

walrusmustgo opened this issue · 2 comments

Hi! First of all, thanks for this, it's an awesome library!

I'm having issues with timeouts, I'm doing a map of device parameters which have automation on them, which needs to be done on a large number of tracks, and i've encountered a couple of issues:

  1. The AutomationState enum is incorrectly setup, the AutomationState.Playing should be on the second slot, not the third as it is now, and the .Overridden should be on the third one, to accurately reflect what's happening in ableton.
  2. The mapping is not capturing all of the tracks, and i can't find a pattern in which it happens.
  3. This is the most urgent one, the framework times out after 2000ms, so i've changed it to 20000ms, but the timeout still happens, even though i'm not quite sure why. I'll attach the code and the ableton project for you to test out, i might be missing something really obvious.

Thanks a lot, and thank you for this beautiful piece of software! :) Cheers!

TimeoutIssue.zip

PS. I'm using Ableton 11.0.12.

Hey @walrusmustgo,

Thank you for reporting this issue! I've fixed the enums for the automation state and released a new version.

Regarding your 2nd and 3rd point, these are likely part of the same issue. It seems that when you make a lot of requests at the same time, either Live or my MIDI script can't handle them properly.

A simple solution is to use a library like p-all that allows you to limit the concurrency of asynchronous tasks. Additionally, you can access some data using the raw property of the objects that are returned from Live, saving you a few requests. Here's a modified version of your script that works on my end:

import pAll from "p-all";
import { AutomationState } from "ableton-js/ns/device-parameter";

const ableton = new Ableton();

const getAutomated = async () => {
  let tracks = await ableton.song.get("tracks");

  await Promise.all(
    tracks.map(async (track) => {
      console.log(await track.get("name"));

      const devices = await track.get("devices");

      let automatedParameters = 0;

      await pAll(
        devices.map((device) => async () => {
          const deviceParams = await device.get("parameters");
          await pAll(
            deviceParams.map((deviceParam) => async () => {
              let automationState = await deviceParam.get("automation_state");

              console.log({
                track: track.raw.name,
                device: device.raw.name,
                parameter: deviceParam.raw.name,
                automationState: AutomationState[automationState],
              });

              automatedParameters++;

              return;
            }),
            { concurrency: 10 },
          );
        }),
        { concurrency: 10 },
      );
    }),
  );
};

getAutomated();

Let me know if this works for you as well

I'll close this one due to inactivity. Feel free to open a new ticket if you have any further questions!