Real-time updates for voice streams in editor
[lsnes.git] / src / core / dispatch.cpp
blob6a91e859c4189f35598e31de99c72d25d1a13308
1 #include "core/dispatch.hpp"
2 #include "core/globalwrap.hpp"
3 #include "core/misc.hpp"
5 #include <sstream>
6 #include <iomanip>
7 #include <cmath>
9 #define START_EH_BLOCK try {
10 #define END_EH_BLOCK(obj, call) } catch(std::bad_alloc& e) { \
11 OOM_panic(); \
12 } catch(std::exception& e) { \
13 messages << "[dumper " << obj->get_name() << "] Warning: " call ": " << e.what() \
14 << std::endl; \
15 } catch(int code) { \
16 messages << "[dumper " << obj->get_name() << "] Warning: " call ": Error code #" << code \
17 << std::endl; \
20 gameinfo_struct::gameinfo_struct() throw(std::bad_alloc)
22 length = 0;
23 rerecords = "0";
26 std::string gameinfo_struct::get_readable_time(unsigned digits) const throw(std::bad_alloc)
28 double bias = 0.5 * pow(10, -static_cast<int>(digits));
29 double len = length + bias;
30 std::ostringstream str;
31 if(length >= 3600) {
32 double hours = floor(len / 3600);
33 str << hours << ":";
34 len -= hours * 3600;
36 double minutes = floor(len / 60);
37 len -= minutes * 60;
38 double seconds = floor(len);
39 len -= seconds;
40 str << std::setw(2) << std::setfill('0') << minutes << ":" << seconds;
41 if(digits > 0)
42 str << ".";
43 while(digits > 0) {
44 len = 10 * len;
45 str << '0' + static_cast<int>(len);
46 len -= floor(len);
47 digits--;
51 size_t gameinfo_struct::get_author_count() const throw()
53 return authors.size();
56 std::string gameinfo_struct::get_author_short(size_t idx) const throw(std::bad_alloc)
58 if(idx >= authors.size())
59 return "";
60 const std::pair<std::string, std::string>& x = authors[idx];
61 if(x.second != "")
62 return x.second;
63 else
64 return x.first;
67 uint64_t gameinfo_struct::get_rerecords() const throw()
69 uint64_t v = 0;
70 uint64_t max = 0xFFFFFFFFFFFFFFFFULL;
71 for(size_t i = 0; i < rerecords.length(); i++) {
72 if(v < max / 10)
73 //No risk of overflow.
74 v = v * 10 + static_cast<unsigned>(rerecords[i] - '0');
75 else if(v == max / 10) {
76 //THis may overflow.
77 v = v * 10;
78 if(v + static_cast<unsigned>(rerecords[i] - '0') < v)
79 return max;
80 v = v + static_cast<unsigned>(rerecords[i] - '0');
81 } else
82 //Definite overflow.
83 return max;
85 return v;
88 namespace
90 globalwrap<std::list<information_dispatch*>> dispatch;
91 globalwrap<std::list<information_dispatch*>> dispatch_audio;
92 uint32_t srate_n = 32000;
93 uint32_t srate_d = 1;
94 struct gameinfo_struct sgi;
95 information_dispatch* exclusive_key = NULL;
96 int32_t vc_xoffset = 0;
97 int32_t vc_yoffset = 0;
98 uint32_t vc_hscl = 1;
99 uint32_t vc_vscl = 1;
100 bool recursive = false;
103 information_dispatch::information_dispatch(const std::string& name) throw(std::bad_alloc)
105 target_name = name;
106 dispatch().push_back(this);
107 known_if_dumper = false;
108 marked_as_dumper = false;
109 notified_as_dumper = false;
110 grabbing_keys = false;
113 information_dispatch::~information_dispatch() throw()
115 for(auto i = dispatch().begin(); i != dispatch().end(); ++i) {
116 if(*i == this) {
117 dispatch().erase(i);
118 break;
121 for(auto i = dispatch_audio().begin(); i != dispatch_audio().end(); ++i) {
122 if(*i == this) {
123 dispatch_audio().erase(i);
124 break;
127 if(notified_as_dumper)
128 for(auto& i : dispatch()) {
129 START_EH_BLOCK
130 i->on_destroy_dumper(target_name);
131 END_EH_BLOCK(i, "on_destroy_dumper");
135 void information_dispatch::on_close()
137 //Do nothing.
140 void information_dispatch::do_close() throw()
142 for(auto& i : dispatch()) {
143 START_EH_BLOCK
144 i->on_close();
145 END_EH_BLOCK(i, "on_close");
149 void information_dispatch::on_sound_unmute(bool unmuted)
151 //Do nothing.
154 void information_dispatch::do_sound_unmute(bool unmuted) throw()
156 for(auto& i : dispatch()) {
157 START_EH_BLOCK
158 i->on_sound_unmute(unmuted);
159 END_EH_BLOCK(i, "on_sound_unmute");
163 void information_dispatch::on_sound_change(const std::string& dev)
165 //Do nothing.
168 void information_dispatch::do_sound_change(const std::string& dev) throw()
170 for(auto& i : dispatch()) {
171 START_EH_BLOCK
172 i->on_sound_change(dev);
173 END_EH_BLOCK(i, "on_sound_change");
177 void information_dispatch::on_mode_change(bool readonly)
179 //Do nothing.
182 void information_dispatch::do_mode_change(bool readonly) throw()
184 for(auto& i : dispatch()) {
185 START_EH_BLOCK
186 i->on_mode_change(readonly);
187 END_EH_BLOCK(i, "on_mode_change");
191 void information_dispatch::on_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate)
193 //Do nothing.
196 void information_dispatch::do_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate) throw()
198 for(auto& i : dispatch()) {
199 START_EH_BLOCK
200 i->on_autohold_update(pid, ctrlnum, newstate);
201 END_EH_BLOCK(i, "on_autohold_update");
205 void information_dispatch::on_autohold_reconfigure()
207 //Do nothing.
210 void information_dispatch::do_autohold_reconfigure() throw()
212 for(auto& i : dispatch()) {
213 START_EH_BLOCK
214 i->on_autohold_reconfigure();
215 END_EH_BLOCK(i, "on_autohold_reconfigure");
219 void information_dispatch::on_setting_change(const std::string& setting, const std::string& value)
221 //Do nothing.
224 void information_dispatch::do_setting_change(const std::string& setting, const std::string& value) throw()
226 for(auto& i : dispatch()) {
227 START_EH_BLOCK
228 i->on_setting_change(setting, value);
229 END_EH_BLOCK(i, "on_setting_change");
233 void information_dispatch::on_setting_clear(const std::string& setting)
235 //Do nothing.
238 void information_dispatch::do_setting_clear(const std::string& setting) throw()
240 for(auto& i : dispatch()) {
241 START_EH_BLOCK
242 i->on_setting_clear(setting);
243 END_EH_BLOCK(i, "on_setting_clear");
248 void information_dispatch::on_raw_frame(const uint32_t* raw, bool hires, bool interlaced, bool overscan,
249 unsigned region)
251 //Do nothing.
254 void information_dispatch::do_raw_frame(const uint32_t* raw, bool hires, bool interlaced, bool overscan,
255 unsigned region) throw()
257 update_dumpers();
258 for(auto& i : dispatch()) {
259 START_EH_BLOCK
260 i->on_raw_frame(raw, hires, interlaced, overscan, region);
261 END_EH_BLOCK(i, "on_raw_frame");
265 void information_dispatch::on_frame(struct framebuffer_raw& _frame, uint32_t fps_n, uint32_t fps_d)
267 //Do nothing.
270 void information_dispatch::do_frame(struct framebuffer_raw& _frame, uint32_t fps_n, uint32_t fps_d) throw()
272 update_dumpers();
273 for(auto& i : dispatch()) {
274 START_EH_BLOCK
275 i->on_frame(_frame, fps_n, fps_d);
276 END_EH_BLOCK(i, "on_frame");
280 void information_dispatch::on_sample(short l, short r)
282 //Do nothing.
285 void information_dispatch::do_sample(short l, short r) throw()
287 update_dumpers();
288 for(auto& i : dispatch_audio()) {
289 START_EH_BLOCK
290 i->on_sample(l, r);
291 END_EH_BLOCK(i, "on_sample");
295 void information_dispatch::on_dump_end()
297 //Do nothing.
300 void information_dispatch::do_dump_end() throw()
302 update_dumpers();
303 for(auto& i : dispatch()) {
304 START_EH_BLOCK
305 i->on_dump_end();
306 END_EH_BLOCK(i, "on_dump_end");
310 void information_dispatch::on_sound_rate(uint32_t rate_n, uint32_t rate_d)
312 if(!known_if_dumper) {
313 marked_as_dumper = get_dumper_flag();
314 known_if_dumper = true;
316 if(marked_as_dumper) {
317 messages << "[dumper " << get_name() << "] Warning: Sound sample rate changing not supported!"
318 << std::endl;
322 void information_dispatch::do_sound_rate(uint32_t rate_n, uint32_t rate_d) throw()
324 update_dumpers();
325 uint32_t g = gcd(rate_n, rate_d);
326 rate_n /= g;
327 rate_d /= g;
328 if(rate_n == srate_n && rate_d == srate_d)
329 return;
330 srate_n = rate_n;
331 srate_d = rate_d;
332 for(auto& i : dispatch()) {
333 START_EH_BLOCK
334 i->on_sound_rate(rate_n, rate_d);
335 END_EH_BLOCK(i, "on_sound_rate");
339 std::pair<uint32_t, uint32_t> information_dispatch::get_sound_rate() throw()
341 return std::make_pair(srate_n, srate_d);
344 void information_dispatch::on_gameinfo(const struct gameinfo_struct& gi)
346 //Do nothing.
349 void information_dispatch::do_gameinfo(const struct gameinfo_struct& gi) throw()
351 update_dumpers();
352 try {
353 sgi = gi;
354 } catch(...) {
355 OOM_panic();
357 for(auto& i : dispatch()) {
358 START_EH_BLOCK
359 i->on_gameinfo(sgi);
360 END_EH_BLOCK(i, "on_gameinfo");
364 const struct gameinfo_struct& information_dispatch::get_gameinfo() throw()
366 return sgi;
369 bool information_dispatch::get_dumper_flag() throw()
371 return false;
374 void information_dispatch::on_new_dumper(const std::string& dumper)
376 //Do nothing.
379 void information_dispatch::on_destroy_dumper(const std::string& dumper)
381 //Do nothing.
384 unsigned information_dispatch::get_dumper_count() throw()
386 update_dumpers(true);
387 unsigned count = 0;
388 for(auto& i : dispatch())
389 if(i->marked_as_dumper)
390 count++;
391 if(!recursive) {
392 recursive = true;
393 update_dumpers();
394 recursive = false;
396 return count;
399 std::set<std::string> information_dispatch::get_dumpers() throw(std::bad_alloc)
401 update_dumpers();
402 std::set<std::string> r;
403 try {
404 for(auto& i : dispatch())
405 if(i->notified_as_dumper)
406 r.insert(i->get_name());
407 } catch(...) {
408 OOM_panic();
410 return r;
413 void information_dispatch::on_key_event(const modifier_set& modifiers, keygroup& keygroup, unsigned subkey,
414 bool polarity, const std::string& name)
416 //Do nothing.
419 void information_dispatch::do_key_event(const modifier_set& modifiers, keygroup& keygroup, unsigned subkey,
420 bool polarity, const std::string& name) throw()
422 if(exclusive_key) {
423 START_EH_BLOCK
424 exclusive_key->on_key_event(modifiers, keygroup, subkey, polarity, name);
425 END_EH_BLOCK(exclusive_key, "on_key_event");
426 return;
428 for(auto& i : dispatch()) {
429 START_EH_BLOCK
430 i->on_key_event(modifiers, keygroup, subkey, polarity, name);
431 END_EH_BLOCK(i, "on_key_event");
435 void information_dispatch::grab_keys() throw()
437 if(grabbing_keys)
438 return;
439 exclusive_key = this;
440 grabbing_keys = true;
443 void information_dispatch::ungrab_keys() throw()
445 if(!grabbing_keys)
446 return;
447 exclusive_key = NULL;
448 grabbing_keys = false;
449 for(auto& i : dispatch())
450 if(i->grabbing_keys) {
451 exclusive_key = i;
452 break;
456 const std::string& information_dispatch::get_name() throw()
458 return target_name;
461 void information_dispatch::update_dumpers(bool nocalls) throw()
463 for(auto& i : dispatch()) {
464 if(!i->known_if_dumper) {
465 i->marked_as_dumper = i->get_dumper_flag();
466 i->known_if_dumper = true;
468 if(i->marked_as_dumper && !i->notified_as_dumper && !nocalls) {
469 for(auto& j : dispatch()) {
470 START_EH_BLOCK
471 j->on_new_dumper(i->target_name);
472 END_EH_BLOCK(j, "on_new_dumper");
474 i->notified_as_dumper = true;
479 void information_dispatch::on_set_screen(framebuffer<false>& scr)
481 //Do nothing.
484 void information_dispatch::do_set_screen(framebuffer<false>& scr) throw()
486 for(auto& i : dispatch()) {
487 START_EH_BLOCK
488 i->on_set_screen(scr);
489 END_EH_BLOCK(i, "on_set_screen");
493 void information_dispatch::on_screen_update()
495 //Do nothing.
498 void information_dispatch::do_screen_update() throw()
500 for(auto& i : dispatch()) {
501 START_EH_BLOCK
502 i->on_screen_update();
503 END_EH_BLOCK(i, "on_screen_update");
507 void information_dispatch::on_status_update()
509 //Do nothing.
512 void information_dispatch::do_status_update() throw()
514 for(auto& i : dispatch()) {
515 START_EH_BLOCK
516 i->on_status_update();
517 END_EH_BLOCK(i, "on_status_update");
521 void information_dispatch::enable_send_sound() throw(std::bad_alloc)
523 dispatch_audio().push_back(this);
526 void information_dispatch::on_dumper_update()
528 //Do nothing.
531 void information_dispatch::do_dumper_update() throw()
533 if(in_global_ctors())
534 return;
535 for(auto& i : dispatch()) {
536 START_EH_BLOCK
537 i->on_dumper_update();
538 END_EH_BLOCK(i, "on_dumper_update");
542 void information_dispatch::on_voice_stream_change()
544 //Do nothing.
547 void information_dispatch::do_voice_stream_change() throw()
549 if(in_global_ctors())
550 return;
551 for(auto& i : dispatch()) {
552 START_EH_BLOCK
553 i->on_voice_stream_change();
554 END_EH_BLOCK(i, "on_voice_stream_change");