10 #define FLAG_SYNC CONTROL_FRAME_SYNC
12 std::string global_rerecord_count
= "0";
13 //std::ofstream debuglog("movie-debugging-log", std::ios::out | std::ios::app);
17 void hash_string(uint8_t* res
, const std::string
& s
) throw(std::bad_alloc
)
21 std::copy(s
.begin(), s
.end(), t
.begin());
25 uint8_t* enlarge(std::vector
<uint8_t>& v
, size_t amount
) throw(std::bad_alloc
)
32 inline void write64(uint8_t* buffer
, uint64_t value
) throw()
34 buffer
[0] = value
>> 56;
35 buffer
[1] = value
>> 48;
36 buffer
[2] = value
>> 40;
37 buffer
[3] = value
>> 32;
38 buffer
[4] = value
>> 24;
39 buffer
[5] = value
>> 16;
40 buffer
[6] = value
>> 8;
44 inline void write32(uint8_t* buffer
, uint32_t value
) throw()
46 buffer
[0] = value
>> 24;
47 buffer
[1] = value
>> 16;
48 buffer
[2] = value
>> 8;
52 inline uint32_t read32(const uint8_t* buffer
) throw()
54 return (static_cast<uint32_t>(buffer
[0]) << 24) |
55 (static_cast<uint32_t>(buffer
[1]) << 16) |
56 (static_cast<uint32_t>(buffer
[2]) << 8) |
57 (static_cast<uint32_t>(buffer
[3]));
60 inline uint64_t read64(const uint8_t* buffer
) throw()
62 return (static_cast<uint64_t>(buffer
[0]) << 56) |
63 (static_cast<uint64_t>(buffer
[1]) << 48) |
64 (static_cast<uint64_t>(buffer
[2]) << 40) |
65 (static_cast<uint64_t>(buffer
[3]) << 32) |
66 (static_cast<uint64_t>(buffer
[4]) << 24) |
67 (static_cast<uint64_t>(buffer
[5]) << 16) |
68 (static_cast<uint64_t>(buffer
[6]) << 8) |
69 (static_cast<uint64_t>(buffer
[7]));
72 inline void write16s(uint8_t* buffer
, int16_t x
) throw()
74 uint16_t y
= static_cast<uint16_t>(x
);
79 void hash_subframe(sha256
& ctx
, const controls_t
& ctrl
) throw()
81 uint8_t buf
[2 * TOTAL_CONTROLS
];
82 for(unsigned i
= 0; i
< TOTAL_CONTROLS
; i
++)
83 write16s(buf
+ 2 * i
, ctrl(i
));
84 ctx
.write(buf
, 2 * TOTAL_CONTROLS
);
87 //Hashes frame and returns starting subframe of next frame.
88 uint64_t hash_frame(sha256
& ctx
, std::vector
<controls_t
>& input
, uint64_t first_subframe
,
89 uint32_t bound
) throw()
92 //Ignore this frame completely.
93 if(first_subframe
>= input
.size())
94 return first_subframe
;
96 while(first_subframe
< input
.size() && !input
[first_subframe
](CONTROL_FRAME_SYNC
))
98 return first_subframe
;
100 if(first_subframe
>= input
.size()) {
101 //Hash an empty frame.
102 hash_subframe(ctx
, controls_t(true));
103 return first_subframe
;
106 uint64_t subframes_to_hash
= 1;
107 uint64_t last_differing
= 1;
109 controls_t prev
= input
[first_subframe
];
110 prev(CONTROL_FRAME_SYNC
) = 0;
112 while(first_subframe
+ subframes_to_hash
< input
.size() && !input
[first_subframe
+ subframes_to_hash
]
113 (CONTROL_FRAME_SYNC
)) {
114 if(!(input
[first_subframe
+ subframes_to_hash
] == prev
))
115 last_differing
= subframes_to_hash
+ 1;
116 prev
= input
[first_subframe
+ subframes_to_hash
];
119 next
= first_subframe
+ subframes_to_hash
;
120 subframes_to_hash
= last_differing
;
121 for(uint64_t i
= 0; i
< subframes_to_hash
&& i
< bound
; i
++)
122 hash_subframe(ctx
, input
[first_subframe
+ i
]);
126 void hash_movie(uint8_t* res
, uint64_t current_frame
, uint32_t* pollcounters
,
127 std::vector
<controls_t
>& input
) throw(std::bad_alloc
)
130 //If current_frame == 0, hash is empty.
136 uint64_t current_subframe
= 0;
137 for(uint64_t i
= 1; i
< current_frame
; i
++)
138 current_subframe
= hash_frame(ctx
, input
, current_subframe
, 0x7FFFFFFF);
139 //Current frame is special.
140 for(size_t i
= 0; i
< TOTAL_CONTROLS
; i
++) {
141 uint32_t polls
= pollcounters
[i
] & 0x7FFFFFFF;
142 uint32_t last_seen
= 0;
143 for(size_t j
= 0; j
< polls
; j
++) {
144 if(current_subframe
+ j
< input
.size() && !input
[current_subframe
+ j
]
145 (CONTROL_FRAME_SYNC
))
146 last_seen
= input
[current_subframe
+ j
](i
);
148 write16s(buf
, last_seen
);
156 void movie::set_all_DRDY() throw()
158 for(size_t i
= 0; i
< TOTAL_CONTROLS
; i
++)
159 pollcounters
[i
] |= 0x80000000UL
;
162 std::string
movie::rerecord_count() throw(std::bad_alloc
)
167 void movie::rerecord_count(const std::string
& count
) throw(std::bad_alloc
)
172 std::string
movie::project_id() throw(std::bad_alloc
)
177 void movie::project_id(const std::string
& id
) throw(std::bad_alloc
)
182 bool movie::readonly_mode() throw()
187 short movie::next_input(unsigned port
, unsigned controller
, unsigned index
) throw(std::bad_alloc
, std::logic_error
)
189 return next_input(ccindex2(port
, controller
, index
));
192 void movie::set_controls(controls_t controls
) throw()
194 current_controls
= controls
;
197 uint32_t movie::count_changes(uint64_t first_subframe
)
199 if(first_subframe
>= movie_data
.size())
202 while(first_subframe
+ ret
< movie_data
.size() && !movie_data
[first_subframe
+ ret
](CONTROL_FRAME_SYNC
))
207 controls_t
movie::get_controls() throw()
210 return current_controls
;
212 //Before the beginning? Somebody screwed up (but return released / neutral anyway)...
213 if(current_frame
== 0)
215 //Otherwise find the last valid frame of input.
216 uint32_t changes
= count_changes(current_frame_first_subframe
);
218 return c
; //End of movie.
219 for(size_t i
= 0; i
< TOTAL_CONTROLS
; i
++) {
220 uint32_t polls
= pollcounters
[i
] & 0x7FFFFFFF;
221 uint32_t index
= (changes
> polls
) ? polls
: changes
- 1;
222 c(i
) = movie_data
[current_frame_first_subframe
+ index
](i
);
227 uint64_t movie::get_current_frame() throw()
229 return current_frame
;
232 uint64_t movie::get_lag_frames() throw()
237 uint64_t movie::get_frame_count() throw()
239 return frames_in_movie
;
242 void movie::next_frame() throw(std::bad_alloc
)
244 //If all poll counters are zero for all real controls, this frame is lag.
245 bool this_frame_lag
= true;
246 for(size_t i
= MAX_SYSTEM_CONTROLS
; i
< TOTAL_CONTROLS
; i
++)
247 if(pollcounters
[i
] & 0x7FFFFFFF)
248 this_frame_lag
= false;
249 //Hack: Reset frames must not be considered lagged, so we abuse pollcounter bit for reset to mark those.
250 if(pollcounters
[CONTROL_SYSTEM_RESET
] & 0x7FFFFFFF)
251 this_frame_lag
= false;
252 //Oh, frame 0 must not be considered lag.
253 if(current_frame
&& this_frame_lag
) {
255 //debuglog << "Frame " << current_frame << " is lag" << std::endl << std::flush;
257 //If in read-write mode, write a dummy record for the frame. Force sync flag.
258 //As index should be movie_data.size(), it is correct afterwards.
259 controls_t c
= current_controls
;
260 c(CONTROL_FRAME_SYNC
) = 1;
261 movie_data
.push_back(c
);
266 //Reset the poll counters and DRDY flags.
267 for(unsigned i
= 0; i
< TOTAL_CONTROLS
; i
++)
270 //Increment the current frame counter and subframe counter. Note that first subframe is undefined for
271 //frame 0 and 0 for frame 1.
273 current_frame_first_subframe
= current_frame_first_subframe
+
274 count_changes(current_frame_first_subframe
);
276 current_frame_first_subframe
= 0;
280 bool movie::get_DRDY(unsigned controlindex
) throw(std::logic_error
)
282 if(controlindex
>= TOTAL_CONTROLS
)
283 throw std::logic_error("movie::get_DRDY: Bad index");
284 return ((pollcounters
[controlindex
] & 0x80000000UL
) != 0);
287 bool movie::get_DRDY(unsigned port
, unsigned controller
, unsigned index
) throw(std::logic_error
)
289 return get_DRDY(ccindex2(port
, controller
, index
));
292 short movie::next_input(unsigned controlindex
) throw(std::bad_alloc
, std::logic_error
)
294 //Check validity of index.
295 if(controlindex
== FLAG_SYNC
)
297 if(controlindex
>= TOTAL_CONTROLS
)
298 throw std::logic_error("movie::next_input: Invalid control index");
300 //Clear the DRDY flag.
301 pollcounters
[controlindex
] &= 0x7FFFFFFF;
304 //In readonly mode...
305 //If at the end of the movie, return released / neutral (but also record the poll)...
306 if(current_frame_first_subframe
>= movie_data
.size()) {
307 pollcounters
[controlindex
]++;
310 //Before the beginning? Somebody screwed up (but return released / neutral anyway)...
311 if(current_frame
== 0)
313 //Otherwise find the last valid frame of input.
314 uint32_t changes
= count_changes(current_frame_first_subframe
);
315 uint32_t polls
= (pollcounters
[controlindex
]++) & 0x7FFFFFFF;
316 uint32_t index
= (changes
> polls
) ? polls
: changes
- 1;
317 //debuglog << "Frame=" << current_frame << " Subframe=" << polls << " control=" << controlindex << " value=" << movie_data[current_frame_first_subframe + index](controlindex) << " fetchrow=" << current_frame_first_subframe + index << std::endl << std::flush;
318 return movie_data
[current_frame_first_subframe
+ index
](controlindex
);
321 //Before the beginning? Somebody screwed up (but return released / neutral anyway)...
322 //Also, frame 0 must not be added to movie file.
323 if(current_frame
== 0)
325 //If at movie end, insert complete input with frame sync set (this is the first subframe).
326 if(current_frame_first_subframe
>= movie_data
.size()) {
327 controls_t c
= current_controls
;
328 c(CONTROL_FRAME_SYNC
) = 1;
329 movie_data
.push_back(c
);
330 //current_frame_first_subframe should be movie_data.size(), so it is right.
331 pollcounters
[controlindex
]++;
333 assert(pollcounters
[controlindex
] == 1);
334 //debuglog << "Frame=" << current_frame << " Subframe=" << (pollcounters[controlindex] - 1) << " control=" << controlindex << " value=" << movie_data[current_frame_first_subframe](controlindex) << " fetchrow=" << current_frame_first_subframe << std::endl << std::flush;
335 return movie_data
[current_frame_first_subframe
](controlindex
);
337 short new_value
= current_controls(controlindex
);
338 //Fortunately, we know this frame is the last one in movie_data.
339 uint32_t pollcounter
= pollcounters
[controlindex
] & 0x7FFFFFFF;
340 uint64_t fetchrow
= movie_data
.size() - 1;
341 if(current_frame_first_subframe
+ pollcounter
< movie_data
.size()) {
342 //The index is within existing size. Change the value and propagate to all subsequent
344 for(uint64_t i
= current_frame_first_subframe
+ pollcounter
; i
< movie_data
.size(); i
++)
345 movie_data
[i
](controlindex
) = new_value
;
346 fetchrow
= current_frame_first_subframe
+ pollcounter
;
347 } else if(new_value
!= movie_data
[movie_data
.size() - 1](controlindex
)) {
348 //The index is not within existing size and value does not match. We need to create a new
349 //subframes(s), copying the last subframe.
350 while(current_frame_first_subframe
+ pollcounter
>= movie_data
.size()) {
351 controls_t c
= movie_data
[movie_data
.size() - 1];
352 c(CONTROL_FRAME_SYNC
) = 0;
353 movie_data
.push_back(c
);
355 fetchrow
= current_frame_first_subframe
+ pollcounter
;
356 movie_data
[current_frame_first_subframe
+ pollcounter
](controlindex
) = new_value
;
358 pollcounters
[controlindex
]++;
359 //debuglog << "Frame=" << current_frame << " Subframe=" << (pollcounters[controlindex] - 1) << " control=" << controlindex << " value=" << new_value << " fetchrow=" << fetchrow << std::endl << std::flush;
364 movie::movie() throw(std::bad_alloc
)
371 current_frame_first_subframe
= 0;
372 for(unsigned i
= 0; i
< TOTAL_CONTROLS
; i
++) {
374 current_controls(i
) = 0;
380 void movie::load(const std::string
& rerecs
, const std::string
& project_id
, const std::vector
<controls_t
>& input
)
381 throw(std::bad_alloc
, std::runtime_error
)
383 if(input
.size() > 0 && !input
[0](CONTROL_FRAME_SYNC
))
384 throw std::runtime_error("First subframe MUST have frame sync flag set");
387 for(auto i
= input
.begin(); i
!= input
.end(); i
++)
388 if((*i
)(CONTROL_FRAME_SYNC
))
392 _project_id
= project_id
;
394 current_frame_first_subframe
= 0;
395 for(unsigned i
= 0; i
< TOTAL_CONTROLS
; i
++) {
402 std::vector
<controls_t
> movie::save() throw(std::bad_alloc
)
407 void movie::commit_reset(long delay
) throw(std::bad_alloc
)
409 if(readonly
|| delay
< 0)
411 //If this frame is lagged, we need to write entry for it.
412 bool this_frame_lag
= true;
413 for(size_t i
= MAX_SYSTEM_CONTROLS
; i
< TOTAL_CONTROLS
; i
++)
414 if(pollcounters
[i
] & 0x7FFFFFFF)
415 this_frame_lag
= false;
416 //Hack: Reset frames must not be considered lagged, so we abuse pollcounter bit for reset to mark those.
417 if(pollcounters
[CONTROL_SYSTEM_RESET
] & 0x7FFFFFFF)
418 this_frame_lag
= false;
420 controls_t c
= current_controls
;
421 c(CONTROL_FRAME_SYNC
) = 1;
422 movie_data
.push_back(c
);
424 //Current_frame_first_subframe is correct.
426 //Also set poll counters on reset cycles to avoid special cases elsewhere.
427 pollcounters
[CONTROL_SYSTEM_RESET
] = 1;
428 pollcounters
[CONTROL_SYSTEM_RESET_CYCLES_HI
] = 1;
429 pollcounters
[CONTROL_SYSTEM_RESET_CYCLES_LO
] = 1;
430 //Current frame is always last in rw mode.
431 movie_data
[current_frame_first_subframe
](CONTROL_SYSTEM_RESET
) = 1;
432 movie_data
[current_frame_first_subframe
](CONTROL_SYSTEM_RESET_CYCLES_HI
) = delay
/ 10000;
433 movie_data
[current_frame_first_subframe
](CONTROL_SYSTEM_RESET_CYCLES_LO
) = delay
% 10000;
436 unsigned movie::next_poll_number()
439 for(unsigned i
= 0; i
< TOTAL_CONTROLS
; i
++)
440 if(max
< (pollcounters
[i
] & 0x7FFFFFFF))
441 max
= (pollcounters
[i
] & 0x7FFFFFFF);
445 void movie::readonly_mode(bool enable
) throw(std::bad_alloc
)
447 bool was_in_readonly
= readonly
;
449 if(was_in_readonly
&& !readonly
) {
451 //Transitioning to readwrite mode, we have to adjust the length of the movie data.
452 if(current_frame
== 0) {
453 //WTF... At before first frame. Blank the entiere movie.
457 //Fun special case: Current frame is not in movie (current_frame_first_subframe >= movie_data.size()).
458 //In this case, we have to extend the movie data.
459 if(current_frame_first_subframe
>= movie_data
.size()) {
460 //Yes, this will insert one extra frame... But we will lose it later if it is not needed.
461 while(frames_in_movie
< current_frame
) {
463 movie_data
.push_back(c
);
466 current_frame_first_subframe
= movie_data
.size() - 1;
469 //We have to take the part up to furthest currently readable subframe. Also, we need to propagate
470 //forward values with smaller poll counters.
471 uint64_t next_frame_first_subframe
= current_frame_first_subframe
+
472 count_changes(current_frame_first_subframe
);
473 uint64_t max_readable_subframes
= current_frame_first_subframe
;
474 for(size_t i
= 0; i
< TOTAL_CONTROLS
; i
++) {
475 uint32_t polls
= pollcounters
[i
] & 0x7FFFFFFF;
476 if(current_frame_first_subframe
+ polls
>= next_frame_first_subframe
)
477 max_readable_subframes
= next_frame_first_subframe
;
478 else if(current_frame_first_subframe
+ polls
> max_readable_subframes
)
479 max_readable_subframes
= current_frame_first_subframe
+ polls
;
481 movie_data
.resize(max_readable_subframes
);
482 next_frame_first_subframe
= max_readable_subframes
;
483 for(size_t i
= 1; i
< TOTAL_CONTROLS
; i
++) {
484 uint32_t polls
= pollcounters
[i
] & 0x7FFFFFFF;
487 for(uint64_t j
= current_frame_first_subframe
+ polls
; j
< next_frame_first_subframe
; j
++)
488 movie_data
[j
](i
) = movie_data
[current_frame_first_subframe
+ polls
- 1](i
);
490 frames_in_movie
= current_frame
- ((current_frame_first_subframe
>= movie_data
.size()) ? 1 : 0);
494 //Save state of movie code.
495 std::vector
<uint8_t> movie::save_state() throw(std::bad_alloc
)
497 //debuglog << "--------------------------------------------" << std::endl;
498 //debuglog << "SAVING STATE:" << std::endl;
499 std::vector
<uint8_t> ret
;
500 hash_string(enlarge(ret
, 32), _project_id
);
501 write64(enlarge(ret
, 8), current_frame
);
502 //debuglog << "Current frame is " << current_frame << std::endl;
503 //debuglog << "Poll counters: ";
504 for(unsigned i
= 0; i
< TOTAL_CONTROLS
; i
++) {
505 uint32_t v
= pollcounters
[i
];
507 if(v
& 0x80000000UL
) {
511 write32(enlarge(ret
, 4), v
);
513 //debuglog << std::endl;
515 uint64_t v
= lag_frames
;
516 //debuglog << "Lag frame count: " << lag_frames << std::endl;
517 write64(enlarge(ret
, 8), v
);
519 hash_movie(enlarge(ret
, 32), current_frame
, pollcounters
, movie_data
);
521 sha256::hash(hash
, ret
);
522 memcpy(enlarge(ret
, 32), hash
, 32);
523 //debuglog << "--------------------------------------------" << std::endl;
528 //Restore state of movie code. Throws if state is invalid. Flag gives new state of readonly flag.
529 size_t movie::restore_state(const std::vector
<uint8_t>& state
, bool ro
) throw(std::bad_alloc
, std::runtime_error
)
531 //Check the whole-data checksum.
534 if(state
.size() != 112+4*TOTAL_CONTROLS
)
535 throw std::runtime_error("Movie save data corrupt: Wrong length");
536 sha256::hash(tmp
, &state
[0], state
.size() - 32);
537 if(memcmp(tmp
, &state
[state
.size() - 32], 32))
538 throw std::runtime_error("Movie save data corrupt: Checksum does not match");
539 //debuglog << "--------------------------------------------" << std::endl;
540 //debuglog << "RESTORING STATE:" << std::endl;
542 hash_string(tmp
, _project_id
);
543 if(memcmp(tmp
, &state
[ptr
], 32))
544 throw std::runtime_error("Save is not from this movie");
546 //Read current frame.
547 uint64_t tmp_curframe
= read64(&state
[ptr
]);
548 uint64_t tmp_firstsubframe
= 0;
549 for(uint64_t i
= 1; i
< tmp_curframe
; i
++)
550 tmp_firstsubframe
= tmp_firstsubframe
+ count_changes(tmp_firstsubframe
);
552 //Read poll counters and drdy flags.
553 uint32_t tmp_pollcount
[TOTAL_CONTROLS
];
554 for(unsigned i
= 0; i
< TOTAL_CONTROLS
; i
++) {
555 uint32_t v
= read32(&state
[ptr
]);
557 tmp_pollcount
[i
] = v
;
559 uint64_t tmp_lagframes
= read64(&state
[ptr
]);
560 tmp_lagframes
&= 0x7FFFFFFFFFFFFFFFULL
;
562 hash_movie(tmp
, tmp_curframe
, tmp_pollcount
, movie_data
);
563 if(memcmp(tmp
, &state
[ptr
], 32))
564 throw std::runtime_error("Save is not from this movie");
566 //Ok, all checks pass. Copy the state. Do this in readonly mode so we can use normal routine to switch
569 current_frame
= tmp_curframe
;
570 current_frame_first_subframe
= tmp_firstsubframe
;
571 memcpy(pollcounters
, tmp_pollcount
, sizeof(tmp_pollcount
));
572 lag_frames
= tmp_lagframes
;
574 //debuglog << "Current frame is " << current_frame << std::endl;
575 //debuglog << "Poll counters: ";
576 for(unsigned i
= 0; i
< TOTAL_CONTROLS
; i
++) {
577 uint32_t v
= pollcounters
[i
];
579 if(v
& 0x80000000UL
) {
584 //debuglog << std::endl;
586 //debuglog << "Lag frame count: " << lag_frames << std::endl;
589 //debuglog << "--------------------------------------------" << std::endl;
592 //Move to readwrite mode if needed.
597 long movie::get_reset_status() throw()
599 if(current_frame
== 0 || current_frame_first_subframe
>= movie_data
.size())
600 return -1; //No resets out of range.
601 if(!movie_data
[current_frame_first_subframe
](CONTROL_SYSTEM_RESET
))
602 return -1; //Not a reset.
603 //Also set poll counters on reset cycles to avoid special cases elsewhere.
604 pollcounters
[CONTROL_SYSTEM_RESET
] = 1;
605 pollcounters
[CONTROL_SYSTEM_RESET_CYCLES_HI
] = 1;
606 pollcounters
[CONTROL_SYSTEM_RESET_CYCLES_LO
] = 1;
607 long hi
= movie_data
[current_frame_first_subframe
](CONTROL_SYSTEM_RESET_CYCLES_HI
);
608 long lo
= movie_data
[current_frame_first_subframe
](CONTROL_SYSTEM_RESET_CYCLES_LO
);
609 return hi
* 10000 + lo
;
612 uint64_t movie::frame_subframes(uint64_t frame
)
614 if(frame
< cached_frame
)
616 uint64_t p
= cached_subframe
;
617 for(uint64_t i
= cached_frame
; i
< frame
; i
++)
618 p
= p
+ count_changes(p
);
619 cached_frame
= frame
;
621 return count_changes(p
);
624 void movie::clear_caches()
630 controls_t
movie::read_subframe(uint64_t frame
, uint64_t subframe
)
632 if(frame
< cached_frame
)
634 uint64_t p
= cached_subframe
;
635 for(uint64_t i
= cached_frame
; i
< frame
; i
++)
636 p
= p
+ count_changes(p
);
637 cached_frame
= frame
;
639 uint64_t max
= count_changes(p
);
641 return controls_t(true);
644 return movie_data
[p
+ subframe
];
648 movie_logic::movie_logic(movie
& m
) throw()
653 movie_logic::~movie_logic() throw()
657 movie
& movie_logic::get_movie() throw()
662 long movie_logic::new_frame_starting(bool dont_poll
) throw(std::bad_alloc
, std::runtime_error
)
665 controls_t c
= update_controls(false);
666 if(!mov
.readonly_mode()) {
670 if(c(CONTROL_SYSTEM_RESET
)) {
671 long hi
= c(CONTROL_SYSTEM_RESET_CYCLES_HI
);
672 long lo
= c(CONTROL_SYSTEM_RESET_CYCLES_LO
);
673 mov
.commit_reset(hi
* 10000 + lo
);
676 return mov
.get_reset_status();
679 short movie_logic::input_poll(bool port
, unsigned dev
, unsigned id
) throw(std::bad_alloc
, std::runtime_error
)
681 if(dev
>= MAX_CONTROLLERS_PER_PORT
|| id
>= CONTROLLER_CONTROLS
)
683 if(!mov
.get_DRDY(port
? 1 : 0, dev
, id
)) {
684 mov
.set_controls(update_controls(true));
687 int16_t in
= mov
.next_input(port
? 1 : 0, dev
, id
);
688 //debuglog << "BSNES asking for (" << port << "," << dev << "," << id << ") (frame " << mov.get_current_frame()
689 // << ") giving " << in << std::endl;