gled-core 2.31.2

The engine of gled without a user interface: inputs, timing, rendering, Art-Net/DMX output and storage
Documentation
//! Starting the engine: what it needs from its creator and its thread.

use std::{collections::HashMap, sync::Arc};

use gled_midi::{HostEvent, native::NativeHost};
use gled_model::asset::scene::grid::GridLocation;
use kanal::{Receiver, unbounded};

use super::{
    Engine, EngineConnector, RenderStats, applied_output::AppliedOutput, devices, midi_tools,
    patch_layout::PatchLayout,
};
use crate::{
    action::UiAction,
    audio::{AudioPool, sound_data::SoundData},
    input::external_control::ExternalControlState,
    pipeline::extract_output::{ExtractOutput, OutputConfig, PreviewOutput},
    runtime::{persistent_state::PersistentState, render_thread::RenderThread, timing::Timing},
    storage::collections::Collections,
};

/// What the engine needs from its creator.
#[derive(Debug)]
pub(crate) struct EngineConfig {
    /// GPU adapter for the render thread's output device.
    pub(crate) adapter: wgpu::Adapter,
    pub(crate) extract_output: ExtractOutput,
    pub(crate) artnet_control_receiver: Receiver<Vec<u8>>,
    /// The rendered output, read back for the preview.
    pub(crate) preview_output: Receiver<PreviewOutput>,
    /// Art-Net and DMX traffic in Mbit/s, in and out.
    pub(crate) network_stats: Receiver<(f64, f64)>,
    /// The machine's hottest temperature sensor in °C, once a second.
    pub(crate) temperature: Receiver<Option<f32>>,
    /// The host of this machine's MIDI ports, and what it reports.
    pub(crate) midi: NativeHost,
    pub(crate) midi_events: Receiver<HostEvent>,
    pub(crate) audio_pool: AudioPool,
}

/// Starts the engine thread. It runs until every connector and connection is
/// dropped.
pub(crate) fn spawn(
    config: EngineConfig,
    actions: Receiver<UiAction>,
) -> anyhow::Result<EngineConnector> {
    let timing = Timing::default();
    let persistent_state = PersistentState::default();
    let render_thread = RenderThread::spawn(
        &config.adapter,
        timing.link(),
        config.extract_output,
        persistent_state.fps_limit(),
    )?;

    let (input_sender, input_receiver) = unbounded();

    let engine = Engine {
        startup: true,
        timing,
        project: None,
        project_id: None,
        selected_scene_instance: GridLocation::default(),
        effect_selection: Default::default(),
        blackout: true,
        blackout_hold: false,
        midi_output_active: false,
        actions,
        inputs: input_receiver,
        sessions: HashMap::new(),
        collections: Collections::default(),
        persistent_state,
        output_config: OutputConfig::default(),
        render_thread,
        external_control_state: ExternalControlState::new(config.artnet_control_receiver),
        audio_pool: config.audio_pool,
        sound_data: SoundData::default(),
        osc_handler: None,
        osc_config: None,
        applied_output: AppliedOutput::default(),
        hovered_routing: None,
        input_log: Arc::default(),
        device_scan: devices::DeviceScan::default(),
        pictures: Default::default(),
        watched_triggers: HashMap::new(),
        midi: midi_tools::MidiTools::new(config.midi, config.midi_events),
        patch_layout: PatchLayout::default(),
        render_stats: RenderStats::default(),
        published_assets: (u64::MAX, Arc::default()),
        preview_output: config.preview_output,
        network_stats_receiver: config.network_stats,
        network_stats: (0.0, 0.0),
        temperature_receiver: config.temperature,
        temperature: None,
        host_name: gethostname::gethostname().to_string_lossy().into_owned(),
        sound: Arc::default(),
        ticks_since_sound: 0,
        preview: None,
    };

    std::thread::Builder::new()
        .name("gled:engine".to_string())
        .spawn(move || engine.run())?;

    Ok(EngineConnector {
        inputs: input_sender,
        next_id: Arc::default(),
    })
}