Add turbocharged twin scenario and cross-platform test harness
This commit is contained in:
87
include/FluidSim/DesktopScenario.hpp
Normal file
87
include/FluidSim/DesktopScenario.hpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
#include "FluidSim/Scenario.hpp"
|
||||
#include "FluidSim/TwoStrokeScenario.hpp"
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace fluidsim::port {
|
||||
// Shared desktop controls/snapshot contract. Two-stroke access is serialized;
|
||||
// the twin already protects its own simulation state.
|
||||
class DesktopScenario {
|
||||
public:
|
||||
explicit DesktopScenario(ScenarioKind kind, TwoStrokeConfig config = {}) {
|
||||
if (kind == ScenarioKind::TwoStroke)
|
||||
two_ = std::make_unique<TwoStrokeScenario>(44100, config);
|
||||
else
|
||||
twin_ = std::make_unique<FourStrokeScenario>(44100, kind == ScenarioKind::SaabB205 ?
|
||||
FourStrokePreset::SaabB205 : FourStrokePreset::Twin, kind == ScenarioKind::TurboTwin);
|
||||
}
|
||||
AudioFrame process() {
|
||||
if (twin_)
|
||||
return twin_->process();
|
||||
const std::lock_guard lock(mutex_);
|
||||
return two_->process();
|
||||
}
|
||||
void set_controls(float pedal, float load, float clutch) {
|
||||
visit([&](auto& scenario) { scenario.set_controls(pedal, load, clutch); });
|
||||
}
|
||||
void shift_up() { visit([](auto& scenario) { scenario.shift_up(); }); }
|
||||
void shift_down() { visit([](auto& scenario) { scenario.shift_down(); }); }
|
||||
void set_neutral() { visit([](auto& scenario) { scenario.set_neutral(); }); }
|
||||
void toggle_mechanical_sound() {
|
||||
if (twin_)
|
||||
twin_->toggle_mechanical_sound();
|
||||
}
|
||||
void set_audio_scene(OutdoorScene scene) {
|
||||
visit([&](auto& scenario) { scenario.set_audio_scene(scene); });
|
||||
}
|
||||
ScenarioSnapshot snapshot() const {
|
||||
if (twin_)
|
||||
return twin_->snapshot();
|
||||
const std::lock_guard lock(mutex_);
|
||||
const auto source = two_->snapshot();
|
||||
ScenarioSnapshot s;
|
||||
s.two_stroke = true;
|
||||
s.cylinder_count = 1;
|
||||
s.racing_exhaust = two_->configuration.exhaust == TwoStrokeExhaust::Racing;
|
||||
s.rpm = source.rpm;
|
||||
s.speed_kmh = two_->vehicle.speed * 3.6f;
|
||||
s.kinetic_energy = two_->vehicle.kinetic_energy();
|
||||
s.gear = two_->vehicle.current_gear;
|
||||
s.clutch = two_->clutch;
|
||||
s.average_power = two_->crankshaft.average_power;
|
||||
s.average_torque = two_->crankshaft.average_torque;
|
||||
s.cylinder_pressure1 = source.cylinder_pressure;
|
||||
s.cylinder_temperature1 = two_->cylinder.temperature();
|
||||
s.cylinder_piston_fraction1 =
|
||||
(two_->cylinder.volume - two_->cylinder.clearance_volume()) / two_->cylinder.swept_volume();
|
||||
s.crankcase_pressure = source.crankcase_pressure;
|
||||
s.intake_pressure = source.intake_pressure;
|
||||
s.exhaust_pressure = two_->pipes[3].state(0).pressure;
|
||||
s.throttle = source.throttle;
|
||||
s.pedal = source.pedal;
|
||||
s.target_afr = two_->ecu.target_afr();
|
||||
s.valve1_intake_area = source.transfer_area;
|
||||
s.valve1_exhaust_area = source.exhaust_area;
|
||||
s.reed_open = source.reed_open;
|
||||
s.fuel_cut = source.fuel_cut;
|
||||
s.idle_control = two_->ecu.idle_active();
|
||||
s.rev_limit1 = two_->ecu.rev_limited();
|
||||
s.audio_scene = source.audio_scene;
|
||||
s.intake_flow = two_->intake_flow;
|
||||
s.exhaust_flow = two_->exhaust_flow;
|
||||
s.capture_pipes(two_->pipes);
|
||||
return s;
|
||||
}
|
||||
|
||||
private:
|
||||
template<class Function> void visit(Function&& function) {
|
||||
const std::lock_guard lock(mutex_);
|
||||
if (twin_) function(*twin_);
|
||||
else function(*two_);
|
||||
}
|
||||
std::unique_ptr<FourStrokeTwinScenario> twin_;
|
||||
std::unique_ptr<TwoStrokeScenario> two_;
|
||||
mutable std::mutex mutex_;
|
||||
};
|
||||
} // namespace fluidsim::port
|
||||
Reference in New Issue
Block a user