Please ensure Javascript is enabled for purposes of website accessibility Jump to content

Helix editor 1.12 - Undo: Come on guys!


bobthedog
 Share

Recommended Posts

You would think, except it's important to note that the Helix editor isn't like a plugin or DAW; it's a remote control that reflects the capabilities of the connected hardware.

 

The Helix hardware would need to support undo/redo first, and from what I understand, that's not insignificant effort.

 

I believe there's an IdeaScale entry for undo/redo; it's definitely worth voting up.  :)

  • Upvote 2
Link to comment
Share on other sites

Line6, thank you very much for your latest efforts on the editor!  I think it is a thing of beauty in many respects.  I have to say however, as a "beta" user/tester, I would like to have seen more suggestions from the users who gave feedback during the beta period actually implemented. I thought the purpose of a beta period was not only to find bugs but also to implement the best of the suggested modifications submitted by end users. I know the editor will probably get at least one more revision and I hope you consider some of the best ideas submitted by your user base. Either way, it is a phenomenal tool and a magnificent accomplishment! I am looking forward to the focus shifting back to additions and improvements to other areas on the Helix.

  • Upvote 1
Link to comment
Share on other sites

...I thought the purpose of a beta period was not only to find bugs but also to implement the best of the suggested modifications submitted by end users......

Bug finding/fixing, for sure. But new features? Not so much. Typically the feature set of any software release is pretty well fixed at the design close stage of development, and that happens long before beta testing.

Link to comment
Share on other sites

Bug finding/fixing, for sure. But new features? Not so much. Typically the feature set of any software release is pretty well fixed at the design close stage of development, and that happens long before beta testing.

 

Absolutely not always the case! I have been a developer and beta tester for a huge range of software and soliciting recommendations for improvement and making changes to parts of the UI that users find problematic or in need of tweaking is often part of the process. Otherwise the beta process is nothing other than a QA process utilizing end users as your QA team. Not that this does not happen but it is hardly an ideal use of the resources inherent in a large user base. A beta process at its best should be a feedback process of give and take and more than just a QA exercise.

 

The endgame should be the goal of putting out the best, most well received product possible, catered to the end users needs and requests (within reason, technical constraints, and allotted resources). Line6 did a wonderful job on the editor but implementing some suggestions that came up almost right away during the beta period would make the editor much better. Lastly I would add, if, as you suggest, the design was fixed long before the beta process, then L6 might want to consider getting more users, especially those familiar with UI design, involved in the initial process.

Link to comment
Share on other sites

Fair enough. I haven't been involved in as wide a range of beta testing as you. I was just speaking from my experience, both as a tester and a software developer. It's partly a matter of terminology. I call what you are referring to 'usability testing', and that generally happens earlier in the design stage.

 

And I'm sure Line 6 is not losing track of all the suggestions that have been made using the resources form a larger user base. Those suggestions may appear in later version of the editor.

 

EDIT: Also, I notice that you still have to tick the 'Beta' box to see this latest release. So unless Line 6 just forgot to change the status that suggests that this is an interim release during an ongoing beta period. So you may yet see some of what you'd like to see!

Link to comment
Share on other sites

...

 

EDIT: Also, I notice that you still have to tick the 'Beta' box to see this latest release. So unless Line 6 just forgot to change the status that suggests that this is an interim release during an ongoing beta period. So you may yet see some of what you'd like to see!

I noticed the same thing regarding the download. For those who have not updated yet (at least at the moment), the latest download of the "Helix" app installer under the beta (checkbox) section of the download page will update you to the latest driver, firmware, and Editor version (1.12). I found this a bit confusing when I went to do the update as the editor is officially out of beta.

 

I have in no way given up on seeing some of the better suggestions find their way into the editor and have no problem with patiently awaiting them as Line6 rotates through top priority issues and additions to other areas of the Helix.

Link to comment
Share on other sites

Provided 1.12 behaves nicely, that is indeed the plan.

 

I spent a couple of hours with it today and it behaved very well. New foot switch features are very welcome. Block copy and paste worked well for me.

 

Can't wait to see what's next...  I'm doing my first gig with the Helix this weekend. Can't wait.... my patches are almost in order... gotta level out preset volumes next

 

 

(I would like to see me not have to re-launch the editor to reconnect to the Helix eventually too BTW)

Link to comment
Share on other sites

You would think, except it's important to note that the Helix editor isn't like a plugin or DAW; it's a remote control that reflects the capabilities of the connected hardware.

 

The Helix hardware would need to support undo/redo first, and from what I understand, that's not insignificant effort.

 

I believe there's an IdeaScale entry for undo/redo; it's definitely worth voting up.  :)

 

As a developer I will give you a hint of how to do it without implementing undo/redo on the helix hardware (not that I wouldn't like it on the hardware!):

 

1. Whenever a patch is changed clear the undo stack.

 

2. Whenever a parameter is changed in the editor (either directly by user or via the helix hardware) if the top item on the Undo Stack is a different parameter then push the details of the parameter and its old value onto  the undo stack.

 

2. Whenever undo is pressed pop the data off the undo stack and set the parameter back to it's old value.

 

It isn't rocket science!

Link to comment
Share on other sites

As a developer I will give you a hint of how to do it without implementing undo/redo on the helix hardware (not that I wouldn't like it on the hardware!):

 

1. Whenever a patch is changed clear the undo stack.

 

2. Whenever a parameter is changed in the editor (either directly by user or via the helix hardware) if the top item on the Undo Stack is a different parameter then push the details of the parameter and its old value onto  the undo stack.

 

2. Whenever undo is pressed pop the data off the undo stack and set the parameter back to it's old value.

 

It isn't rocket science!

 

Although it's nowhere near the top of my list it seems like an undo function might take us one step closer to an offline editor, grin.  ;)

Link to comment
Share on other sites

As long as I hear a change in Helix in real time as I tweak via the editor, idk if its on line or otherwise. Im not a big fan however of "turn based" software. Chess is for that stuff...  ;)

Link to comment
Share on other sites

Nice to see a bunch of keyboard navigation added.

 

Maybe I'm missing something, but is there a way to cycle through the parameters of a selected block using the keyboard? There is one keystroke that might have something to do with this according to the keyboard shortcut sheet, which is ENTER, but it doesn't seem to do anything.

 

Also, is there a way, again using only the keyboard, to select an empty block location and put a desired block in that location?

 

It seems to me there should be another panel to TAB into. So there would be the preset list, signal chain, and block detail panel.

 

It would also be nice to be able to increment the value of all parameters by one. For example, the level parameter in particular has large jumps, or generally anything with a dB label. A lot of parameters with a frequency or millisecond label behave like this too.

Link to comment
Share on other sites

As a developer I will give you a hint of how to do it without implementing undo/redo on the helix hardware (not that I wouldn't like it on the hardware!):

 

1. Whenever a patch is changed clear the undo stack.

 

2. Whenever a parameter is changed in the editor (either directly by user or via the helix hardware) if the top item on the Undo Stack is a different parameter then push the details of the parameter and its old value onto  the undo stack.

 

2. Whenever undo is pressed pop the data off the undo stack and set the parameter back to it's old value.

 

It isn't rocket science!

There are still several obstacles to deal with. Some examples...

 

What if they don't move on to another parameter? What if they tweak a bit, then play a few chords, then tweak more, then play a few chords...set drive to 5.5 and try it, decide they need more, set it to 6.5, nah still need more, set it to 8.0 WHOAH too far, I want to undo that...where does the undo take them then? Do you go all the way back down to 0? Then they're like wait wtf where'd my last update go? Do you go back to 6.5? Ideally, sure, but what triggered the app to store that specific value? And would every user agree?

 

And then there's the fact that an update could be anything - tweak a parameter, add a block, delete a block, move a block, change the signal path, switch the selected model in a block, toggle a block on/off, change a scribble strip, add or remove an effect to a footswitch assignment, and on and on and on. It's not as simple as pushing {parameter, old_value, new_value} onto a stack. The simplest away around this is to store the state of the entire patch, but that's resource-intensive.

 

And then there's the fact you completely glossed over, that it does in fact have to take the hardware into account. If you change the Drive parameter from 0.0 to 5.5, that may have actually been 55 messages to the Helix, 0.0 to 0.1 to 0.2, etc. Maybe the Helix doesn't have a simple message that can do that in one go. That's a bad example, because It probably does in the case of simply setting a parameter to a value, but there may be cases, like moving a block or changing an amp model, where it can't be done in a single message. My point is, we don't know the Helix hardware or messaging protocol, so we don't know what limitations may be there to complicate matters.

 

Storing an undo stack locally is one thing, unraveling it into blocks that make sense to the user and packing those into messages that work with the hardware is another matter.

  • Upvote 1
Link to comment
Share on other sites

Here's a concrete example from another Undo scenario that may help clarify what I mean. In VisualStudio, copy a block of code from inside brackets (in an if block, for example). Paste it outside the brackets. Then undo it. What happens?

 

If I explained the steps clearly enough for you to do it the way I'm thinking, the code you pasted is still there after you undo, it's just indented more. Your undo didn't undo the last user action, it undid an automatic reformatting that the application did. It takes 2 undo actions to get rid of your 1 user action. And that's for a simple copy/paste in what is essentially a glorified text editor.

 

Now try applying that to the vast array of disparate functions you can do in editing a Helix patch. If you change an effect from one Drive to another, is that one action, or is it two? Does the Helix delete the block and then add the new one behind the scenes? If so, would a single undo leave you with an empty block, and the second undo give you back your original?

 

When you assign an action to a footswitch, you can overwrite the previous assignment. What if the assignment was a toggle for several other effects? The assignment you just did is probably two Helix actions (or more), Clear Assignment, Add Assignment. Undoing that, however, is more complicated. You probably have a Clear Assignment, and then a loop to Add Assignment for each of the previously assigned pedals. I highly doubt Helix can do a multi-assignment in a single message.

 

What if you move a block around? Each movement is probably a single action to undo on the Helix. Plus, if you go through/past/around other blocks, you might have Move Block actions for those other blocks all encapsulated in that one user action of moving a completely different block.

 

What if you move a block down to the second signal path, and that path was previously empty? You probably have some hidden Helix changes there to create the second signal path.

 

It's not an insurmountable problem, but you greatly oversimplified it and glossed over some tricky details. That's all I'm saying.

  • Upvote 1
Link to comment
Share on other sites

 

The Helix hardware would need to support undo/redo first, and from what I understand, that's not insignificant effort.

 

 

As a seasoned ( jaded ) programmer ...  I fully concur.  Undo/Redo  is what we call in the trade ... "non-trivial" to implement. 

  • Upvote 1
Link to comment
Share on other sites

There is a simple 'undo' feature that will restore the preset to its last-saved state. Switch momentarily to a different preset and then return to the preset-being-edited. I know it's not what's requested, but it can be useful. You can enhance it by saving your desired changes along the way - much like you would do with any file after making changes or adding information that you don't want to lose. If you want to keep intermediate changes, save the preset. If you don't want to save the changes then presumably you're prepared to lose them.

 

You can also copy the preset-being-edited at multiple points to create your own set of 'undo' points. Doing this in conjunction with using the Looper in pre-position will also let you conveniently audition the changes and different versions of the preset.

 

Sure it's not ideal - but you can manage it until/unless the editor incorporates a better way, which certainly sounds like it's not imminent.

Link to comment
Share on other sites

Bug finding/fixing, for sure. But new features? Not so much. Typically the feature set of any software release is pretty well fixed at the design close stage of development, and that happens long before beta testing.

 

 

Absolutely not always the case! I have been a developer and beta tester for a huge range of software and soliciting recommendations for improvement and making changes to parts of the UI that users find problematic or in need of tweaking is often part of the process. Otherwise the beta process is nothing other than a QA process utilizing end users as your QA team. Not that this does not happen but it is hardly an ideal use of the resources inherent in a large user base. A beta process at its best should be a feedback process of give and take and more than just a QA exercise.

 

The endgame should be the goal of putting out the best, most well received product possible, catered to the end users needs and requests (within reason, technical constraints, and allotted resources). Line6 did a wonderful job on the editor but implementing some suggestions that came up almost right away during the beta period would make the editor much better. Lastly I would add, if, as you suggest, the design was fixed long before the beta process, then L6 might want to consider getting more users, especially those familiar with UI design, involved in the initial process.

I don't really think you two disagreed much here. There is an ocean of difference between "new features" and "improvements" or "tweaks". Feature set is unlikely to change much, if at all, by the time a product is ready for beta testing. If it changes, it's far more likely to be features dropped for the sake of meeting deadlines than it is to be features added. That's simply the way the world tends to work, unfortunately. Sure, you can find exceptions to this, but I doubt you'll find many. Modifications, tweaks, enhancements, and so on...sure, there's a better chance those will make it in. It depends on the scope of the change.

 

Let's be honest. The primary value of beta testing is extended QA, pure and simple. There is no way your QA department will hit everything. Users will have a wider variety of hardware (processors, video cards, operating systems, and on and on) in a wider arrangement than any QA department could ever possibly replicate. They will do a much wider range of things with the product too. I've seen some extensive test plans and test procedures, but there are always cases where you end up saying, "huh, I didn't think to try that." The most important thing in beta testing is to squash as many bugs as you can, plain and simple. Management will never say, "holy crap this idea from BetaTester_01 is brilliant, we can't release until we implement it!" They will, however, say, "mother ****er, how did we miss this bug?!? We can't release until it's resolved."

 

When you beta test, that is your job. Find bugs. You're making a trade - early access to try out the product in exchange for reporting bugs. That's their main priority at that point. They may like feature requests and ideas for tweaks, they may run them by management as ideas to be implemented in the future, but they'd trade a single show-stopping bug report for a dozen ideas for nice little tweaks.

 

Now end user feedback is good. Great even. But really, 1) feature set is likely not changing (for release 1.0) at that point. 2) The management very likely already have a set of new features for the next release planned. 3) The developers very likely have a set of things they argued for but were shut down on due to schedule or money. 4) If your idea is genuinely a good one, it's likely already covered by 2 (planned future features) or 3 (ideas that were shot down) or for some reason you don't know it's unfeasible. 5) A heck of a lot of this stuff, features and usability, particularly when it comes to UI implementation, is personal preference. What one user likes two others will hate. Your beta testers are not necessarily a good representative sample of your final end users. Feature changes based on beta feedback are dangerous. 6) If they're using their heads, they already have market research, user feedback, etc, that went into the design stages. Do you think they came up with this product in a vacuum? 7) Beta tests are typically occurring when the product is getting close to release. What's the top priority at that point? Bugs, bugs, bugs. Even if you could get past all the other reasons that your idea is unlikely to get implemented, you still have a team of developers who are overloaded with bug fixes they're scrambling to get in so that they can meet the release date without show-stopping issues killing them.

 

Long story short, sure, they should pay attention to beta user feedback, absolutely. But there are a lot of reasons why beta user feedback is unlikely to get implemented (short-term) beyond bug fixes.

  • Upvote 1
Link to comment
Share on other sites

Although it's nowhere near the top of my list it seems like an undo function might take us one step closer to an offline editor, grin.  ;)

 

I doubt it... because.

 

 

...except it's important to note that the Helix editor isn't like a plugin or DAW; it's a remote control that reflects the capabilities of the connected hardware....

 

If it's truly a "remote control" then they'd have to write a completely different program to make it work offline I bet.

 

And I'd rather they modeled all the Whizbangs we've been asking for, frankly...

Link to comment
Share on other sites

I don't really think you two disagreed much here. There is an ocean of difference between "new features" and "improvements" or "tweaks". Feature set is unlikely to change much, if at all, by the time a product is ready for beta testing. If it changes, it's far more likely to be features dropped for the sake of meeting deadlines than it is to be features added. That's simply the way the world tends to work, unfortunately. Sure, you can find exceptions to this, but I doubt you'll find many. Modifications, tweaks, enhancements, and so on...sure, there's a better chance those will make it in. It depends on the scope of the change.

 

Let's be honest. The primary value of beta testing is extended QA, pure and simple. There is no way your QA department will hit everything. Users will have a wider variety of hardware (processors, video cards, operating systems, and on and on) in a wider arrangement than any QA department could ever possibly replicate. They will do a much wider range of things with the product too. I've seen some extensive test plans and test procedures, but there are always cases where you end up saying, "huh, I didn't think to try that." The most important thing in beta testing is to squash as many bugs as you can, plain and simple. Management will never say, "holy crap this idea from BetaTester_01 is brilliant, we can't release until we implement it!" They will, however, say, "mother ****er, how did we miss this bug?!? We can't release until it's resolved."

 

When you beta test, that is your job. Find bugs. You're making a trade - early access to try out the product in exchange for reporting bugs. That's their main priority at that point. They may like feature requests and ideas for tweaks, they may run them by management as ideas to be implemented in the future, but they'd trade a single show-stopping bug report for a dozen ideas for nice little tweaks.

 

Now end user feedback is good. Great even. But really, 1) feature set is likely not changing (for release 1.0) at that point. 2) The management very likely already have a set of new features for the next release planned. 3) The developers very likely have a set of things they argued for but were shut down on due to schedule or money. 4) If your idea is genuinely a good one, it's likely already covered by 2 (planned future features) or 3 (ideas that were shot down) or for some reason you don't know it's unfeasible. 5) A heck of a lot of this stuff, features and usability, particularly when it comes to UI implementation, is personal preference. What one user likes two others will hate. Your beta testers are not necessarily a good representative sample of your final end users. Feature changes based on beta feedback are dangerous. 6) If they're using their heads, they already have market research, user feedback, etc, that went into the design stages. Do you think they came up with this product in a vacuum? 7) Beta tests are typically occurring when the product is getting close to release. What's the top priority at that point? Bugs, bugs, bugs. Even if you could get past all the other reasons that your idea is unlikely to get implemented, you still have a team of developers who are overloaded with bug fixes they're scrambling to get in so that they can meet the release date without show-stopping issues killing them.

 

Long story short, sure, they should pay attention to beta user feedback, absolutely. But there are a lot of reasons why beta user feedback is unlikely to get implemented (short-term) beyond bug fixes.

 

 A well written synopsis and I agree with most of the points you are making, particularly regarding the range of user hardware and software platforms that beta testing provides and the emphasis on bug fixes. I am simply stating that an ideal beta test takes into account critical feature requests and UI usability issues as well; even if as you say, it takes version 2.0,3.0 or 35.0 to deliver them. I do have to disagree on a couple of points, given the number of users already out here for the Helix, the best and most common of their suggestions are probably a very good representation of the wider user base. Also feature changes and enhancements based on user feedback are "dangerous" seems like a bit of hyperbole. I have designed software and made numerous and sometimes substantial modfications according to user feedback during the beta period. Granted there can be unanticipated bugs caused by new features/changes but that is all part of a beta process which can be as fluid or as static as the developers deem appropriate and have time and resources for.

 

Of course the product did not come up in a vacuum although a different or larger design team might have changed a couple of the underlying premises used in the design. Some things that perhaps could have been, or will be done differently -- I think in a commendable effort to keep consistency between the software for various L6 products they have perpetuated a design paradigm of using bars for everything instead of using them in combination with other UI elements like dropdown menus and switches.  This may expedite development, be visually pleasing and make it easier to position screen elements but IMHO, I believe it degrades the user experience for binary options like on/off and particularly for multiple choice text fields . I also believe the bars are too wide in places preventing all of the parameters for a block from being displayed on one screen without scrolling. I hope L6 modifies this visual paradigm in their software at some point in the future with an eye towards utility as well as consistency.  In an effort, at least initially, to emulate the current functionality of the Helix perhaps some opportunities to add features to the editor have been missed or delayed(? still too early to tell), such as scenes or undo capability and a host of other functions that would make the editor more than a "remote control"  and actually add new features and functionality that may not or cannot exist on the device itself. These features may well be coming later and some have already appeared. I believe the main screen of the editor should show more useful information like the specific names of the various blocks in the signal chain rather than requiring clicking on or hovering over them, but that is not the focus of the point I am making, the underlying design principle is that although the editor screens and feature set need to follow the Helix to some extent for consistency and ease of use they don't need to mimic them to the point of inheriting limitations imposed by the physical hardware of the Helix such as the smaller screen or switch/knob contortions that might be required for certain operations. PC software has its own inherent limitations but also offers some advantages that can be exploited to do things that would be difficult or impossible directly on the Helix. The design team will probably exploit these alternate capabilities the Editor offers even more in future versions.

 

Anyway it is way too easy for us to be armchair quarterbacks when we only have a fraction of the facts and I am sure much of what the user base suggests was already discussed by the designers.  One advantage is that the beta feedback informs the designers as to which features and changes are most important to its users. Those user priorities are information you don't necessarily have during the initial design phases.  Regardless, it is still too close to the release date for me to get mired down in anything other than to express my admiration and appreciation for the editor. It is a great tool and I am elated to have it! Line6 has every reason to be proud of their accomplishment. I think it can only get better in future iterations but it is already fantastic, easy to use, and aesthetically pleasing and ultimately, there are so many things other than the editor that are of way more importance to me.

Link to comment
Share on other sites

Here's a concrete example from another Undo scenario that may help clarify what I mean. In VisualStudio, copy a block of code from inside brackets (in an if block, for example). Paste it outside the brackets. Then undo it. What happens?

 

If I explained the steps clearly enough for you to do it the way I'm thinking, the code you pasted is still there after you undo, it's just indented more. Your undo didn't undo the last user action, it undid an automatic reformatting that the application did. It takes 2 undo actions to get rid of your 1 user action. And that's for a simple copy/paste in what is essentially a glorified text editor.

 

Now try applying that to the vast array of disparate functions you can do in editing a Helix patch. If you change an effect from one Drive to another, is that one action, or is it two? Does the Helix delete the block and then add the new one behind the scenes? If so, would a single undo leave you with an empty block, and the second undo give you back your original?

 

 

When you assign an action to a footswitch, you can overwrite the previous assignment. What if the assignment was a toggle for several other effects? The assignment you just did is probably two Helix actions (or more), Clear Assignment, Add Assignment. Undoing that, however, is more complicated. You probably have a Clear Assignment, and then a loop to Add Assignment for each of the previously assigned pedals. I highly doubt Helix can do a multi-assignment in a single message.

 

What if you move a block around? Each movement is probably a single action to undo on the Helix. Plus, if you go through/past/around other blocks, you might have Move Block actions for those other blocks all encapsulated in that one user action of moving a completely different block.

 

What if you move a block down to the second signal path, and that path was previously empty? You probably have some hidden Helix changes there to create the second signal path.

 

It's not an insurmountable problem, but you greatly oversimplified it and glossed over some tricky details. That's all I'm saying.

In the database world we would simply encapsulate all levels of the undo within a single uncommited transaction, potentially with multiple savepoints. Hitting save would constitute the commit and undo would be a rollback. But yes, I can see where at least initially implementing "Undo" functionality and still being able to dynamically hear the results of your action on the Helix would be a bit of a programming exercise but nothing that can't be pulled off. You may have to implement some messaging to the user for certain actions that cannot be undone such as you see in other applications. I would think an initial simple implementation would be at least to have the parameters for a block be stored in an undo/redo stack for A/B comparison purposes. More complex undo actions could come in later implementations.

Link to comment
Share on other sites

A)Also feature changes and enhancements based on user feedback are "dangerous" seems like a bit of hyperbole.

 

B)Anyway it is way too easy for us to be armchair quarterbacks when we only have a fraction of the facts and I am sure much of what the user base suggests was already discussed by the designers.

Just two quick points. We're not far enough apart in opinions to get bogged down in a big debate. :)

 

A) Eh, not really. It obviously depends on the size / scope / depth / extent of the change, but overall I stand by what I said. It's dangerous to make large changes late in the game. You need to be very careful when doing so. Again, it obviously depends on the scope of the change. As a release date approaches, many places implement strict code freezes for this very reason; nothing but bug fixes merged into the main branch after that point, period.

 

B) Really, that's my main point, summarized pretty well. We don't have all the information they do. Not even close. It's the height of hubris to take what little info we have and tell them something would be easy.

Link to comment
Share on other sites

I doubt it... because.

 

 

 

If it's truly a "remote control" then they'd have to write a completely different program to make it work offline I bet.

 

And I'd rather they modeled all the Whizbangs we've been asking for, frankly...

 

Definitely not holding my breath on this one. And if its remote control, why isn't it wireless (just kiddin')?  B)

Link to comment
Share on other sites

...

 

B) Really, that's my main point, summarized pretty well. We don't have all the information they do. Not even close. It's the height of hubris to take what little info we have and tell them something would be easy.

 

When I go for "hubris" I definitely strive for the "heights". Otherwise you denigrate your hubris to mere arrogance or conceit.   :D

  • Upvote 1
Link to comment
Share on other sites

Here's a concrete example from another Undo scenario that may help clarify what I mean. In VisualStudio, copy a block of code from inside brackets (in an if block, for example). Paste it outside the brackets. Then undo it. What happens?

 

If I explained the steps clearly enough for you to do it the way I'm thinking, the code you pasted is still there after you undo, it's just indented more. Your undo didn't undo the last user action, it undid an automatic reformatting that the application did. It takes 2 undo actions to get rid of your 1 user action. And that's for a simple copy/paste in what is essentially a glorified text editor.

 

Now try applying that to the vast array of disparate functions you can do in editing a Helix patch. If you change an effect from one Drive to another, is that one action, or is it two? Does the Helix delete the block and then add the new one behind the scenes? If so, would a single undo leave you with an empty block, and the second undo give you back your original?

 

When you assign an action to a footswitch, you can overwrite the previous assignment. What if the assignment was a toggle for several other effects? The assignment you just did is probably two Helix actions (or more), Clear Assignment, Add Assignment. Undoing that, however, is more complicated. You probably have a Clear Assignment, and then a loop to Add Assignment for each of the previously assigned pedals. I highly doubt Helix can do a multi-assignment in a single message.

 

What if you move a block around? Each movement is probably a single action to undo on the Helix. Plus, if you go through/past/around other blocks, you might have Move Block actions for those other blocks all encapsulated in that one user action of moving a completely different block.

 

What if you move a block down to the second signal path, and that path was previously empty? You probably have some hidden Helix changes there to create the second signal path.

 

It's not an insurmountable problem, but you greatly oversimplified it and glossed over some tricky details. That's all I'm saying.

 

I oversimplified it to explain that you do not need changes to the Helix firmware in order to implement undo in the editor. Which was the point of my post..

 

Grouping undo changes is not hard, this can be done using a combination of timers and explicit grouping.

 

As I said this isn't rocket science, it is basics.

Link to comment
Share on other sites

I oversimplified it to explain that you do not need changes to the Helix firmware in order to implement undo in the editor. Which was the point of my post..

 

Grouping undo changes is not hard, this can be done using a combination of timers and explicit grouping.

 

As I said this isn't rocket science, it is basics.

Let's take a simple scenario. You have a full line of effects in your top chain. You have a single EQ pedal in the split chain. You delete that lone EQ pedal. What does the app need to store in order to undo that delete, and how does it restore that pedal?

 

The specific value changed is simple: Block Location + Effect ID. That's all the user is changing. But what do we need to store to undo it? What does the Helix do behind the scenes? For starters, the app needs to not just store the block location and effect ID, it needs to store all of the effect's parameters. But it goes beyond that.

 

To undo it, first it needs to create the pedal in the same spot, right? Except it can't, because as soon as that pedal is gone the empty chain disappears. You can't create a pedal in a block down there if the chain isn't there, you need to create it somewhere else and then move it. The app needs to know that. Ok, so it creates it in the chain above! Except that's full. Ok, so it finds an empty spot somewhere and creates in and then moves it. And then it has to go through and set each parameter.

 

And then there's stuff like the footswitch assignment. You can assign 8 things to a single footswitch. Handling undo on one to many relationships is fun! Difficult? Rocket science? No, of course not. I've had to do it before. It goes beyond the simple "store the old parameter and call SetValue on Undo". You need to understand how to handle each specific case.

 

Let's say you have 5 assignments, and the user calls AddAssignment, which passes in FootswitchID, BlockID, ParameterID, FootswitchOnValue, FootswitchOffValue, and Merge. So now you need to know that if they passed in Merge as true, Undo means you call RemoveAssignment (FootswitchID, BlockID) to go back to the original 5 assignments. Oh, hey, that message may not even exist! Is there a way to remove a single assignment from a footswitch that has several set? I don't know. So you may need to call ClearAllAssignments(FootswitchID) and then loop through and AddAssignment. Or you call AddAssignment for its first assignment with Merge set to false (which will internally ClearAllAssignments and then AddAssignment), and then AddAssignment for all the others with Merge set to true. It all depends on the Helix firmware and messaging and what commands are exposed to the outside world. Point being, we don't know.

 

And then you need to know how to handle it if Merge is false.

 

So really...is this rocket science? No, absolutely not. It's entirely doable. But the application needs to know how to do a lot of things that the firmware does automatically. It needs to understand the chain of events that each action would have. It may not be difficult, but neither is it trivial. It is, at best, tedious and time consuming, because they need to go through everything in the whole Helix and map out what steps are required to reverse everything the user can do, and that changes depending on the state of other things around it.

 

The only reasonable way to do it in the app would be to store the entire state of the patch for each undo, but again, that's resource-intensive.

Link to comment
Share on other sites

Let's take a simple scenario. You have a full line of effects in your top chain. You have a single EQ pedal in the split chain. You delete that lone EQ pedal. What does the app need to store in order to undo that delete, and how does it restore that pedal?

 

The specific value changed is simple: Block Location + Effect ID. That's all the user is changing. But what do we need to store to undo it? What does the Helix do behind the scenes? For starters, the app needs to not just store the block location and effect ID, it needs to store all of the effect's parameters. But it goes beyond that.

 

To undo it, first it needs to create the pedal in the same spot, right? Except it can't, because as soon as that pedal is gone the empty chain disappears. You can't create a pedal in a block down there if the chain isn't there, you need to create it somewhere else and then move it. The app needs to know that. Ok, so it creates it in the chain above! Except that's full. Ok, so it finds an empty spot somewhere and creates in and then moves it. And then it has to go through and set each parameter.

 

And then there's stuff like the footswitch assignment. You can assign 8 things to a single footswitch. Handling undo on one to many relationships is fun! Difficult? Rocket science? No, of course not. I've had to do it before. It goes beyond the simple "store the old parameter and call SetValue on Undo". You need to understand how to handle each specific case.

 

Let's say you have 5 assignments, and the user calls AddAssignment, which passes in FootswitchID, BlockID, ParameterID, FootswitchOnValue, FootswitchOffValue, and Merge. So now you need to know that if they passed in Merge as true, Undo means you call RemoveAssignment (FootswitchID, BlockID) to go back to the original 5 assignments. Oh, hey, that message may not even exist! Is there a way to remove a single assignment from a footswitch that has several set? I don't know. So you may need to call ClearAllAssignments(FootswitchID) and then loop through and AddAssignment. Or you call AddAssignment for its first assignment with Merge set to false (which will internally ClearAllAssignments and then AddAssignment), and then AddAssignment for all the others with Merge set to true. It all depends on the Helix firmware and messaging and what commands are exposed to the outside world. Point being, we don't know.

 

And then you need to know how to handle it if Merge is false.

 

So really...is this rocket science? No, absolutely not. It's entirely doable. But the application needs to know how to do a lot of things that the firmware does automatically. It needs to understand the chain of events that each action would have. It may not be difficult, but neither is it trivial. It is, at best, tedious and time consuming, because they need to go through everything in the whole Helix and map out what steps are required to reverse everything the user can do, and that changes depending on the state of other things around it.

 

The only reasonable way to do it in the app would be to store the entire state of the patch for each undo, but again, that's resource-intensive.

 

Lets look at this in a simple way, if the user can change something in the editor and then change it back in the editor then it is possible for an undo system in the editor to do the same irrespective of the device and it's firmware. The editor can render the structure of the patch and the parameters for each block therefore it has access to this data.

 

If the design of the Helix/computer interface is so bad that the only way to change something on the Helix is to emulate what a user would have to do on the hardware itself then the undo system would have to take this into account, no big deal.

 

Nothing about it is hard, it is just grunt work.

 

p.s. If the interface between the Helix/Computer is that bad you have to ask what they were thinking about when they designed it!

 

p.p.s. I just did a little test. The helix patches .hlx are pretty small and are text based so you could implement the undo system using these. The undo could just work on this data, when you undo it sends the saved undo .hlx data to the helix. whenever there has been a grouped change then save away the .hlx representation. If you need to save space then just store away the changes between his files with a full index .hlx every so often. Of course as the data is text anyway I don't see why the editor isn't using this interface anyway!

{
  "version" : 6,
  "data" : {
    "meta" : {
      "name" : "Stadium Rock",
      "application" : "Helix",
      "build_sha" : "69d8fa6",
      "modifieddate" : 1463155947,
      "appversion" : 17956864
    },
    "device" : 2162689,
    "tone" : {
      "dsp1" : {
        "join" : {
          "@model" : "HD2_AppDSPFlowJoin",
          "B Pan" : 1,
          "B Level" : -4,
          "A Level" : -4,
          "A Pan" : 0,
          "@position" : 4,
          "Level" : 0,
          "@enabled" : true,
          "B Polarity" : false
        },
        "block3" : {
          "@model" : "HD2_DelayPingPong",
          "@position" : 4,
          "Feedback" : 0.4,
          "LowCut" : 100,
          "SyncSelect1" : 6,
          "Scale" : 0.5,
          "@enabled" : true,
          "TempoSync1" : false,
          "@path" : 0,
          "@trails" : false,
          "@type" : 7,
          "Mix" : 0.23,
          "Time" : 0.6,
          "Level" : 0,
          "Spread" : 1,
          "HighCut" : 8900
        },
        "block2" : {
          "@model" : "HD2_Looper",
          "Overdub" : 0,
          "Playback" : 0,
          "@path" : 0,
          "@stereo" : false,
          "@type" : 6,
          "highCut" : 20000,
          "lowCut" : 20,
          "@position" : 7,
          "@enabled" : false
        },
        "inputB" : {
          "@input" : 0,
          "@model" : "HD2_AppDSPFlow2Input",
          "noiseGate" : false,
          "decay" : 0.5,
          "threshold" : -48
        },
        "block1" : {
          "@model" : "HD2_Cab4x12Greenback25",
          "Level" : 0.0999999,
          "LowCut" : 20,
          "@path" : 1,
          "@mic" : 0,
          "@type" : 2,
          "@position" : 5,
          "Distance" : 4,
          "EarlyReflections" : 0.17,
          "@enabled" : true,
          "HighCut" : 20000
        },
        "outputB" : {
          "@model" : "HD2_AppDSPFlowOutput",
          "@output" : 0,
          "pan" : 0.5,
          "gain" : 0
        },
        "inputA" : {
          "@input" : 0,
          "@model" : "HD2_AppDSPFlow1Input",
          "noiseGate" : false,
          "decay" : 0.5,
          "threshold" : -48
        },
        "split" : {
          "@position" : 0,
          "@model" : "HD2_AppDSPFlowSplitY",
          "@enabled" : true
        },
        "block0" : {
          "Bias" : 0.74,
          "@model" : "HD2_AmpSoloLeadOD",
          "Master" : 0.62,
          "@position" : 4,
          "Drive" : 0.8299999,
          "Treble" : 0.5,
          "ChVol" : 0.6,
          "@enabled" : true,
          "Ripple" : 0.5,
          "@path" : 1,
          "@type" : 1,
          "Bass" : 0.75,
          "BiasX" : 0.5,
          "Hum" : 0.5,
          "Mid" : 0.45,
          "@bypassvolume" : 1,
          "Presence" : 0.46,
          "Sag" : 0.21
        },
        "block5" : {
          "@model" : "HD2_VolPanVol",
          "@path" : 0,
          "@stereo" : true,
          "@type" : 0,
          "Pedal" : 1,
          "@position" : 6,
          "@enabled" : true,
          "VolumeTaper" : false
        },
        "outputA" : {
          "@model" : "HD2_AppDSPFlowOutput",
          "@output" : 1,
          "pan" : 0.5,
          "gain" : 0
        },
        "block4" : {
          "@model" : "HD2_ReverbChamber",
          "@position" : 5,
          "LowCut" : 143,
          "@enabled" : true,
          "@path" : 0,
          "@trails" : false,
          "@type" : 7,
          "Mix" : 0.39,
          "Level" : 0,
          "Decay" : 0.6600001,
          "HighCut" : 4700,
          "Predelay" : 0.1
        }
      },
      "global" : {
        "@variax_volumeknob" : -0.1,
        "@pedalstate" : 2,
        "@variax_customtuning" : true,
        "@variax_str1tuning" : 0,
        "@variax_str2tuning" : 0,
        "@variax_str4tuning" : 0,
        "@variax_str6tuning" : 0,
        "@variax_model" : 10,
        "@model" : "@global_params",
        "@topology0" : "SAB",
        "@cursor_dsp" : 0,
        "@cursor_path" : 0,
        "@tempo" : 120,
        "@topology1" : "ABJ",
        "@variax_magmode" : true,
        "@cursor_position" : 4,
        "@variax_lockctrls" : 0,
        "@variax_str3tuning" : 0,
        "@variax_str5tuning" : 0,
        "@variax_toneknob" : -0.1,
        "@cursor_group" : "block0"
      },
      "footswitch" : {
        "dsp1" : {
          "block4" : {
            "@fs_label" : "Chamber",
            "@fs_enabled" : true,
            "@fs_index" : 11,
            "@fs_ledcolor" : 16723200,
            "@fs_momentary" : false
          },
          "block5" : {
            "@fs_label" : "Volume Pedal",
            "@fs_enabled" : true,
            "@fs_index" : 13,
            "@fs_ledcolor" : 65408,
            "@fs_momentary" : false
          },
          "block2" : {
            "@fs_label" : "Looper",
            "@fs_enabled" : false,
            "@fs_index" : 5,
            "@fs_ledcolor" : 462860,
            "@fs_momentary" : false
          },
          "block3" : {
            "@fs_label" : "Ping Pong",
            "@fs_enabled" : true,
            "@fs_index" : 10,
            "@fs_ledcolor" : 458496,
            "@fs_momentary" : false
          }
        },
        "dsp0" : {
          "block4" : {
            "@fs_label" : "Minotaur",
            "@fs_enabled" : false,
            "@fs_index" : 8,
            "@fs_ledcolor" : 525824,
            "@fs_momentary" : false
          },
          "block6" : {
            "@fs_label" : "Tycoctavia Fuzz",
            "@fs_enabled" : false,
            "@fs_index" : 4,
            "@fs_ledcolor" : 525824,
            "@fs_momentary" : false
          },
          "block5" : {
            "@fs_label" : "Gray Flanger",
            "@fs_enabled" : false,
            "@fs_index" : 9,
            "@fs_ledcolor" : 1037,
            "@fs_momentary" : false
          }
        }
      },
      "dsp0" : {
        "join" : {
          "@model" : "HD2_AppDSPFlowJoin",
          "B Pan" : 0.5,
          "B Level" : 0,
          "A Level" : 0,
          "A Pan" : 0.5,
          "@position" : 8,
          "Level" : 0,
          "@enabled" : true,
          "B Polarity" : false
        },
        "block3" : {
          "@model" : "HD2_GateHardGate",
          "Decay" : 0.01,
          "@path" : 0,
          "@stereo" : false,
          "@type" : 0,
          "HoldTime" : 0.01,
          "OpenThreshold" : -50,
          "@position" : 0,
          "CloseThreshold" : -60,
          "Level" : 0,
          "@enabled" : true
        },
        "block2" : {
          "@model" : "HD2_VolPanVol",
          "@path" : 1,
          "@stereo" : false,
          "@type" : 0,
          "Pedal" : 1,
          "@position" : 7,
          "@enabled" : false,
          "VolumeTaper" : false
        },
        "inputB" : {
          "@input" : 0,
          "@model" : "HD2_AppDSPFlow2Input",
          "noiseGate" : false,
          "decay" : 0.5,
          "threshold" : -48
        },
        "block1" : {
          "@model" : "HD2_Cab4x12Greenback25",
          "Level" : 0,
          "LowCut" : 20,
          "@path" : 0,
          "@mic" : 2,
          "@type" : 2,
          "@position" : 5,
          "Distance" : 1,
          "EarlyReflections" : 0.3,
          "@enabled" : true,
          "HighCut" : 20000
        },
        "outputB" : {
          "@model" : "HD2_AppDSPFlowOutput",
          "@output" : 3,
          "pan" : 0.5,
          "gain" : 0
        },
        "inputA" : {
          "@input" : 1,
          "@model" : "HD2_AppDSPFlow1Input",
          "noiseGate" : false,
          "decay" : 0.5,
          "threshold" : -48
        },
        "block6" : {
          "@model" : "HD2_DistTycoctaviaFuzz",
          "Fuzz" : 0.75,
          "@path" : 0,
          "@stereo" : false,
          "@type" : 0,
          "@position" : 3,
          "Level" : 0.6700001,
          "@enabled" : false
        },
        "block0" : {
          "Bias" : 0.6,
          "@model" : "HD2_AmpCaliRectifire",
          "Master" : 0.45,
          "@position" : 4,
          "Drive" : 0.77,
          "Treble" : 0.6600001,
          "ChVol" : 0.5,
          "@enabled" : true,
          "Ripple" : 0.5,
          "@path" : 0,
          "@type" : 1,
          "Bass" : 0.34,
          "BiasX" : 0.48,
          "Hum" : 0.5,
          "Mid" : 0.34,
          "@bypassvolume" : 1,
          "Presence" : 0.5,
          "Sag" : 0.5
        },
        "split" : {
          "@position" : 4,
          "@model" : "HD2_AppDSPFlowSplitY",
          "@enabled" : true
        },
        "block5" : {
          "@model" : "HD2_FlangerGrayFlanger",
          "Rate" : 0.16,
          "@position" : 2,
          "Regen" : 0.5599999,
          "SyncSelect1" : 6,
          "TempoSync1" : false,
          "@enabled" : false,
          "@path" : 0,
          "@type" : 0,
          "Mix" : 0.5,
          "Headroom" : 0,
          "Width" : 0.78,
          "Level" : 0,
          "@stereo" : false,
          "Manual" : 0.78,
          "Spread" : 0.125
        },
        "outputA" : {
          "@model" : "HD2_AppDSPFlowOutput",
          "@output" : 2,
          "pan" : 0.5,
          "gain" : 0
        },
        "block4" : {
          "@model" : "HD2_DistMinotaur",
          "@path" : 0,
          "@stereo" : false,
          "@type" : 0,
          "Gain" : 0.42,
          "@position" : 1,
          "Level" : 0.35,
          "Tone" : 0.53,
          "@enabled" : false
        }
      },
      "controller" : {
        "dsp1" : {
          "block5" : {
            "Pedal" : {
              "@min" : 0,
              "@controller" : 2,
              "@max" : 1
            }
          }
        },
        "dsp0" : {
          "block2" : {
            "Pedal" : {
              "@min" : 0,
              "@controller" : 2,
              "@max" : 1
            }
          }
        }
      }
    },
    "device_version" : 17956896
  },
  "schema" : "L6Preset"
}
Link to comment
Share on other sites

Lets look at this in a simple way, if the user can change something in the editor and then change it back in the editor then it is possible for an undo system in the editor to do the same irrespective of the device and it's firmware. The editor can render the structure of the patch and the parameters for each block therefore it has access to this data.

 

If the design of the Helix/computer interface is so bad that the only way to change something on the Helix is to emulate what a user would have to do on the hardware itself then the undo system would have to take this into account, no big deal.

 

Nothing about it is hard, it is just grunt work.

 

p.s. If the interface between the Helix/Computer is that bad you have to ask what they were thinking about when they designed it!

Quite the contrary, in my opinion. It's actually good design that makes it so difficult. Encapsulation. Hiding data. Restricting access to functions. Exposing only that which the UI needs for a user to interact with the device. Handling the business logic in the lower levels and letting the UI worry about being a user interface. This is all good, standard practice that makes handling the undo in the UI much more difficult.

 

If you implement undo in the UI, you're giving them access to stuff they shouldn't have access to. You're duplicating logic that should all be handled at the lower levels. That would be bad design.

  • Upvote 1
Link to comment
Share on other sites

Quite the contrary, in my opinion. It's actually good design that makes it so difficult. Encapsulation. Hiding data. Restricting access to functions. Exposing only that which the UI needs for a user to interact with the device. Handling the business logic in the lower levels and letting the UI worry about being a user interface. This is all good, standard practice that makes handling the undo in the UI much more difficult.

 

If you implement undo in the UI, you're giving them access to stuff they shouldn't have access to. You're duplicating logic that should all be handled at the lower levels. That would be bad design.

 

I would not argue that this may perhaps be good design. However, having a hidden lower layer in a multi-tiered application in no way precludes having hooks to it that allow something along the order of what BobTheDog is proposing. Business logic is often embedded in an object layer with objects that have simple command structures for manipulating them. The lower level operations in the object are opaque to the end user, may be vastly more complex, and do the heavy lifting and things like enforcing data integrity and business logic, but those objects can be easily invoked and manipulated with simple commands from the upper layer. Many applications and of course operating systems work this way, otherwise every time you wanted to do any simple operation like moving a file you would be flipping bits one by one. My one caveat to BobTheDog would be advising restraint in actually making code level recommendations to L6 regarding implementation on too granular or specific a level. We simply do not have enough information on their architecture and code. However, ultimately in more general terms, I think he is on the right track.

Link to comment
Share on other sites

Having a hidden lower layer in a multi-tiered application in no way precludes having hooks to it that allow something along the order of what BobTheDog is proposing. Business logic is often embedded in an object layer with objects that have simple command structures for manipulating them. The lower level operations in the object are opaque to the end user and do the heavy lifting but can be easily invoked with simple commands from the upper layer.

Sure. And the appropriate hook to expose that allows this functionality would be "Undo". Which is not in the firmware. Which is the whole point of this. We're right back where we started, aren't we? Either a) the firmware needs to support Undo, or 2) the UI needs to understand the business logic (since there's no Undo in the firmware, there's no simple hook to expose here), or, option 3), which I already suggested as a possible solution, the UI handles Undo by loading restore points with the entire patch data.

Link to comment
Share on other sites

Sure. And the appropriate hook to expose that allows this functionality would be "Undo". Which is not in the firmware. Which is the whole point of this. We're right back where we started, aren't we? Either a) the firmware needs to support Undo, or 2) the UI needs to understand the business logic (since there's no Undo in the firmware, there's no simple hook to expose here), or, option 3), which I already suggested as a possible solution, the UI handles Undo by loading restore points with the entire patch data.

 

How do we know the hooks are not in the firmware already?

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...