Loading ...
Sorry, an error occurred while loading the content.

Re: Undo and History in DX7 Voice Editing

Expand Messages
  • clementrp
    ... Thanks. What I ve done is different from what you suggest later on that one gesture equals one undo. E.g. if I adjust EG 1 Level 1, then listen to it a
    Message 1 of 8 , Mar 1, 2011
    • 0 Attachment
      --- In YamahaDX@yahoogroups.com, <RichardG@...> wrote:
      >
      > Hi,
      >
      > I'd say : any event between mouse-down and mouse-up only stores the start and end-value (unless there's no change so goinf from 45 to 99 to 00 and back to 45 doesn't change anything hence doesn't need to be stor

      Thanks. What I've done is different from what you suggest later on that one gesture equals one undo. E.g. if I adjust EG 1 Level 1, then listen to it a bit, and then adjust EG 1 Level 1 again, then the

      However, that's not going to work. As say someone edits coarse frequency for operator 3 and voila! their masterpiece is perfect. Then they fiddle with coarse frequency for operator 3 again, and the patch is ruined. My system will have merged both of these into a single "state", and the user won't be able to undo back to the masterpiece again. Not good enough.

      Unfortunately my interface often only has access to part of the DX7 patch being edited. E.g. the envelope sliders of operator 2 only have access to the data model for the envelope. No access to other parts of the voice. I've now either got to put in "gesture listeners" throughout the voice, or change my data model so that every slider has access to the whole voice, and can mark the start and end of gestures. The latter option being my preferred one. I think I went for the not-so-good undo model in a bit of hopeful optimism as it wouldn't make me go through all the currently over 16,000 lines of code and change it :)

      At least that will make more advanced editing, such as direct visual editing of envelopes and other things, much easier to make work with undo. So, there is a silver lining to the cloud.

      Cheers,

      Ross Clement
    • RichardG@Chello.NL
      Hi, I don t know how the code is setup but I suppose, since you mention an object-like approach (being able to access only a part of the voice-data), it s
      Message 2 of 8 , Mar 1, 2011
      • 0 Attachment
        Hi,

        I don't know how the code is setup but I suppose, since you mention an object-like approach (being able to access only a part of the voice-data), it's divided in logical pieces which you can reuse.
        I think every action/change should be stored, whether it's the same parameter or not.
        This will solve the problem you describe.
        One way to do it is to let every object keep track of it's own 'undo/redo-stack' and glue them together in an overall stack which points to the right object with the right undo.

        Let me give an example :

        Actual changes in real-time :
        12:00:00 AM -> eg 1 op 1 change from 2 to 3 -> store it in it's own object-undostack.
        12:00:03 AM -> choose different algorhyhtm -> store in it's undo stack
        12:00:15 AM -> eg 1 op 1 change from 3 to 2 -> store in it's undo stack

        so the eg 1 op 1 object will have 2 undo's : from 2 to 3 and from 3 to 2
        the algo-object will have 1 undo.

        the overall stack should only know about the time-stamps and objects so you can undo in the same order (but backwards) without actually knowing *what* the change was.
        The objects will know that for themselves -> every method-call to undo will pop the last one from it's stack.
        The objects themselves even wouldn't have to know any times since the stack will always be in the order of the changes.

        The 'main'-stack wouldn't have to have timestamps either but from a user perspective it might be a pointer to 'the-change-I-made-10-minutes-ago' :-)

        I think the beauty of the concept is the independence of the actual data.
        If you'd create a new object it would be completely self-contained wrt it's parameters and undo/redo stack.

        The 'main'-stack should only be told of an actual change.

        Does this help your problem of sifting thru 16k of code or did I just complicate it even more ?

        rg,rg

        ---- clementrp <rossclement@...> schreef:
        >
        >
        > --- In YamahaDX@yahoogroups.com, <RichardG@...> wrote:
        > >
        > > Hi,
        > >
        > > I'd say : any event between mouse-down and mouse-up only stores the start and end-value (unless there's no change so goinf from 45 to 99 to 00 and back to 45 doesn't change anything hence doesn't need to be stor
        >
        > Thanks. What I've done is different from what you suggest later on that one gesture equals one undo. E.g. if I adjust EG 1 Level 1, then listen to it a bit, and then adjust EG 1 Level 1 again, then the
        >
        > However, that's not going to work. As say someone edits coarse frequency for operator 3 and voila! their masterpiece is perfect. Then they fiddle with coarse frequency for operator 3 again, and the patch is ruined. My system will have merged both of these into a single "state", and the user won't be able to undo back to the masterpiece again. Not good enough.
        >
        > Unfortunately my interface often only has access to part of the DX7 patch being edited. E.g. the envelope sliders of operator 2 only have access to the data model for the envelope. No access to other parts of the voice. I've now either got to put in "gesture listeners" throughout the voice, or change my data model so that every slider has access to the whole voice, and can mark the start and end of gestures. The latter option being my preferred one. I think I went for the not-so-good undo model in a bit of hopeful optimism as it wouldn't make me go through all the currently over 16,000 lines of code and change it :)
        >
        > At least that will make more advanced editing, such as direct visual editing of envelopes and other things, much easier to make work with undo. So, there is a silver lining to the cloud.
        >
        > Cheers,
        >
        > Ross Clement
        >
        >
        >
        > ------------------------------------
        >
        > Yahoo! Groups Links
        >
        >
        >
      • charlie midi gfa
        16000 thats all ? kinda smalll so can you summerize what you want to do ? is it a list record of all changes made to a voice while ediitng or you just want
        Message 3 of 8 , Mar 1, 2011
        • 0 Attachment
          16000 thats all ? kinda smalll

          so can you summerize what you want to do ?
          is it a list record of all changes made to a voice while ediitng
          or you just want the original voice before editing
          \
          i am a coder myself this is a simple task from what i nake of the situation

          charles

          ----- Original Message -----
          From: <RichardG@...>
          To: <YamahaDX@yahoogroups.com>
          Cc: "clementrp" <rossclement@...>
          Sent: Tuesday, March 01, 2011 3:54 AM
          Subject: Re: [YamahaDX] Re: Undo and History in DX7 Voice Editing


          > Hi,
          >
          > I don't know how the code is setup but I suppose, since you mention an
          object-like approach (being able to access only a part of the voice-data),
          it's divided in logical pieces which you can reuse.
          > I think every action/change should be stored, whether it's the same
          parameter or not.
          > This will solve the problem you describe.
          > One way to do it is to let every object keep track of it's own
          'undo/redo-stack' and glue them together in an overall stack which points to
          the right object with the right undo.
          >
          > Let me give an example :
          >
          > Actual changes in real-time :
          > 12:00:00 AM -> eg 1 op 1 change from 2 to 3 -> store it in it's own
          object-undostack.
          > 12:00:03 AM -> choose different algorhyhtm -> store in it's undo stack
          > 12:00:15 AM -> eg 1 op 1 change from 3 to 2 -> store in it's undo stack
          >
          > so the eg 1 op 1 object will have 2 undo's : from 2 to 3 and from 3 to 2
          > the algo-object will have 1 undo.
          >
          > the overall stack should only know about the time-stamps and objects so
          you can undo in the same order (but backwards) without actually knowing
          *what* the change was.
          > The objects will know that for themselves -> every method-call to undo
          will pop the last one from it's stack.
          > The objects themselves even wouldn't have to know any times since the
          stack will always be in the order of the changes.
          >
          > The 'main'-stack wouldn't have to have timestamps either but from a user
          perspective it might be a pointer to 'the-change-I-made-10-minutes-ago' :-)
          >
          > I think the beauty of the concept is the independence of the actual data.
          > If you'd create a new object it would be completely self-contained wrt
          it's parameters and undo/redo stack.
          >
          > The 'main'-stack should only be told of an actual change.
          >
          > Does this help your problem of sifting thru 16k of code or did I just
          complicate it even more ?
          >
          > rg,rg
          >
          > ---- clementrp <rossclement@...> schreef:
          > >
          > >
          > > --- In YamahaDX@yahoogroups.com, <RichardG@...> wrote:
          > > >
          > > > Hi,
          > > >
          > > > I'd say : any event between mouse-down and mouse-up only stores the
          start and end-value (unless there's no change so goinf from 45 to 99 to 00
          and back to 45 doesn't change anything hence doesn't need to be stor
          > >
          > > Thanks. What I've done is different from what you suggest later on that
          one gesture equals one undo. E.g. if I adjust EG 1 Level 1, then listen to
          it a bit, and then adjust EG 1 Level 1 again, then the
          > >
          > > However, that's not going to work. As say someone edits coarse frequency
          for operator 3 and voila! their masterpiece is perfect. Then they fiddle
          with coarse frequency for operator 3 again, and the patch is ruined. My
          system will have merged both of these into a single "state", and the user
          won't be able to undo back to the masterpiece again. Not good enough.
          > >
          > > Unfortunately my interface often only has access to part of the DX7
          patch being edited. E.g. the envelope sliders of operator 2 only have access
          to the data model for the envelope. No access to other parts of the voice.
          I've now either got to put in "gesture listeners" throughout the voice, or
          change my data model so that every slider has access to the whole voice, and
          can mark the start and end of gestures. The latter option being my preferred
          one. I think I went for the not-so-good undo model in a bit of hopeful
          optimism as it wouldn't make me go through all the currently over 16,000
          lines of code and change it :)
          > >
          > > At least that will make more advanced editing, such as direct visual
          editing of envelopes and other things, much easier to make work with undo.
          So, there is a silver lining to the cloud.
          > >
          > > Cheers,
          > >
          > > Ross Clement
          > >
          > >
          > >
          > > ------------------------------------
          > >
          > > Yahoo! Groups Links
          > >
          > >
          > >
          >
          >
          >
          > ------------------------------------
          >
          > Yahoo! Groups Links
          >
          >
          >
          >
        • clementrp
          ... Thanks. I ve added a whole subsystem by which gestures can be marked and named. This is already by some margin the most sophisticated and complex
          Message 4 of 8 , Mar 2, 2011
          • 0 Attachment
            --- In YamahaDX@yahoogroups.com, <RichardG@...> wrote:
            >
            > Hi,
            >
            > I don't know how the code is setup but I suppose, since you mention an object-like approach (being able to access only a part of the voice-data), it's divided in logical pieces which you can reuse.
            > I think every action/change should be stored, whether it's the same parameter or not.
            > This will solve the problem you describe.
            > One way to do it is to let every object keep track of it's own 'undo/redo-stack' and glue them together in an overall stack which points to the right object with the right undo.
            >
            > Let me give an example :
            >
            > Actual changes in real-time :
            > 12:00:00 AM -> eg 1 op 1 change from 2 to 3 -> store it in it's own object-undostack.
            > 12:00:03 AM -> choose different algorhyhtm -> store in it's undo stack
            > 12:00:15 AM -> eg 1 op 1 change from 3 to 2 -> store in it's undo stack
            >
            > so the eg 1 op 1 object will have 2 undo's : from 2 to 3 and from 3 to 2
            > the algo-object will have 1 undo.
            >
            > the overall stack should only know about the time-stamps and objects so you can undo in the same order (but backwards) without actually knowing *what* the change was.
            > The objects will know that for themselves -> every method-call to undo will pop the last one from it's stack.
            > The objects themselves even wouldn't have to know any times since the stack will always be in the order of the changes.
            >
            > The 'main'-stack wouldn't have to have timestamps either but from a user perspective it might be a pointer to 'the-change-I-made-10-minutes-ago' :-)
            >
            > I think the beauty of the concept is the independence of the actual data.
            > If you'd create a new object it would be completely self-contained wrt it's parameters and undo/redo stack.
            >
            > The 'main'-stack should only be told of an actual change.
            >
            > Does this help your problem of sifting thru 16k of code or did I just complicate it even more ?
            >
            > rg,rg

            Thanks. I've added a whole subsystem by which gestures can be marked and named. This is already by some margin the most sophisticated and complex undo/history system I've ever written.

            The DX7VoiceModel object (which stores the patch values) maintains its own history list. I do this because my software can edit 32 (may change later) voices at once. So, I need the software to switch history lists when the user switches voices.

            My software has a plugin interface. And even the default interface has multiple windows, with control of overlapping parameters. The design is that plugins will automatically use the main editing windows code to (e.g.) keep the edit buffer of the connected TX up to date, and all interfaces showing the same data. So, data gets passed around quite a lot, and changes to history can come from different sources acting in quite different ways. And, the history window not only has to show the history, but also has to name each step in an easily understood form. The gesture event strategy, while complicated, helps with this a lot. When gesture events are generated, they are either named or unnamed. And, if they are named, that becomes the name for the history list. So, single gestures that change multiple parameters can be named. And, as of yet unknown plugins that work in unknown ways can name their actions if they want.

            There was a fair amount of code to add, and it's not fully finished yet. But, I think this is the way forward. Some of the more obvious methods for doing this wouldn't work on further consideration. E.g. making the DX7VoiceModel itself be the listener for history. Because that would mean that when the user changes to different voices I would have to manually de-register the previous voice from all GUI things that can generate events, and then register the new one. Also, there are deliberate side effects when some things happen. E.g. if a plugin changes some values, then it generates a voice updated event. This is caught, and the man GUI is told to update its sliders and other things. Updating the sliders and other things causes, if the value of a parameter has changed, MIDI messages to be sent that update the TX. This is what changes the TX (or DX of course) edit buffer when patches are changed, etc. But, before I looked into things further, an early bug was that when I changed patches, it generated a whole bunch of undos for the new patch, one for each parameter that was different from the old patch. That was quickly fixed, but it's an example of what makes this undo/history functionality more complicated than any I've done before. But, I think I have it done now.

            Using events marking start and end of gestures helps with this a lot. Plugins can generate gestures which they police and name themselves. Also, gestures can group multiple parameter changes into a single change). One thing I dislike with some graphic plugins for The Gimp and similar software is where you apply a plugin to an image, but when you try to undo, you end up undoing all the individual steps that the plugin used to change the image.

            BTW: each step in the history stores an entire DX7 voice. It's only 157 parameters (155 + operator on/off + operators selected), so even with long histories, it doesn't take up much space. Storing a single changed parameter won't work as some gestures change multiple parameters. E.g. I can load or save LFOs and other things independent of the rest of the voice. If I need to, I can create a compressed form of a "change" later on.

            Regards,

            Ross
          • clementrp
            ... There s a big long description of the evolving specification in the discussion with Richard. In short, the actual history record itself isn t tricky at
            Message 5 of 8 , Mar 2, 2011
            • 0 Attachment
              --- In YamahaDX@yahoogroups.com, charlie midi gfa <charles.copp@...> wrote:
              > so can you summerize what you want to do ?
              > is it a list record of all changes made to a voice while ediitng
              > or you just want the original voice before editing
              > \
              > i am a coder myself this is a simple task from what i nake of the situation

              There's a big long description of the evolving specification in the discussion with Richard.

              In short, the actual history record itself isn't tricky at all. I just store a number of previous voices (all parameters), each named in a way to identify what change was made. E.g. if a voice was changed by changing EG Rate 1 to 99, then the name might be "EG Rate 1 = 99". That much is trivial.

              The slightly more complicated bit is in deciding in which changes should be grouped under a single name, and backtracked with a single undo (or redone with a single redo), and what this name should be. As per the conversation with Richard, this is now based on single gestures.

              The much more complicated bit is how different windows, some plugins, can change the same underlying voice in different ways, some changing multiple parameters at once. And how this can sensibly be worked into a single "history" subsystem, which works sensibly, given that we also need to keep the edit buffer of an attached TX7 up to date. This is where the heavily object orientated event and event listener strategy as described in the other email comes from. It looks very complicated, but I want to eventually have a base system for which it's very easy to write plugins, with these plugins looking at new models of synth programming, and integrated with the rest of the system (history, etc.). And that requires something more robust and in particular adaptive compared to the simple and straightforward methods.

              But, I think I've cracked it now. Maybe.

              Regards,

              Ross Clement
            • charlie midi gfa
              well you are at a eveloutionary point use this to your avantage and invent something! i see you want a list of changes , why not invent the circular buffer? as
              Message 6 of 8 , Mar 2, 2011
              • 0 Attachment
                well you are at a eveloutionary point
                use this to your avantage and invent something!

                i see you want a list of changes , why not invent the circular buffer?

                as long as users know that the history is tracked ,invent a buffer for each
                parameter
                and save each value everytime changed

                but i have creative input,, use say 64 places in the buffer , once 64
                changes have been made , it will start from 1 again wring over existing
                entries(and make3 so user can scroll thru the changes popup menu???)

                but this is insane , all this can be avoided if you just imploy a save voice
                button thats easily accessable
                evey time the user finds something to their liking ,
                keyboard 'ctrl + s' done , don't like it don't save it .....

                is ponder still a word?

                charles


                ----- Original Message -----
                From: "clementrp" <rossclement@...>
                To: <YamahaDX@yahoogroups.com>
                Sent: Wednesday, March 02, 2011 5:55 AM
                Subject: [YamahaDX] Re: Undo and History in DX7 Voice Editing


                >
                >
                > --- In YamahaDX@yahoogroups.com, charlie midi gfa <charles.copp@...>
                wrote:
                > > so can you summerize what you want to do ?
                > > is it a list record of all changes made to a voice while ediitng
                > > or you just want the original voice before editing
                > > \
                > > i am a coder myself this is a simple task from what i nake of the
                situation
                >
                > There's a big long description of the evolving specification in the
                discussion with Richard.
                >
                > In short, the actual history record itself isn't tricky at all. I just
                store a number of previous voices (all parameters), each named in a way to
                identify what change was made. E.g. if a voice was changed by changing EG
                Rate 1 to 99, then the name might be "EG Rate 1 = 99". That much is trivial.
                >
                > The slightly more complicated bit is in deciding in which changes should
                be grouped under a single name, and backtracked with a single undo (or
                redone with a single redo), and what this name should be. As per the
                conversation with Richard, this is now based on single gestures.
                >
                > The much more complicated bit is how different windows, some plugins, can
                change the same underlying voice in different ways, some changing multiple
                parameters at once. And how this can sensibly be worked into a single
                "history" subsystem, which works sensibly, given that we also need to keep
                the edit buffer of an attached TX7 up to date. This is where the heavily
                object orientated event and event listener strategy as described in the
                other email comes from. It looks very complicated, but I want to eventually
                have a base system for which it's very easy to write plugins, with these
                plugins looking at new models of synth programming, and integrated with the
                rest of the system (history, etc.). And that requires something more robust
                and in particular adaptive compared to the simple and straightforward
                methods.
                >
                > But, I think I've cracked it now. Maybe.
                >
                > Regards,
                >
                > Ross Clement
                >
                >
                >
                > ------------------------------------
                >
                > Yahoo! Groups Links
                >
                >
                >
                >
              Your message has been successfully submitted and would be delivered to recipients shortly.