3 #include "core/misc.hpp"
4 #include "core/movie.hpp"
5 #include "core/rom.hpp"
13 //std::ofstream debuglog("movie-debugging-log", std::ios::out | std::ios::app);
17 bool movies_compatible(controller_frame_vector
& old_movie
, controller_frame_vector
& new_movie
,
18 uint64_t frame
, const uint32_t* polls
, const std::string
& old_projectid
,
19 const std::string
& new_projectid
)
21 //Project IDs have to match.
22 if(old_projectid
!= new_projectid
)
24 //If new movie is before first frame, anything with same project_id is compatible.
27 //Scan both movies until frame syncs are seen. Out of bounds reads behave as all neutral but frame
29 uint64_t syncs_seen
= 0;
30 uint64_t frames_read
= 0;
31 while(syncs_seen
< frame
- 1) {
32 controller_frame oldc
= old_movie
.blank_frame(true), newc
= new_movie
.blank_frame(true);
33 if(frames_read
< old_movie
.size())
34 oldc
= old_movie
[frames_read
];
35 if(frames_read
< new_movie
.size())
36 newc
= new_movie
[frames_read
];
38 return false; //Mismatch.
43 //We increment the counter one time too many.
45 //Current frame. We need to compare each control up to poll counter.
46 uint64_t readable_old_subframes
= 0, readable_new_subframes
= 0;
47 if(frames_read
< old_movie
.size())
48 readable_old_subframes
= old_movie
.size() - frames_read
;
49 if(frames_read
< new_movie
.size())
50 readable_new_subframes
= new_movie
.size() - frames_read
;
51 //Compare reset flags of current frame.
52 bool old_reset
= false;
53 bool new_reset
= false;
54 std::pair
<short, short> old_delay
= std::make_pair(0, 0);
55 std::pair
<short, short> new_delay
= std::make_pair(0, 0);
56 if(readable_old_subframes
) {
57 old_reset
= old_movie
[frames_read
].reset();
58 old_delay
= old_movie
[frames_read
].delay();
60 if(readable_new_subframes
) {
61 new_reset
= new_movie
[frames_read
].reset();
62 new_delay
= new_movie
[frames_read
].delay();
64 if(old_reset
!= new_reset
|| old_delay
!= new_delay
)
66 //Then rest of the stuff.
67 for(unsigned i
= 0; i
< MAX_BUTTONS
; i
++) {
68 uint32_t p
= polls
[i
+ 4] & 0x7FFFFFFFUL
;
70 for(uint32_t j
= 0; j
< p
; j
++) {
71 if(j
< readable_old_subframes
)
72 ov
= old_movie
[j
+ frames_read
].axis2(i
);
73 if(j
< readable_new_subframes
)
74 nv
= new_movie
[j
+ frames_read
].axis2(i
);
83 void movie::set_all_DRDY() throw()
85 pollcounters
.set_all_DRDY();
88 std::string
movie::rerecord_count() throw(std::bad_alloc
)
93 void movie::rerecord_count(const std::string
& count
) throw(std::bad_alloc
)
98 std::string
movie::project_id() throw(std::bad_alloc
)
103 void movie::project_id(const std::string
& id
) throw(std::bad_alloc
)
108 bool movie::readonly_mode() throw()
113 void movie::set_controls(controller_frame controls
) throw()
115 current_controls
= controls
;
118 uint32_t movie::count_changes(uint64_t first_subframe
) throw()
120 return movie_data
.subframe_count(first_subframe
);
123 controller_frame
movie::get_controls() throw()
126 return current_controls
;
127 controller_frame c
= movie_data
.blank_frame(false);
128 //Before the beginning? Somebody screwed up (but return released / neutral anyway)...
129 if(current_frame
== 0)
131 //Otherwise find the last valid frame of input.
132 uint32_t changes
= count_changes(current_frame_first_subframe
);
134 return c
; //End of movie.
135 if(pollcounters
.get_system()) {
136 c
.reset(movie_data
[current_frame_first_subframe
].reset());
137 c
.delay(movie_data
[current_frame_first_subframe
].delay());
139 for(size_t i
= 0; i
< MAX_BUTTONS
; i
++) {
140 uint32_t polls
= pollcounters
.get_polls(i
);
141 uint32_t index
= (changes
> polls
) ? polls
: changes
- 1;
142 c
.axis2(i
, movie_data
[current_frame_first_subframe
+ index
].axis2(i
));
147 uint64_t movie::get_current_frame() throw()
149 return current_frame
;
152 uint64_t movie::get_lag_frames() throw()
157 uint64_t movie::get_frame_count() throw()
159 return frames_in_movie
;
162 void movie::next_frame() throw(std::bad_alloc
)
164 //If all poll counters are zero for all real controls, this frame is lag.
165 bool this_frame_lag
= !pollcounters
.has_polled();
166 //Oh, frame 0 must not be considered lag.
167 if(current_frame
&& this_frame_lag
) {
169 //debuglog << "Frame " << current_frame << " is lag" << std::endl << std::flush;
171 //If in read-write mode, write a dummy record for the frame. Force sync flag.
172 //As index should be movie_data.size(), it is correct afterwards.
173 movie_data
.append(current_controls
.copy(true));
178 //Reset the poll counters and DRDY flags.
179 pollcounters
.clear();
181 //Increment the current frame counter and subframe counter. Note that first subframe is undefined for
182 //frame 0 and 0 for frame 1.
184 current_frame_first_subframe
= current_frame_first_subframe
+
185 count_changes(current_frame_first_subframe
);
187 current_frame_first_subframe
= 0;
191 bool movie::get_DRDY(unsigned pid
, unsigned ctrl
) throw(std::logic_error
)
193 return pollcounters
.get_DRDY(pid
, ctrl
);
196 short movie::next_input(unsigned pid
, unsigned ctrl
) throw(std::bad_alloc
, std::logic_error
)
198 pollcounters
.clear_DRDY(pid
, ctrl
);
201 //In readonly mode...
202 //If at the end of the movie, return released / neutral (but also record the poll)...
203 if(current_frame_first_subframe
>= movie_data
.size()) {
204 pollcounters
.increment_polls(pid
, ctrl
);
207 //Before the beginning? Somebody screwed up (but return released / neutral anyway)...
208 if(current_frame
== 0)
210 //Otherwise find the last valid frame of input.
211 uint32_t changes
= count_changes(current_frame_first_subframe
);
212 uint32_t polls
= pollcounters
.increment_polls(pid
, ctrl
);
213 uint32_t index
= (changes
> polls
) ? polls
: changes
- 1;
214 //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;
215 return movie_data
[current_frame_first_subframe
+ index
].axis(pid
, ctrl
);
218 //Before the beginning? Somebody screwed up (but return released / neutral anyway)...
219 //Also, frame 0 must not be added to movie file.
220 if(current_frame
== 0)
222 //If at movie end, insert complete input with frame sync set (this is the first subframe).
223 if(current_frame_first_subframe
>= movie_data
.size()) {
224 movie_data
.append(current_controls
.copy(true));
225 //current_frame_first_subframe should be movie_data.size(), so it is right.
226 pollcounters
.increment_polls(pid
, ctrl
);
228 //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;
229 return movie_data
[current_frame_first_subframe
].axis(pid
, ctrl
);
231 short new_value
= current_controls
.axis(pid
, ctrl
);
232 //Fortunately, we know this frame is the last one in movie_data.
233 uint32_t pollcounter
= pollcounters
.get_polls(pid
, ctrl
);
234 uint64_t fetchrow
= movie_data
.size() - 1;
235 if(current_frame_first_subframe
+ pollcounter
< movie_data
.size()) {
236 //The index is within existing size. Change the value and propagate to all subsequent
238 for(uint64_t i
= current_frame_first_subframe
+ pollcounter
; i
< movie_data
.size(); i
++)
239 movie_data
[i
].axis(pid
, ctrl
, new_value
);
240 fetchrow
= current_frame_first_subframe
+ pollcounter
;
241 } else if(new_value
!= movie_data
[movie_data
.size() - 1].axis(pid
, ctrl
)) {
242 //The index is not within existing size and value does not match. We need to create a new
243 //subframes(s), copying the last subframe.
244 while(current_frame_first_subframe
+ pollcounter
>= movie_data
.size())
245 movie_data
.append(movie_data
[movie_data
.size() - 1].copy(false));
246 fetchrow
= current_frame_first_subframe
+ pollcounter
;
247 movie_data
[current_frame_first_subframe
+ pollcounter
].axis(pid
, ctrl
, new_value
);
249 pollcounters
.increment_polls(pid
, ctrl
);
250 //debuglog << "Frame=" << current_frame << " Subframe=" << (pollcounters[controlindex] - 1) << " control=" << controlindex << " value=" << new_value << " fetchrow=" << fetchrow << std::endl << std::flush;
255 movie::movie() throw(std::bad_alloc
)
262 current_frame_first_subframe
= 0;
267 void movie::load(const std::string
& rerecs
, const std::string
& project_id
, controller_frame_vector
& input
)
268 throw(std::bad_alloc
, std::runtime_error
)
270 if(input
.size() > 0 && !input
[0].sync())
271 throw std::runtime_error("First subframe MUST have frame sync flag set");
274 for(size_t i
= 0; i
< input
.size(); i
++)
279 _project_id
= project_id
;
281 current_frame_first_subframe
= 0;
282 pollcounters
.clear();
285 //This is to force internal type of current_controls to become correct.
286 current_controls
= input
.blank_frame(false);
289 controller_frame_vector
movie::save() throw(std::bad_alloc
)
294 void movie::commit_reset(long delay
) throw(std::bad_alloc
)
296 if(readonly
|| delay
< 0)
298 //If this frame is lagged, we need to write entry for it.
299 if(!pollcounters
.has_polled()) {
300 movie_data
.append(current_controls
.copy(true));
302 //Current_frame_first_subframe is correct.
304 //Also set poll counters on reset cycles to avoid special cases elsewhere.
305 pollcounters
.set_system();
306 //Current frame is always last in rw mode.
307 movie_data
[current_frame_first_subframe
].reset(true);
308 movie_data
[current_frame_first_subframe
].delay(std::make_pair(delay
/ 10000, delay
% 10000));
311 unsigned movie::next_poll_number()
313 return pollcounters
.max_polls() + 1;
316 void movie::readonly_mode(bool enable
) throw(std::bad_alloc
)
318 bool was_in_readonly
= readonly
;
320 if(was_in_readonly
&& !readonly
) {
322 //Transitioning to readwrite mode, we have to adjust the length of the movie data.
323 if(current_frame
== 0) {
324 //WTF... At before first frame. Blank the entiere movie.
329 //Fun special case: Current frame is not in movie (current_frame_first_subframe >= movie_data.size()).
330 //In this case, we have to extend the movie data.
331 if(current_frame_first_subframe
>= movie_data
.size()) {
332 //Yes, this will insert one extra frame... But we will lose it later if it is not needed.
333 while(frames_in_movie
< current_frame
) {
334 movie_data
.append(movie_data
.blank_frame(true));
337 current_frame_first_subframe
= movie_data
.size() - 1;
340 //We have to take the part up to furthest currently readable subframe. Also, we need to propagate
341 //forward values with smaller poll counters.
342 uint64_t next_frame_first_subframe
= current_frame_first_subframe
+
343 count_changes(current_frame_first_subframe
);
344 uint64_t max_readable_subframes
= current_frame_first_subframe
+ pollcounters
.max_polls();
345 if(max_readable_subframes
> next_frame_first_subframe
)
346 max_readable_subframes
= next_frame_first_subframe
;
348 movie_data
.resize(max_readable_subframes
);
349 next_frame_first_subframe
= max_readable_subframes
;
350 //Propagate RESET. This always has poll count of 0 or 1, which always behaves like 1.
351 for(uint64_t j
= current_frame_first_subframe
+ 1; j
< next_frame_first_subframe
; j
++) {
352 movie_data
[j
].reset(movie_data
[current_frame_first_subframe
].reset());
353 movie_data
[j
].delay(movie_data
[current_frame_first_subframe
].delay());
355 //Then the other buttons.
356 for(size_t i
= 0; i
< MAX_BUTTONS
; i
++) {
357 uint32_t polls
= pollcounters
.get_polls(i
);
358 polls
= polls
? polls
: 1;
359 for(uint64_t j
= current_frame_first_subframe
+ polls
; j
< next_frame_first_subframe
; j
++)
360 movie_data
[j
].axis2(i
, movie_data
[current_frame_first_subframe
+ polls
- 1].axis2(i
));
362 frames_in_movie
= current_frame
- ((current_frame_first_subframe
>= movie_data
.size()) ? 1 : 0);
366 //Save state of movie code.
367 void movie::save_state(std::string
& proj_id
, uint64_t& curframe
, uint64_t& lagframes
, std::vector
<uint32_t>& pcounters
)
368 throw(std::bad_alloc
)
370 pollcounters
.save_state(pcounters
);
371 proj_id
= _project_id
;
372 curframe
= current_frame
;
373 lagframes
= lag_frames
;
376 //Restore state of movie code. Throws if state is invalid. Flag gives new state of readonly flag.
377 size_t movie::restore_state(uint64_t curframe
, uint64_t lagframe
, const std::vector
<uint32_t>& pcounters
, bool ro
,
378 controller_frame_vector
* old_movie
, const std::string
& old_projectid
) throw(std::bad_alloc
,
381 if(!pollcounters
.check(pcounters
))
382 throw std::runtime_error("Wrong number of poll counters");
383 if(old_movie
&& !movies_compatible(*old_movie
, movie_data
, curframe
, &pcounters
[0], old_projectid
,
385 throw std::runtime_error("Save is not from this movie");
386 uint64_t tmp_firstsubframe
= 0;
387 for(uint64_t i
= 1; i
< curframe
; i
++)
388 tmp_firstsubframe
= tmp_firstsubframe
+ count_changes(tmp_firstsubframe
);
389 //Checks have passed, copy the data.
391 current_frame
= curframe
;
392 current_frame_first_subframe
= tmp_firstsubframe
;
393 lag_frames
= lagframe
;
394 pollcounters
.load_state(pcounters
);
399 long movie::get_reset_status() throw()
401 if(current_frame
== 0 || current_frame_first_subframe
>= movie_data
.size())
402 return -1; //No resets out of range.
403 if(!movie_data
[current_frame_first_subframe
].reset())
404 return -1; //Not a reset.
405 //Also set poll counters on reset cycles to avoid special cases elsewhere.
406 pollcounters
.set_system();
407 auto g
= movie_data
[current_frame_first_subframe
].delay();
408 long hi
= g
.first
, lo
= g
.second
;
409 return hi
* 10000 + lo
;
412 uint64_t movie::frame_subframes(uint64_t frame
) throw()
414 if(frame
< cached_frame
)
416 uint64_t p
= cached_subframe
;
417 for(uint64_t i
= cached_frame
; i
< frame
; i
++)
418 p
= p
+ count_changes(p
);
419 cached_frame
= frame
;
421 return count_changes(p
);
424 void movie::clear_caches() throw()
430 controller_frame
movie::read_subframe(uint64_t frame
, uint64_t subframe
) throw()
432 if(frame
< cached_frame
)
434 uint64_t p
= cached_subframe
;
435 for(uint64_t i
= cached_frame
; i
< frame
; i
++)
436 p
= p
+ count_changes(p
);
437 cached_frame
= frame
;
439 uint64_t max
= count_changes(p
);
441 return movie_data
.blank_frame(true);
445 return movie_data
[p
+ subframe
];
449 movie_logic::movie_logic() throw()
453 movie
& movie_logic::get_movie() throw()
458 long movie_logic::new_frame_starting(bool dont_poll
) throw(std::bad_alloc
, std::runtime_error
)
461 controller_frame c
= update_controls(false);
462 if(!mov
.readonly_mode()) {
468 long hi
= g
.first
, lo
= g
.second
;
469 mov
.commit_reset(hi
* 10000 + lo
);
472 return mov
.get_reset_status();
475 short movie_logic::input_poll(bool port
, unsigned dev
, unsigned id
) throw(std::bad_alloc
, std::runtime_error
)
477 unsigned pid
= port
? (dev
+ MAX_CONTROLLERS_PER_PORT
) : dev
;
478 if(!mov
.get_DRDY(pid
, id
)) {
479 mov
.set_controls(update_controls(true));
482 int16_t in
= mov
.next_input(pid
, id
);
483 //debuglog << "BSNES asking for (" << port << "," << dev << "," << id << ") (frame " << mov.get_current_frame()
484 // << ") giving " << in << std::endl;