Evdev joystick plugin
[lsnes.git] / generic / sdump.cpp
blobe3e0897abee907c28e9442dd42fa8937c74bc7be
1 #include "lsnes.hpp"
2 #include <snes/snes.hpp>
3 #include "sdump.hpp"
4 #include <fstream>
5 #include <stdexcept>
6 #include <iomanip>
7 #include "avsnoop.hpp"
8 #include "command.hpp"
9 #include "misc.hpp"
11 #define CUTOFF 2100000000
13 namespace
15 bool sdump_in_progress;
16 std::string oprefix;
17 std::ofstream out;
18 uint32_t ssize;
19 uint32_t next_seq;
20 bool sdump_iopen;
21 bool sdump_ss;
23 class dummy_avsnoop : public av_snooper
25 public:
26 dummy_avsnoop() throw(std::bad_alloc)
30 ~dummy_avsnoop() throw()
34 void frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d) throw(std::bad_alloc,
35 std::runtime_error)
39 void sample(short l, short r) throw(std::bad_alloc, std::runtime_error)
43 void end() throw(std::bad_alloc, std::runtime_error)
45 if(sdump_iopen)
46 out.close();
47 if(sdump_in_progress)
48 sdump_in_progress = false;
51 void gameinfo(const std::string& gamename, const std::list<std::pair<std::string, std::string>>&
52 authors, double gametime, const std::string& rerecords) throw(std::bad_alloc, std::runtime_error)
56 dummy_avsnoop* snooper;
58 function_ptr_command<const std::string&> jmd_dump("dump-sdmp", "Start sdmp capture",
59 "Syntax: dump-sdmp <prefix>\nStart SDMP capture to <prefix>\n",
60 [](const std::string& prefix) throw(std::bad_alloc, std::runtime_error) {
61 if(prefix == "")
62 throw std::runtime_error("Expected filename");
63 sdump_open(prefix, false);
64 messages << "Dumping to " << prefix << std::endl;
65 });
67 function_ptr_command<const std::string&> jmd_dumpss("dump-sdmpss", "Start SS sdmp capture",
68 "Syntax: dump-sdmpss <file>\nStart SS SDMP capture to <file>\n",
69 [](const std::string& prefix) throw(std::bad_alloc, std::runtime_error) {
70 if(prefix == "")
71 throw std::runtime_error("Expected filename");
72 sdump_open(prefix, true);
73 messages << "Dumping to " << prefix << std::endl;
74 });
76 function_ptr_command<> end_avi("end-sdmp", "End SDMP capture",
77 "Syntax: end-sdmp\nEnd a SDMP capture.\n",
78 []() throw(std::bad_alloc, std::runtime_error) {
79 sdump_close();
80 messages << "Dump finished" << std::endl;
81 });
84 void sdump_open(const std::string& prefix, bool ss)
86 if(sdump_in_progress)
87 throw std::runtime_error("Dump already in progress");
88 oprefix = prefix;
89 snooper = new dummy_avsnoop;
90 sdump_ss = ss;
91 sdump_in_progress = true;
92 ssize = 0;
93 next_seq = 0;
94 sdump_iopen = false;
97 void sdump_close()
99 if(!sdump_in_progress)
100 throw std::runtime_error("No dump in progress");
101 if(sdump_iopen)
102 out.close();
103 sdump_in_progress = false;
104 delete snooper;
107 void sdump_frame(const uint32_t* buffer, unsigned flags)
109 flags &= 0xF;
110 unsigned char tbuffer[2049];
111 if(!sdump_in_progress)
112 return;
113 if(!sdump_iopen || (ssize > CUTOFF && !sdump_ss)) {
114 std::cerr << "Starting new segment" << std::endl;
115 if(sdump_iopen)
116 out.close();
117 std::ostringstream str;
118 if(sdump_ss)
119 str << oprefix;
120 else
121 str << oprefix << "_" << std::setw(4) << std::setfill('0') << (next_seq++) << ".sdmp";
122 std::string str2 = str.str();
123 out.open(str2.c_str(), std::ios::out | std::ios::binary);
124 if(!out)
125 throw std::runtime_error("Failed to open '" + str2 + "'");
126 sdump_iopen = true;
127 tbuffer[0] = 'S';
128 tbuffer[1] = 'D';
129 tbuffer[2] = 'M';
130 tbuffer[3] = 'P';
131 uint32_t apufreq = SNES::system.apu_frequency();
132 uint32_t cpufreq = SNES::system.cpu_frequency();
133 tbuffer[4] = cpufreq >> 24;
134 tbuffer[5] = cpufreq >> 16;
135 tbuffer[6] = cpufreq >> 8;
136 tbuffer[7] = cpufreq;
137 tbuffer[8] = apufreq >> 24;
138 tbuffer[9] = apufreq >> 16;
139 tbuffer[10] = apufreq >> 8;
140 tbuffer[11] = apufreq;
141 out.write(reinterpret_cast<char*>(tbuffer), 12);
142 if(!out)
143 throw std::runtime_error("Failed to write header to '" + str2 + "'");
144 ssize = 12;
146 tbuffer[0] = flags;
147 for(unsigned i = 0; i < 512; i++) {
148 for(unsigned j = 0; j < 512; j++) {
149 tbuffer[4 * j + 1] = buffer[512 * i + j] >> 24;
150 tbuffer[4 * j + 2] = buffer[512 * i + j] >> 16;
151 tbuffer[4 * j + 3] = buffer[512 * i + j] >> 8;
152 tbuffer[4 * j + 4] = buffer[512 * i + j];
154 out.write(reinterpret_cast<char*>(tbuffer + (i ? 1 : 0)), i ? 2048 : 2049);
156 if(!out)
157 throw std::runtime_error("Failed to write frame");
158 ssize += 1048577;
161 void sdump_sample(short left, short right)
163 if(!sdump_in_progress || !sdump_iopen)
164 return;
165 unsigned char pkt[5];
166 pkt[0] = 16;
167 pkt[1] = static_cast<unsigned short>(left) >> 8;
168 pkt[2] = static_cast<unsigned short>(left);
169 pkt[3] = static_cast<unsigned short>(right) >> 8;
170 pkt[4] = static_cast<unsigned short>(right);
171 out.write(reinterpret_cast<char*>(pkt), 5);
172 if(!out)
173 throw std::runtime_error("Failed to write sample");
174 ssize += 5;