// Boot firmware 5.0.0.2084, send MIDI, and record three seconds of mono PCM. #include "targets/main.hpp" #include "control/panel.hpp" #include #include #include #include #include #include #include int main(int argc, char **argv) { try { if (argc != 3) throw std::runtime_error("usage: record firmware.bin output.wav"); std::ifstream input(argv[1], std::ios::binary); if (!input) throw std::runtime_error("cannot open firmware"); std::vector bytes{std::istreambuf_iterator(input), {}}; auto main = mf::Main::create(std::as_bytes(std::span(bytes))); main->boot(); uint8_t sequence = 0; auto parameter = [&](uint16_t id, uint16_t raw) { const auto command = "synth param " + std::to_string(id) + " " + std::to_string(raw); std::vector sysex{0xf0, 0, 0x20, 0x6b, 7, 1, sequence++, static_cast(command.size()), 0x53}; sysex.insert(sysex.end(), command.begin(), command.end()); sysex.push_back(0xf7); main->midi().send(sysex); // Deliver each edit before the next one; discard the settling audio. auto result = main->audio().advance(480, nullptr); if (!result) throw std::runtime_error(result.error().message); }; parameter(0x0000, mf::panel::Param::encode(22, 2)); // SuperWave parameter(0x0001, 0); // saw waveform parameter(0x0003, 9000); // moderate detune parameter(0x0005, 24000); // detuned-copy level parameter(0x0601, 1500); // short attack parameter(0x0602, 15000); // decay/release tail parameter(0x0603, 24000); // sustain // std::ofstream wav(argv[2], std::ios::binary); wav.exceptions(std::ios::failbit | std::ios::badbit); auto le = [&](uint32_t value, unsigned count) { for (unsigned i = 0; i < count; ++i) wav.put(static_cast(value >> (8 * i))); }; constexpr uint32_t rate = 48000, frames = rate * 3; wav.write("RIFF", 4); le(36 + frames * 2, 4); wav.write("WAVEfmt ", 8); le(16, 4); le(1, 2); le(1, 2); le(rate, 4); le(rate * 2, 4); le(2, 2); le(16, 2); wav.write("data", 4); le(frames * 2, 4); const std::array on{0x90, 60, 100}, off{0x80, 60, 0}; main->midi().send(on); std::array block{}; for (uint32_t pos = 0; pos < frames; pos += block.size()) { if (pos == rate * 2) main->midi().send(off); auto result = main->audio().advance(block.size(), block.data()); if (!result) throw std::runtime_error(result.error().message); for (float sample : block) le(static_cast(static_cast(std::clamp(sample, -1.f, 1.f) * 32767)), 2); } wav.close(); } catch (const std::exception &e) { std::cerr << e.what() << '\n'; return 1; } }