platform.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. auto Program::attach(ares::Node::Object node) -> void {
  2. if(auto screen = node->cast<ares::Node::Screen>()) {
  3. screens = emulator->root->find<ares::Node::Screen>();
  4. }
  5. if(auto stream = node->cast<ares::Node::Stream>()) {
  6. streams = emulator->root->find<ares::Node::Stream>();
  7. stream->setResamplerFrequency(ruby::audio.frequency());
  8. }
  9. }
  10. auto Program::detach(ares::Node::Object node) -> void {
  11. if(auto screen = node->cast<ares::Node::Screen>()) {
  12. screens = emulator->root->find<ares::Node::Screen>();
  13. }
  14. if(auto stream = node->cast<ares::Node::Stream>()) {
  15. streams = emulator->root->find<ares::Node::Stream>();
  16. }
  17. }
  18. auto Program::open(ares::Node::Object node, string name, vfs::file::mode mode, bool required) -> shared_pointer<vfs::file> {
  19. return emulator->open(node, name, mode, required);
  20. }
  21. auto Program::event(ares::Event event) -> void {
  22. }
  23. auto Program::log(string_view message) -> void {
  24. if(traceLogger.traceToTerminal.checked()) {
  25. return print(message);
  26. }
  27. if(!traceLogger.fp) {
  28. auto datetime = chrono::local::datetime().replace("-", "").replace(":", "").replace(" ", "-");
  29. auto location = emulator->locate({Location::notsuffix(emulator->game.location), "-", datetime, ".log"}, ".log", settings.paths.debugging);
  30. traceLogger.fp.open(location, file::mode::write);
  31. }
  32. traceLogger.fp.print(message);
  33. }
  34. auto Program::video(ares::Node::Screen node, const uint32_t* data, uint pitch, uint width, uint height) -> void {
  35. if(!screens) return;
  36. if(requestScreenshot) {
  37. requestScreenshot = false;
  38. captureScreenshot(data, pitch, width, height);
  39. }
  40. if(node->width() != emulator->latch.width || node->height() != emulator->latch.height || node->rotation() != emulator->latch.rotation) {
  41. emulator->latch.width = node->width();
  42. emulator->latch.height = node->height();
  43. emulator->latch.rotation = node->rotation();
  44. if(settings.video.adaptiveSizing) presentation.resizeWindow();
  45. }
  46. uint videoWidth = node->width() * node->scaleX();
  47. uint videoHeight = node->height() * node->scaleY();
  48. if(settings.video.aspectCorrection) videoWidth = videoWidth * node->aspectX() / node->aspectY();
  49. if(node->rotation() == 90 || node->rotation() == 270) swap(videoWidth, videoHeight);
  50. auto [viewportWidth, viewportHeight] = ruby::video.size();
  51. uint multiplierX = viewportWidth / videoWidth;
  52. uint multiplierY = viewportHeight / videoHeight;
  53. uint multiplier = min(multiplierX, multiplierY);
  54. uint outputWidth = videoWidth * multiplier;
  55. uint outputHeight = videoHeight * multiplier;
  56. if(multiplier == 0 || settings.video.output == "Scale") {
  57. float multiplierX = (float)viewportWidth / (float)videoWidth;
  58. float multiplierY = (float)viewportHeight / (float)videoHeight;
  59. float multiplier = min(multiplierX, multiplierY);
  60. outputWidth = videoWidth * multiplier;
  61. outputHeight = videoHeight * multiplier;
  62. }
  63. if(settings.video.output == "Stretch") {
  64. outputWidth = viewportWidth;
  65. outputHeight = viewportHeight;
  66. }
  67. pitch >>= 2;
  68. if(auto [output, length] = ruby::video.acquire(width, height); output) {
  69. length >>= 2;
  70. for(auto y : range(height)) {
  71. memory::copy<uint32_t>(output + y * length, data + y * pitch, width);
  72. }
  73. ruby::video.release();
  74. ruby::video.output(outputWidth, outputHeight);
  75. }
  76. static uint64_t frameCounter = 0, previous, current;
  77. frameCounter++;
  78. current = chrono::timestamp();
  79. if(current != previous) {
  80. previous = current;
  81. presentation.statusRight.setText({frameCounter, " FPS"});
  82. frameCounter = 0;
  83. }
  84. }
  85. auto Program::audio(ares::Node::Stream node) -> void {
  86. if(!streams) return;
  87. //process all pending frames (there may be more than one waiting)
  88. while(true) {
  89. //only process a frame if all streams have at least one pending frame
  90. for(auto& stream : streams) {
  91. if(!stream->pending()) return;
  92. }
  93. //mix all frames together
  94. double samples[2] = {0.0, 0.0};
  95. for(auto& stream : streams) {
  96. double buffer[2];
  97. uint channels = stream->read(buffer);
  98. if(channels == 1) {
  99. //monaural -> stereo mixing
  100. samples[0] += buffer[0];
  101. samples[1] += buffer[0];
  102. } else {
  103. samples[0] += buffer[0];
  104. samples[1] += buffer[1];
  105. }
  106. }
  107. //apply volume, balance, and clamping to the output frame
  108. double volume = !settings.audio.mute ? settings.audio.volume : 0.0;
  109. double balance = settings.audio.balance;
  110. for(uint c : range(2)) {
  111. samples[c] = max(-1.0, min(+1.0, samples[c] * volume));
  112. if(balance < 0.0) samples[1] *= 1.0 + balance;
  113. if(balance > 0.0) samples[0] *= 1.0 - balance;
  114. }
  115. //send frame to the audio output device
  116. ruby::audio.output(samples);
  117. }
  118. }
  119. auto Program::input(ares::Node::Input node) -> void {
  120. if(!driverSettings.inputDefocusAllow.checked()) {
  121. if(!ruby::video.fullScreen() && !presentation.focused()) {
  122. //todo: set node->value() to zero here
  123. return;
  124. }
  125. }
  126. emulator->input(node);
  127. }