Scale marker regions to match tempo marker?

I have a music template that I’d very much like to not have to replicate every time I recreate the event, as it has approx 10 markers and twice as many regions.

Is it possible to resize all regions that are after a tempo marker to fit the new tempo? so they fit to the new grid?

I don’t think it’s directly possible. But instead of saving your template, you could script it, which would allow you to recreate everything at the right place. Here’s a code exemple, which you can try in the console, that places a loop in a new event, between bar 5 and 7, whatever tempo you choose for the “tempo” variable.

myEvent = studio.project.create("Event");
logictrack = myEvent.markerTracks[0];
tempo = 80;
start = 5;
stop = 7;
logictrack.addRegion((start-1)*60/tempo*4 , (stop-start)*60/tempo*4 , "loop" , 1);
1 Like

As of the time of writing (February of 2023), the only way to do this is to create or edit an event by using a script, as Alcibiade suggests.

That being said, a task to add a dedicated feature for this is already in our feature and improvement tracker, so I’ll add you to the list of people interested in it.

1 Like

The Following Script works perfectly to solve my problem, for those of you wanting to achieve the same thing before it gets officially implemented. Just save it as a .js and out it in the sscripts folder of your specific install.
Thanks guys.

studio.menu.addMenuItem({
  name: "Change Tempo While Preserving Beat Alignments",
  isEnabled: function() {
    var current = studio.window.editorCurrent();
    return current != null && current.entity == "TempoMarker";
  },
  execute: function() {
    var tempoMarker = studio.window.editorCurrent();

    var newTempo = studio.system.getNumber("Enter the new tempo:", tempoMarker.tempo);

    if (newTempo == null || newTempo <= 0) {
      return;
    }

    repositionModules(tempoMarker, newTempo);
    repositionMarkers(tempoMarker, newTempo);
    repositionAutomationCurvePoints(tempoMarker, newTempo);

    tempoMarker.tempo = newTempo;
  },
});

function positionToBeats(position, basePosition, tempo) {
  var offset = position - basePosition;
  return offset / 60 * tempo;

}

function beatsToPosition(beats, basePosition, tempo) {
  var offset = beats * 60 / tempo;
  return basePosition + offset;
}

function repositionModules(tempoMarker, newTempo) {
  var modules = tempoMarker.timeline.modules;

  for (var i = 0; i < modules.length; ++i) {
    var module = modules[i];

    if (module.start >= tempoMarker.position) {
      var startBeat = positionToBeats(module.start, tempoMarker.position, tempoMarker.tempo);
      var endBeat = positionToBeats(module.start + module.length, tempoMarker.position, tempoMarker.tempo);

      module.start = beatsToPosition(startBeat, tempoMarker.position, newTempo);
      module.length = beatsToPosition(endBeat, tempoMarker.position, newTempo) - module.start;

      repositionFadeCurve(module.fadeInCurve, tempoMarker, newTempo);
      repositionFadeCurve(module.fadeOutCurve, tempoMarker, newTempo);
    }
  }
}

function repositionFadeCurve(fadeCurve, tempoMarker, newTempo) {
  if (fadeCurve != null) {
    repositionAutomationPoint(fadeCurve.startPoint, tempoMarker, newTempo);
    repositionAutomationPoint(fadeCurve.endPoint, tempoMarker, newTempo);
  }
}

function repositionMarkers(tempoMarker, newTempo) {
  var markers = tempoMarker.timeline.markers;

  for (var i = 0; i < markers.length; ++i) {
    var marker = markers[i];

    if (marker != tempoMarker && marker.position >= tempoMarker.position) {
      var startBeat = positionToBeats(marker.position, tempoMarker.position, tempoMarker.tempo);
      var endBeat = null;

      if (marker.length != null) {
        endBeat = positionToBeats(marker.position + marker.length, tempoMarker.position, tempoMarker.tempo);
      }

      marker.position = beatsToPosition(startBeat, tempoMarker.position, newTempo);

      if (marker.length != null) {
        marker.length = beatsToPosition(endBeat, tempoMarker.position, newTempo) - marker.position;
      }
    }
  }
}

function repositionAutomationCurvePoints(tempoMarker, newTempo) {
  var curves = tempoMarker.timeline.automationCurves;

  for (var i = 0; i < curves.length; ++i) {
    var points = curves[i].automationPoints;

    for (var j = 0; j < points.length; ++j) {
      var point = points[j];

      if (point.position >= tempoMarker.position) {
        repositionAutomationPoint(point, tempoMarker, newTempo);
      }
    }
  }
}

function repositionAutomationPoint(point, tempoMarker, newTempo) {
  var beat = positionToBeats(point.position, tempoMarker.position, tempoMarker.tempo);
  point.position = beatsToPosition(beat, tempoMarker.position, newTempo);
}
1 Like