#pragma once #include "FluidSim/AudioProcessing.hpp" #include "FluidSim/Crankcase.hpp" #include "FluidSim/Fluid.hpp" #include "FluidSim/OutdoorExhaustReverb.hpp" #include "FluidSim/Solver.hpp" #include "FluidSim/TwoStrokeCylinder.hpp" #include #include namespace fluidsim::port { struct TwoStrokeSnapshot { float rpm{}, cylinder_pressure{}, crankcase_pressure{}, intake_pressure{}; float throttle{}, transfer_area{}, exhaust_area{}; bool reed_open{}; }; // Port of the C# 125 cc crankcase-scavenged two-stroke scenario. It retains // the plenum / reed / crankcase / transfer / cylinder / exhaust topology. class TwoStrokeScenario { public: explicit TwoStrokeScenario(int sample_rate = 44100); AudioFrame process(); void set_throttle(float value); TwoStrokeSnapshot snapshot() const; float throttle{}; Crankshaft crankshaft{}; TwoStrokeCylinder cylinder; Crankcase crankcase; Volume0D intake_plenum{0.5e-3f, 101325.0f, 300.0f}; std::vector pipes; private: float dt_{}, max_throttle_area_{}; float reed_in_area_{}, reed_out_area_{}, transfer_pipe_area_{}, transfer_valve_area_{}, exhaust_valve_area_{}; bool reed_open_{}; std::uint64_t step_count_{}; Port* plenum_inlet_{}; Port* plenum_outlet_{}; BoundarySystem boundaries_; Solver solver_; SoundProcessor intake_sound_; SoundProcessor exhaust_sound_; OutdoorExhaustReverb reverb_; static float area_for_diameter(float diameter); static std::vector create_pipes(); }; } // namespace fluidsim::port