1 #include "cmdhelp/multitrack.hpp"
2 #include "core/command.hpp"
3 #include "core/controller.hpp"
4 #include "core/dispatch.hpp"
5 #include "core/emustatus.hpp"
6 #include "core/instance.hpp"
7 #include "core/keymapper.hpp"
8 #include "core/movie.hpp"
9 #include "core/multitrack.hpp"
10 #include "lua/internal.hpp"
14 multitrack_edit::multitrack_edit(movie_logic
& _mlogic
, controller_state
& _controls
, emulator_dispatch
& _dispatch
,
15 status_updater
& _supdater
, button_mapping
& _buttons
, command::group
& _cmd
)
16 : mlogic(_mlogic
), controls(_controls
), edispatch(_dispatch
), supdater(_supdater
), buttons(_buttons
),
18 mt_f(cmd
, CMULTITRACK::f
, [this]() { this->do_mt_fwd(); }),
19 mt_b(cmd
, CMULTITRACK::b
, [this]() { this->do_mt_bw(); }),
20 mt_s(cmd
, CMULTITRACK::s
, [this](const std::string
& a
) { this->do_mt_set(a
); })
24 bool multitrack_edit::is_enabled()
29 void multitrack_edit::enable(bool state
)
32 threads::alock
h(mlock
);
34 controllerstate
.clear();
39 void multitrack_edit::set(unsigned port
, unsigned controller
, state s
)
42 threads::alock
h(mlock
);
43 controllerstate
[std::make_pair(port
, controller
)] = s
;
48 void multitrack_edit::set_and_notify(unsigned port
, unsigned controller
, state s
)
50 if(!mlogic
|| !mlogic
.get_movie().readonly_mode())
52 set(port
, controller
, s
);
53 edispatch
.multitrack_change(port
, controller
, (int)s
);
56 void multitrack_edit::rotate(bool forward
)
58 if(!mlogic
|| !mlogic
.get_movie().readonly_mode())
60 std::vector
<std::pair
<unsigned, unsigned>> x
;
61 for(unsigned i
= 0;; i
++) {
62 auto pcid
= controls
.lcid_to_pcid(i
);
65 x
.push_back(std::make_pair(pcid
.first
, pcid
.second
));
67 auto old_controllerstate
= controllerstate
;
68 for(unsigned i
= 0; i
< x
.size(); i
++) {
69 state s
= MT_PRESERVE
;
70 if(old_controllerstate
.count(x
[i
]))
71 s
= old_controllerstate
[x
[i
]];
82 controllerstate
[x
[i2
]] = s
;
83 edispatch
.multitrack_change(x
[i2
].first
, x
[i2
].second
, s
);
88 multitrack_edit::state
multitrack_edit::get(unsigned port
, unsigned controller
)
90 threads::alock
h(mlock
);
91 auto key
= std::make_pair(port
, controller
);
92 if(controllerstate
.count(key
))
93 return controllerstate
[key
];
97 void multitrack_edit::config_altered()
99 threads::alock
h(mlock
);
100 controllerstate
.clear();
103 void multitrack_edit::process_frame(portctrl::frame
& input
)
105 if(!mlogic
|| !mlogic
.get_movie().readonly_mode())
107 threads::alock
h(mlock
);
108 bool any_need
= false;
111 for(auto i
: controllerstate
)
112 any_need
= any_need
|| (i
.second
!= MT_PRESERVE
);
114 return; //No need to twiddle.
115 unsigned indices
= input
.get_index_count();
116 const portctrl::type_set
& portset
= input
.porttypes();
117 portctrl::counters
& p
= mlogic
.get_movie().get_pollcounters();
118 for(unsigned i
= 0; i
< indices
; i
++) {
119 portctrl::index_triple t
= portset
.index_to_triple(i
);
122 auto key
= std::make_pair(t
.port
, t
.controller
);
123 uint32_t pc
= p
.get_polls(i
);
124 if(!controllerstate
.count(key
) || controllerstate
[key
] == MT_PRESERVE
|| (!t
.port
&& !t
.controller
)) {
125 int16_t v
= mlogic
.get_movie().read_subframe_at_index(pc
, t
.port
, t
.controller
,
127 input
.axis3(t
.port
, t
.controller
, t
.control
, v
);
129 int16_t v
= mlogic
.get_movie().read_subframe_at_index(pc
, t
.port
, t
.controller
,
131 controllerstate
[key
];
132 const portctrl::type
& pt
= portset
.port_type(t
.port
);
133 auto pci
= pt
.controller_info
->get(t
.controller
);
134 auto pb
= pci
? pci
->get(t
.control
) : NULL
;
135 bool is_axis
= (pb
&& pb
->is_analog());
136 switch(controllerstate
[key
]) {
139 int16_t v2
= input
.axis3(t
.port
, t
.controller
, t
.control
);
143 v
|= input
.axis3(t
.port
, t
.controller
, t
.control
);
146 v
= input
.axis3(t
.port
, t
.controller
, t
.control
);
153 int16_t v2
= input
.axis3(t
.port
, t
.controller
, t
.control
);
157 v
^= input
.axis3(t
.port
, t
.controller
, t
.control
);
160 mlogic
.get_movie().write_subframe_at_index(pc
, t
.port
, t
.controller
, t
.control
,
162 v
= mlogic
.get_movie().read_subframe_at_index(pc
, t
.port
, t
.controller
,
164 input
.axis3(t
.port
, t
.controller
, t
.control
, v
);
169 bool multitrack_edit::any_records()
171 if(!mlogic
|| !mlogic
.get_movie().readonly_mode())
173 threads::alock
h(mlock
);
174 bool any_need
= false;
175 for(auto i
: controllerstate
)
176 any_need
= any_need
|| (i
.second
!= MT_PRESERVE
);
180 void multitrack_edit::do_mt_set(const std::string
& args
)
182 regex_results r
= regex("(.*)[ \t]+(.*)", args
);
184 throw std::runtime_error("Bad arguments");
185 auto c
= buttons
.byname(r
[1]);
187 throw std::runtime_error("No such controller");
189 set_and_notify(c
.first
, c
.second
, multitrack_edit::MT_PRESERVE
);
190 else if(r
[2] == "rewrite")
191 set_and_notify(c
.first
, c
.second
, multitrack_edit::MT_OVERWRITE
);
192 else if(r
[2] == "or")
193 set_and_notify(c
.first
, c
.second
, multitrack_edit::MT_OR
);
194 else if(r
[2] == "xor")
195 set_and_notify(c
.first
, c
.second
, multitrack_edit::MT_XOR
);
197 throw std::runtime_error("Invalid mode (keep, rewrite, or, xor)");
201 void multitrack_edit::do_mt_fwd()
207 void multitrack_edit::do_mt_bw()
215 int multitrack_state(lua::state
& L
, lua::parameters
& P
)
217 unsigned port
, controller
;
221 auto s
= CORE().mteditor
->get(port
, controller
);
223 case multitrack_edit::MT_OR
:
226 case multitrack_edit::MT_OVERWRITE
:
227 L
.pushstring("rewrite");
229 case multitrack_edit::MT_PRESERVE
:
230 L
.pushstring("keep");
232 case multitrack_edit::MT_XOR
:
240 lua::functions
LUA_mtfn(lua_func_misc
, "input", {
241 {"multitrack_state", multitrack_state
},