#include "lsnes.hpp" #include #include "sdump.hpp" #include #include #include #include "avsnoop.hpp" #include "command.hpp" #include "misc.hpp" #define CUTOFF 2100000000 namespace { bool sdump_in_progress; std::string oprefix; std::ofstream out; uint32_t ssize; uint32_t next_seq; bool sdump_iopen; bool sdump_ss; class dummy_avsnoop : public av_snooper { public: dummy_avsnoop() throw(std::bad_alloc) { } ~dummy_avsnoop() throw() { } void frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d) throw(std::bad_alloc, std::runtime_error) { } void sample(short l, short r) throw(std::bad_alloc, std::runtime_error) { } void end() throw(std::bad_alloc, std::runtime_error) { if(sdump_iopen) out.close(); if(sdump_in_progress) sdump_in_progress = false; } void gameinfo(const std::string& gamename, const std::list>& authors, double gametime, const std::string& rerecords) throw(std::bad_alloc, std::runtime_error) { } }; dummy_avsnoop* snooper; function_ptr_command jmd_dump("dump-sdmp", "Start sdmp capture", "Syntax: dump-sdmp \nStart SDMP capture to \n", [](const std::string& prefix) throw(std::bad_alloc, std::runtime_error) { if(prefix == "") throw std::runtime_error("Expected filename"); sdump_open(prefix, false); messages << "Dumping to " << prefix << std::endl; }); function_ptr_command jmd_dumpss("dump-sdmpss", "Start SS sdmp capture", "Syntax: dump-sdmpss \nStart SS SDMP capture to \n", [](const std::string& prefix) throw(std::bad_alloc, std::runtime_error) { if(prefix == "") throw std::runtime_error("Expected filename"); sdump_open(prefix, true); messages << "Dumping to " << prefix << std::endl; }); function_ptr_command<> end_avi("end-sdmp", "End SDMP capture", "Syntax: end-sdmp\nEnd a SDMP capture.\n", []() throw(std::bad_alloc, std::runtime_error) { sdump_close(); messages << "Dump finished" << std::endl; }); } void sdump_open(const std::string& prefix, bool ss) { if(sdump_in_progress) throw std::runtime_error("Dump already in progress"); oprefix = prefix; snooper = new dummy_avsnoop; sdump_ss = ss; sdump_in_progress = true; ssize = 0; next_seq = 0; sdump_iopen = false; } void sdump_close() { if(!sdump_in_progress) throw std::runtime_error("No dump in progress"); if(sdump_iopen) out.close(); sdump_in_progress = false; delete snooper; } void sdump_frame(const uint32_t* buffer, unsigned flags) { flags &= 0xF; unsigned char tbuffer[2049]; if(!sdump_in_progress) return; if(!sdump_iopen || (ssize > CUTOFF && !sdump_ss)) { std::cerr << "Starting new segment" << std::endl; if(sdump_iopen) out.close(); std::ostringstream str; if(sdump_ss) str << oprefix; else str << oprefix << "_" << std::setw(4) << std::setfill('0') << (next_seq++) << ".sdmp"; std::string str2 = str.str(); out.open(str2.c_str(), std::ios::out | std::ios::binary); if(!out) throw std::runtime_error("Failed to open '" + str2 + "'"); sdump_iopen = true; tbuffer[0] = 'S'; tbuffer[1] = 'D'; tbuffer[2] = 'M'; tbuffer[3] = 'P'; uint32_t apufreq = SNES::system.apu_frequency(); uint32_t cpufreq = SNES::system.cpu_frequency(); tbuffer[4] = cpufreq >> 24; tbuffer[5] = cpufreq >> 16; tbuffer[6] = cpufreq >> 8; tbuffer[7] = cpufreq; tbuffer[8] = apufreq >> 24; tbuffer[9] = apufreq >> 16; tbuffer[10] = apufreq >> 8; tbuffer[11] = apufreq; out.write(reinterpret_cast(tbuffer), 12); if(!out) throw std::runtime_error("Failed to write header to '" + str2 + "'"); ssize = 12; } tbuffer[0] = flags; for(unsigned i = 0; i < 512; i++) { for(unsigned j = 0; j < 512; j++) { tbuffer[4 * j + 1] = buffer[512 * i + j] >> 24; tbuffer[4 * j + 2] = buffer[512 * i + j] >> 16; tbuffer[4 * j + 3] = buffer[512 * i + j] >> 8; tbuffer[4 * j + 4] = buffer[512 * i + j]; } out.write(reinterpret_cast(tbuffer + (i ? 1 : 0)), i ? 2048 : 2049); } if(!out) throw std::runtime_error("Failed to write frame"); ssize += 1048577; } void sdump_sample(short left, short right) { if(!sdump_in_progress || !sdump_iopen) return; unsigned char pkt[5]; pkt[0] = 16; pkt[1] = static_cast(left) >> 8; pkt[2] = static_cast(left); pkt[3] = static_cast(right) >> 8; pkt[4] = static_cast(right); out.write(reinterpret_cast(pkt), 5); if(!out) throw std::runtime_error("Failed to write sample"); ssize += 5; }