Nested/Conditional State Machine? (play/overdub/record/etc..)
So I'm building a looper based on the Line6 DL4 style transport control and I'm having a hard time figuring out how to manage the states/conditions.
There are 3 main buttons controlling 8 states, each one of which can go to 3 other states.
The states are :
Begin (initial state)
Record
Play
Stop
Overdub
Playonce
Playonce+overdub
Playone+return from overdub
(flowchart attached)
I built something similar in an Arduino (I needed 9 states there) and I had a separate bit of code that ran while in each state. I'm having a hard time translating that to max objects/logic.
The states seem relatively straight forward but 'playonce' throws a logical wrench in the works going to/from it behaves weirdly (from some states it restarts playback, others it doesn't, it times out in most states etc..)
I have a max patch I got on the forum years ago that's modelled on the DL4 that the logic completely breaks (I looked at it for inspiration, but it's not managing all of the possible states, and the ones that it does can break).
I built something using an 8 outlet gate as my main logic, with each outlet branching off into separate buttons each doing a set of commands and setting the gate to the next step in logic.
It's sort of working (not consistently) but it's a huge mess, and I've only populated half of the states.
Is there a better way to handle nested/conditional states than gate+route?
(I'm building it to be controlled by a monome hence the formatting of the button inputs. The looper core is also acting a bit funny as it sometimes crashes max (so any thoughts on why would be welcome too!))
I didn't look at your patch (too scared), but what I've done in the past is use value objects named appropriately (ie [v is_playing] or [v paused] to store the current state of your machine, and then enable/disable buttons or other controls (like menu items) according to the current state by interrogating the v objects whenever a state is changed by the user. You'd send bangs to value objects to interrogate them, and then use one or more [if] objects to construct some logic, to analyse the output of the value objects.
hth
if things are complex/very conditional you maybe can´t hide much behind simplicity, but maybe some sorting via conditional expressions ([if], [>], [!=] etc.) would lift it a bit. as well as doing some encapsulating.
@Terry so use a val object + if objects to kind of gate things. I sorted of tried getting [gate] to handle both the state management and routing in the example above.
@xh90 So having a comparison for every combination? if (state = 1) && (button = 2) then whatever?
The thing I had the hardest time dealing with was doing everything that needed to happen depending on what state I came from.
If someone can post an example of a conditional/nested state machine (ideally something transport related) that would be amazing.
well i don´t know the details of your plan (your patch and notes aren´t very inviting), but ususally you can group things a little bit (shared conditions). sorting, abstraction, etc.
but thats sth you gotta work out.
I'd suggest using a state transition table (matrix).
I put together a very simple state-machine example. I've separated the state machine description (the "state transition table" which @BROC mentions) from the subpatch that "drives" the state machine. I believe (as long as you stick to my "encoding" style) that you can load any state machine description (I use a "Moore state machine" description - see the linked-to web site). And then run it.
Although an experienced programmer, I am new to this playing field - so, don't trust that I've done things the "best" Max-way. I just picked the first thing that I got to work. Accordingly, any suggestions are more the welcome.