2 #include "core/command.hpp"
3 #include "core/controller.hpp"
4 #include "core/dispatch.hpp"
5 #include "core/keymapper.hpp"
6 #include "core/moviedata.hpp"
7 #include "core/multitrack.hpp"
8 #include "lua/internal.hpp"
10 void update_movie_state();
12 bool multitrack_edit::is_enabled()
17 void multitrack_edit::enable(bool state
)
20 threads::alock
h(mlock
);
22 controllerstate
.clear();
27 void multitrack_edit::set(unsigned port
, unsigned controller
, state s
)
30 threads::alock
h(mlock
);
31 controllerstate
[std::make_pair(port
, controller
)] = s
;
36 void multitrack_edit::set_and_notify(unsigned port
, unsigned controller
, state s
)
38 if(!movb
|| !movb
.get_movie().readonly_mode())
40 set(port
, controller
, s
);
41 notify_multitrack_change(port
, controller
, (int)s
);
44 void multitrack_edit::rotate(bool forward
)
46 if(!movb
|| !movb
.get_movie().readonly_mode())
48 std::vector
<std::pair
<unsigned, unsigned>> x
;
49 for(unsigned i
= 0;; i
++) {
50 auto pcid
= controls
.lcid_to_pcid(i
);
53 x
.push_back(std::make_pair(pcid
.first
, pcid
.second
));
55 auto old_controllerstate
= controllerstate
;
56 for(unsigned i
= 0; i
< x
.size(); i
++) {
57 state s
= MT_PRESERVE
;
58 if(old_controllerstate
.count(x
[i
]))
59 s
= old_controllerstate
[x
[i
]];
70 controllerstate
[x
[i2
]] = s
;
71 notify_multitrack_change(x
[i2
].first
, x
[i2
].second
, s
);
76 multitrack_edit::state
multitrack_edit::get(unsigned port
, unsigned controller
)
78 threads::alock
h(mlock
);
79 auto key
= std::make_pair(port
, controller
);
80 if(controllerstate
.count(key
))
81 return controllerstate
[key
];
85 void multitrack_edit::config_altered()
87 threads::alock
h(mlock
);
88 controllerstate
.clear();
91 void multitrack_edit::process_frame(controller_frame
& input
)
93 if(!movb
|| !movb
.get_movie().readonly_mode())
95 threads::alock
h(mlock
);
96 bool any_need
= false;
99 for(auto i
: controllerstate
)
100 any_need
= any_need
|| (i
.second
!= MT_PRESERVE
);
102 return; //No need to twiddle.
103 unsigned indices
= input
.get_index_count();
104 const port_type_set
& portset
= input
.porttypes();
105 pollcounter_vector
& p
= movb
.get_movie().get_pollcounters();
106 for(unsigned i
= 0; i
< indices
; i
++) {
107 port_index_triple t
= portset
.index_to_triple(i
);
110 auto key
= std::make_pair(t
.port
, t
.controller
);
111 uint32_t pc
= p
.get_polls(i
);
112 if(!controllerstate
.count(key
) || controllerstate
[key
] == MT_PRESERVE
|| (!t
.port
&& !t
.controller
)) {
113 int16_t v
= movb
.get_movie().read_subframe_at_index(pc
, t
.port
, t
.controller
, t
.control
);
114 input
.axis3(t
.port
, t
.controller
, t
.control
, v
);
116 int16_t v
= movb
.get_movie().read_subframe_at_index(pc
, t
.port
, t
.controller
, t
.control
);
117 controllerstate
[key
];
118 const port_type
& pt
= portset
.port_type(t
.port
);
119 auto pci
= pt
.controller_info
->get(t
.controller
);
120 auto pb
= pci
? pci
->get(t
.control
) : NULL
;
121 bool is_axis
= (pb
&& pb
->is_analog());
122 switch(controllerstate
[key
]) {
125 int16_t v2
= input
.axis3(t
.port
, t
.controller
, t
.control
);
129 v
|= input
.axis3(t
.port
, t
.controller
, t
.control
);
132 v
= input
.axis3(t
.port
, t
.controller
, t
.control
);
139 int16_t v2
= input
.axis3(t
.port
, t
.controller
, t
.control
);
143 v
^= input
.axis3(t
.port
, t
.controller
, t
.control
);
146 movb
.get_movie().write_subframe_at_index(pc
, t
.port
, t
.controller
, t
.control
, v
);
147 v
= movb
.get_movie().read_subframe_at_index(pc
, t
.port
, t
.controller
, t
.control
);
148 input
.axis3(t
.port
, t
.controller
, t
.control
, v
);
153 bool multitrack_edit::any_records()
155 if(!movb
|| !movb
.get_movie().readonly_mode())
157 threads::alock
h(mlock
);
158 bool any_need
= false;
159 for(auto i
: controllerstate
)
160 any_need
= any_need
|| (i
.second
!= MT_PRESERVE
);
166 command::fnptr
<> rotate_forward(lsnes_cmd
, "rotate-multitrack", "Rotate multitrack",
167 "Syntax: rotate-multitrack\nRotate multitrack\n",
168 []() throw(std::bad_alloc
, std::runtime_error
) {
169 multitrack_editor
.rotate(true);
170 update_movie_state();
173 command::fnptr
<> rotate_backward(lsnes_cmd
, "rotate-multitrack-backwards", "Rotate multitrack backwards",
174 "Syntax: rotate-multitrack-backwards\nRotate multitrack backwards\n",
175 []() throw(std::bad_alloc
, std::runtime_error
) {
176 multitrack_editor
.rotate(false);
177 update_movie_state();
180 command::fnptr
<const std::string
&> set_mt(lsnes_cmd
, "set-multitrack", "Set multitrack mode",
181 "Syntax: set-multitrack <controller> <mode>\nSet multitrack mode\n",
182 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
183 regex_results r
= regex("(.*)[ \t]+(.*)", args
);
185 throw std::runtime_error("Bad arguments");
186 auto c
= controller_by_name(r
[1]);
188 throw std::runtime_error("No such controller");
190 multitrack_editor
.set_and_notify(c
.first
, c
.second
, multitrack_edit::MT_PRESERVE
);
191 else if(r
[2] == "rewrite")
192 multitrack_editor
.set_and_notify(c
.first
, c
.second
, multitrack_edit::MT_OVERWRITE
);
193 else if(r
[2] == "or")
194 multitrack_editor
.set_and_notify(c
.first
, c
.second
, multitrack_edit::MT_OR
);
195 else if(r
[2] == "xor")
196 multitrack_editor
.set_and_notify(c
.first
, c
.second
, multitrack_edit::MT_XOR
);
198 throw std::runtime_error("Invalid mode (keep, rewrite, or, xor)");
199 update_movie_state();
202 keyboard::invbind
_mtback(lsnes_mapper
, "rotate-multitrack-backwards", "Multitrack‣Rotate backwards");
203 keyboard::invbind
_mtfwd(lsnes_mapper
, "rotate-multitrack", "Multitrack‣Rotate forward");
205 int multitrack_state(lua::state
& L
, lua::parameters
& P
)
207 unsigned port
, controller
;
211 auto s
= multitrack_editor
.get(port
, controller
);
213 case multitrack_edit::MT_OR
:
216 case multitrack_edit::MT_OVERWRITE
:
217 L
.pushstring("rewrite");
219 case multitrack_edit::MT_PRESERVE
:
220 L
.pushstring("keep");
222 case multitrack_edit::MT_XOR
:
230 lua::functions
mtfn(lua_func_misc
, "input", {
231 {"multitrack_state", multitrack_state
},
235 multitrack_edit multitrack_editor
;