You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
First, the volume parameter needs to be reactive. This means that if the setVolume is called and the volume attribute is updated, the UI should update as well. Second, the appropriate attribute in the web audio objects need to be updated. For example, if this instrument were a Synth, the gain value would need to be updated. As you can see, it is already fairly complex and this is one of the simple examples. The most difficult would be the array of scheduled elements (e.g. the notes in a score). These elements MUST be stored in an array for reactivity and must schedule/unschedule the element from the transport as the user adds/removes element from the sequencer.
Solution
An undo/redo framework (called olyger) that allows dependency chains to be created, abstracts the complex logic and exposes a simple interface. The two core items are the following:
The key components are the OlyRef and the OlyArr. The key idea for both of these is that once an action has been performed, all of the steps should be recorded such that they can be undone/redone. Here are two:
When changing the OlyRef for the pan value of an instrument, the audio signal value must also be updated. See how this is done below using the onDidChange and the onExecute functions. The key thing to understand here is that onDidChange is called once for every the the value is changed but is not called when redone. The onExecute function allows us to register functions to be called when executed (either during the initial execution or during a redo) and when undone.
constref=oly.olyRef(initialPan);ref.onDidChange(({ onExecute, newValue, oldValue })=>{onExecute(()=>{signal.value=newValue;return()=>{signal.value=oldValue;};});});ref.value++;// the value is updated internally and onDidChange and onExecute are calledoly.undo();// the value is updated internally and the function returned from onExecute is calledoly.redo();// the value is updated internally and only onExecute is called
This example concerns audio samples and the scheduled playlist elements and uses the onDidRemove function. Notice that this doesn't use the onDidExecute and demonstrate the idea of chaining. To explain what this does, when a sample is deleted from the sample list we also have to remove all instances of this sample from the playlist. This is a single action that involves multiple steps.
// samples: oly.OlyArr<Sample>samples.onDidRemove(({ items })=>{constremoved=newSet(items);consttoRemove: number[]=[];master.elements.forEach((el,ind)=>{if(el.type===type&&removed.has(el.element)){toRemove.push(ind);}});for(constindofreverse(toRemove)){master.elements.splice(ind,1);}});// Remove the third element from the list of samples// During this call, the onDidRemove function is called the the appropriate element(s) are also removed// from the playlist. `master.elements` is also an OlyArr so this registers additional steps in the *same* // action.samples.splice(3,1);samples.undo();// Adds the removed element(s) from master and then re-adds the sample(s)samples.redo();// Removes the sample(s) and then removes the element(s) from master
The text was updated successfully, but these errors were encountered:
Problem
Undo redo is very hard. A very simple implementation of undo/redo uses the command pattern however this becomes error prone and verbose.
Consider the following example:
First, the
volume
parameter needs to be reactive. This means that if thesetVolume
is called and the volume attribute is updated, the UI should update as well. Second, the appropriate attribute in the web audio objects need to be updated. For example, if this instrument were a Synth, the gain value would need to be updated. As you can see, it is already fairly complex and this is one of the simple examples. The most difficult would be the array of scheduled elements (e.g. the notes in a score). These elements MUST be stored in an array for reactivity and must schedule/unschedule the element from the transport as the user adds/removes element from the sequencer.Solution
An undo/redo framework (called
olyger
) that allows dependency chains to be created, abstracts the complex logic and exposes a simple interface. The two core items are the following:The key components are the
OlyRef
and theOlyArr
. The key idea for both of these is that once an action has been performed, all of the steps should be recorded such that they can be undone/redone. Here are two:OlyRef
for the pan value of an instrument, the audio signal value must also be updated. See how this is done below using theonDidChange
and theonExecute
functions. The key thing to understand here is thatonDidChange
is called once for every the the value is changed but is not called when redone. TheonExecute
function allows us to register functions to be called when executed (either during the initial execution or during a redo) and when undone.onDidRemove
function. Notice that this doesn't use theonDidExecute
and demonstrate the idea of chaining. To explain what this does, when a sample is deleted from the sample list we also have to remove all instances of this sample from the playlist. This is a single action that involves multiple steps.The text was updated successfully, but these errors were encountered: