### Rust OBS Plugin Example: TestModule and TestSource Source: https://github.com/bennetthardwick/rust-obs-plugins/blob/master/README.md This Rust code demonstrates the creation of a basic OBS plugin using the `obs-wrapper` crate. It defines a `TestModule` that implements the `Module` trait and a `TestSource` struct implementing `Sourceable`, `GetNameSource`, and `Module` to register a new source with OBS. ```rust use obs_wrapper:: // Everything required for modules prelude::*, // Everything required for creating a source source::*, // Macro for registering modules obs_register_module, // Macro for creating strings obs_string; // The module that will handle creating the source. struct TestModule { context: ModuleRef } // The source that will be shown inside OBS. struct TestSource; // Implement the Sourceable trait for TestSource, this is required for each source. // It allows you to specify the source ID and type. impl Sourceable for TestSource { fn get_id() -> ObsString { obs_string!("test_source") } fn get_type() -> SourceType { SourceType::Filter } fn create(create: &mut CreatableSourceContext, source: SourceContext) -> Self { Self } } // Allow OBS to show a name for the source impl GetNameSource for TestSource { fn get_name() -> ObsString { obs_string!("Test Source") } } // Implement the Module trait for TestModule. This will handle the creation of the source and // has some methods for telling OBS a bit about itself. impl Module for TestModule { fn new(context: ModuleRef) -> Self { Self { context } } fn get_ctx(&self) -> &ModuleRef { &self.context } // Load the module - create all sources, returning true if all went well. fn load(&mut self, load_context: &mut LoadContext) -> bool { // Create the source let source = load_context .create_source_builder::() // Since GetNameSource is implemented, this method needs to be called to // enable it. .enable_get_name() .build(); // Tell OBS about the source so that it will show it. load_context.register_source(source); // Nothing could have gone wrong, so return true. true } fn description() -> ObsString { obs_string!("A great test module.") } fn name() -> ObsString { obs_string!("Test Module") } fn author() -> ObsString { obs_string!("Bennett") } } obs_register_module!(TestModule); ``` -------------------------------- ### Rust OBS Plugin - Complete Example Source: https://context7.com/bennetthardwick/rust-obs-plugins/llms.txt This Rust code defines a complete OBS plugin with a custom source. It includes module registration, source creation, property management, and video rendering hooks. Dependencies include the 'obs-wrapper' crate. It takes color and intensity values as input for rendering. ```rust use obs_wrapper::{ graphics::*, obs_register_module, obs_string, prelude::*, properties::*, source::* }; // Plugin module struct struct ExamplePlugin { context: ModuleRef, } impl Module for ExamplePlugin { fn new(context: ModuleRef) -> Self { // Initialize logging obs_wrapper::log::Logger::new().init().ok(); Self { context } } fn get_ctx(&self) -> &ModuleRef { &self.context } fn load(&mut self, load_context: &mut LoadContext) -> bool { log::info!("Loading example plugin"); let source = load_context .create_source_builder::() .enable_get_name() .enable_update() .enable_get_properties() .enable_video_render() .enable_video_tick() .build(); load_context.register_source(source); true } fn unload(&mut self) { log::info!("Unloading example plugin"); } fn description() -> ObsString { obs_string!("Example plugin demonstrating obs-wrapper features") } fn name() -> ObsString { obs_string!("Example Plugin") } fn author() -> ObsString { obs_string!("Plugin Developer") } } // Source implementation struct ExampleSource { source: SourceRef, color: Vec4, intensity: f64, elapsed_time: f32, } impl Sourceable for ExampleSource { fn get_id() -> ObsString { obs_string!("example_source") } fn get_type() -> SourceType { SourceType::Filter } fn create(ctx: &mut CreatableSourceContext, source: SourceRef) -> Self { let settings = &ctx.settings; let red = settings.get(obs_string!("red")).unwrap_or(1.0); let green = settings.get(obs_string!("green")).unwrap_or(1.0); let blue = settings.get(obs_string!("blue")).unwrap_or(1.0); let intensity = settings.get(obs_string!("intensity")).unwrap_or(1.0); Self { source, color: Vec4::new(red, green, blue, 1.0), intensity, elapsed_time: 0.0, } } } impl GetNameSource for ExampleSource { fn get_name() -> ObsString { obs_string!("Example Source") } } impl UpdateSource for ExampleSource { fn update(&mut self, settings: &mut DataObj, _context: &mut GlobalContext) { if let (Some(r), Some(g), Some(b)) = ( settings.get::(obs_string!("red")), settings.get::(obs_string!("green")), settings.get::(obs_string!("blue")), ) { self.color = Vec4::new(r, g, b, 1.0); } if let Some(intensity) = settings.get::(obs_string!("intensity")) { self.intensity = intensity; } } } impl GetPropertiesSource for ExampleSource { fn get_properties(&mut self) -> Properties { let mut props = Properties::new(); props .add( obs_string!("red"), obs_string!("Red"), NumberProp::new_float(0.01) .with_range(0.0..=1.0) .with_slider(), ) .add( obs_string!("green"), obs_string!("Green"), NumberProp::new_float(0.01) .with_range(0.0..=1.0) .with_slider(), ) .add( obs_string!("blue"), obs_string!("Blue"), NumberProp::new_float(0.01) .with_range(0.0..=1.0) .with_slider(), ) .add( obs_string!("intensity"), obs_string!("Intensity"), NumberProp::new_float(0.01) .with_range(0.0..=2.0) .with_slider(), ); props } } impl VideoTickSource for ExampleSource { fn video_tick(&mut self, seconds: f32) { self.elapsed_time += seconds; } } impl VideoRenderSource for ExampleSource { fn video_render(&mut self, _context: &mut GlobalContext, _render: &mut VideoRenderContext) { // Render implementation log::debug!("Rendering frame at time: {:.2}s", self.elapsed_time); } } // Register the module obs_register_module!(ExamplePlugin); ``` -------------------------------- ### Build and Install scroll-focus-filter with Cargo Source: https://github.com/bennetthardwick/rust-obs-plugins/blob/master/plugins/scroll-focus-filter/README.md This code snippet demonstrates how to build the scroll-focus-filter plugin using Cargo and then create a symbolic link to the compiled plugin for OBS. This allows for easier updates without manual copying. ```bash cd rust-obs-plugins cargo build -p scroll-focus-filter --release # Create a symlink to the plugin so that you don't need to copy when rebuilding, you # could alternatively run `sudo cp ./target/release/scrollfocus.so /usr/lib/obs-plugins/` sudo ln -s $(pwd)/target/release/libscrollfocus.so /usr/lib/obs-plugins/libscrollfocus.so ``` -------------------------------- ### Manage OBS Settings with DataObj in Rust Source: https://context7.com/bennetthardwick/rust-obs-plugins/llms.txt Demonstrates how to create, set, get, and manipulate OBS settings data using the DataObj structure. It covers setting default values, reading values with type inference, creating DataObj from JSON and files, exporting to JSON, removing keys, clearing settings, and handling nested objects. ```rust use obs_wrapper::{data::*, obs_string}; use std::borrow::Cow; fn work_with_settings() { // Create new data object let mut settings = DataObj::new(); // Set default values settings.set_default(obs_string!("width"), 1920_i64); settings.set_default(obs_string!("height"), 1080_i64); settings.set_default(obs_string!("fps"), 30.0_f64); settings.set_default(obs_string!("enabled"), true); settings.set_default(obs_string!("name"), obs_string!("Default")); // Read values with type inference let width: Option = settings.get(obs_string!("width")); let height: Option = settings.get(obs_string!("height")); let fps: Option = settings.get(obs_string!("fps")); let enabled: Option = settings.get(obs_string!("enabled")); let name: Option> = settings.get(obs_string!("name")); println!("Resolution: {}x{} @ {} fps", width.unwrap_or(1920), height.unwrap_or(1080), fps.unwrap_or(30.0)); // Create from JSON let json_data = r#"{"bitrate": 6000, "codec": "h264", "enabled": true}"#; if let Some(config) = DataObj::from_json(json_data) { let bitrate: Option = config.get(obs_string!("bitrate")); let codec: Option> = config.get(obs_string!("codec")); println!("Codec: {}, Bitrate: {}", codec.unwrap().as_ref(), bitrate.unwrap()); } // Load from file if let Some(mut file_settings) = DataObj::from_json_file( obs_string!("/path/to/config.json"), Some(obs_string!(".backup")), ) { // Export to JSON if let Some(json_str) = file_settings.get_json() { println!("Settings JSON: {}", json_str); } // Remove a key file_settings.remove(obs_string!("old_setting")); // Clear all values file_settings.clear(); } // Nested objects let mut parent = DataObj::new(); let mut child = DataObj::new(); child.set_default(obs_string!("nested_value"), 42_i64); parent.set_default(obs_string!("child"), child); // Access nested object if let Some(nested) = parent.get::(obs_string!("child")) { let value: Option = nested.get(obs_string!("nested_value")); println!("Nested value: {}", value.unwrap()); } } ``` -------------------------------- ### Implement Per-Frame Animation with video_tick in Rust Source: https://context7.com/bennetthardwick/rust-obs-plugins/llms.txt Illustrates how to create smooth animations in OBS plugins by utilizing the `video_tick` callback. This example defines an `AnimatedOverlay` struct and implements per-frame updates for position, velocity, and animation progress, including easing functions and target position changes. ```rust use obs_wrapper::{graphics::Vec2, obs_string, source::*}; struct AnimatedOverlay { position: Vec2, target_position: Vec2, velocity: Vec2, animation_progress: f32, animation_duration: f32, } impl Sourceable for AnimatedOverlay { fn get_id() -> ObsString { obs_string!("animated_overlay") } fn get_type() -> SourceType { SourceType::Filter } fn create(_ctx: &mut CreatableSourceContext, _source: SourceRef) -> Self { Self { position: Vec2::new(0.0, 0.0), target_position: Vec2::new(0.5, 0.5), velocity: Vec2::new(0.0, 0.0), animation_progress: 0.0, animation_duration: 1.0, } } } impl GetNameSource for AnimatedOverlay { fn get_name() -> ObsString { obs_string!("Animated Overlay") } } // Called every video frame impl VideoTickSource for AnimatedOverlay { fn video_tick(&mut self, seconds: f32) { // Update animation progress self.animation_progress = (self.animation_progress + seconds / self.animation_duration).min(1.0); // Smooth step easing function let t = self.animation_progress; let smoothed = t * t * (3.0 - 2.0 * t); // Interpolate position let dx = self.target_position.x() - self.position.x(); let dy = self.target_position.y() - self.position.y(); self.position.set( self.position.x() + dx * smoothed, self.position.y() + dy * smoothed, ); // Update velocity for physics-based effects self.velocity.set(dx / seconds, dy / seconds); // Reset animation if complete if self.animation_progress >= 1.0 { self.animation_progress = 0.0; // Set new target position self.target_position.set( (self.target_position.x() + 0.1) % 1.0, (self.target_position.y() + 0.1) % 1.0, ); } } } ``` -------------------------------- ### Integrate Rust Logging with OBS Source: https://context7.com/bennetthardwick/rust-obs-plugins/llms.txt This Rust code snippet demonstrates how to integrate Rust's 'log' crate with OBS's logging system using the 'obs_wrapper::log::Logger'. It shows how to initialize the logger with a specified log level and use standard logging macros (trace, debug, info, warn, error). Messages will appear in OBS log files and the console. ```rust use log::{debug, error, info, trace, warn}; use obs_wrapper::log::Logger; fn setup_logging() { // Initialize logger with OBS Logger::new() .with_max_level(log::LevelFilter::Debug) .init() .expect("Failed to initialize logger"); // Use standard Rust logging macros trace!("This is a trace message"); debug!("Debug information: value = {}", 42); info!("Plugin loaded successfully"); warn!("Warning: deprecated feature used"); error!("Error occurred: {}", "something went wrong"); // Messages appear in OBS log files and console } ``` -------------------------------- ### Create OBS Plugin Configuration UI Properties in Rust Source: https://context7.com/bennetthardwick/rust-obs-plugins/llms.txt This Rust code snippet demonstrates how to build a comprehensive configuration UI for an OBS plugin. It utilizes the `obs-wrapper` library to define various property types, including boolean checkboxes, integer and float sliders, text inputs (default, password, multiline), file and directory pickers, color pickers, font selectors, dropdown lists, and editable lists. These properties allow users to customize plugin settings through the OBS interface. ```rust use obs_wrapper::{obs_string, properties::*, string::ObsString}; fn create_advanced_properties() -> Properties { let mut props = Properties::new(); // Boolean checkbox props.add( obs_string!("enable_feature"), obs_string!("Enable Advanced Processing"), BoolProp, ); // Integer slider props.add( obs_string!("quality"), obs_string!("Quality Level"), NumberProp::new_int() .with_range(1..=10) .with_step(1) .with_slider(), ); // Float slider props.add( obs_string!("opacity"), obs_string!("Opacity"), NumberProp::new_float(0.01) .with_range(0.0..=1.0) .with_slider(), ); // Text input props.add( obs_string!("custom_name"), obs_string!("Display Name"), TextProp::new(TextType::Default), ); // Password field props.add( obs_string!("api_key"), obs_string!("API Key"), TextProp::new(TextType::Password), ); // Multiline text props.add( obs_string!("description"), obs_string!("Description"), TextProp::new(TextType::Multiline), ); // File picker props.add( obs_string!("input_file"), obs_string!("Input File"), PathProp::new(PathType::File) .with_filter(obs_string!("Video Files (*.mp4 *.mov);;All Files (*.*)")) .with_default_path(obs_string!("/home/user/videos")), ); // Directory picker props.add( obs_string!("output_dir"), obs_string!("Output Directory"), PathProp::new(PathType::Directory), ); // Color picker props.add( obs_string!("tint_color"), obs_string!("Tint Color"), ColorProp, ); // Font selector props.add( obs_string!("text_font"), obs_string!("Font"), FontProp, ); // Dropdown list (string values) let mut mode_list = props.add_list::( obs_string!("processing_mode"), obs_string!("Processing Mode"), false, // not editable ); mode_list.push("Fast", obs_string!("fast")); mode_list.push("Balanced", obs_string!("balanced")); mode_list.push("Quality", obs_string!("quality")); // Dropdown list (integer values) let mut size_list = props.add_list::( obs_string!("buffer_size"), obs_string!("Buffer Size"), false, ); size_list.push("Small (512)", 512); size_list.push("Medium (1024)", 1024); size_list.push("Large (2048)", 2048); // Editable combo box let mut preset_list = props.add_list::( obs_string!("preset"), obs_string!("Preset"), true, // editable ); preset_list.push("Default", obs_string!("default")); preset_list.push("Custom", obs_string!("custom")); // Editable list of files props.add( obs_string!("file_list"), obs_string!("Input Files"), EditableListProp::new(EditableListType::Files) .with_filter(obs_string!("*.mp4 *.mov")), ); props } ``` -------------------------------- ### Adding obs-wrapper Dependency to Cargo.toml Source: https://github.com/bennetthardwick/rust-obs-plugins/blob/master/README.md This TOML snippet shows how to add the `obs-wrapper` crate as a dependency in your `Cargo.toml` file. It specifies the version and configures the library type for creating dynamic link libraries (cdylib), which are required for OBS plugins. ```toml [dependencies] obs-wrapper = "0.4" [lib] name = "" crate-type = ["cdylib"] ``` -------------------------------- ### Register OBS Plugin Module in Rust Source: https://context7.com/bennetthardwick/rust-obs-plugins/llms.txt Demonstrates how to register a custom plugin module with OBS Studio using the `obs-wrapper` library. This includes defining the module structure, implementing the `Module` trait for initialization, loading, and unloading, and finally registering the module using the `obs_register_module!` macro. It showcases enabling specific capabilities like video rendering and property updates for a source. ```rust use obs_wrapper::{obs_register_module, obs_string, prelude::*, source::*}; struct MyPluginModule { context: ModuleRef, } impl Module for MyPluginModule { fn new(context: ModuleRef) -> Self { Self { context } } fn get_ctx(&self) -> &ModuleRef { &self.context } fn load(&mut self, load_context: &mut LoadContext) -> bool { // Register sources, outputs, etc. let source = load_context .create_source_builder::() .enable_get_name() .enable_video_render() .enable_update() .enable_get_properties() .build(); load_context.register_source(source); true } fn unload(&mut self) { // Cleanup on plugin unload } fn post_load(&mut self) { // Called after all modules loaded } fn description() -> ObsString { obs_string!("My custom OBS plugin for video processing") } fn name() -> ObsString { obs_string!("My Plugin") } fn author() -> ObsString { obs_string!("Your Name") } } // This macro generates all required C entry points obs_register_module!(MyPluginModule); ``` -------------------------------- ### Rust OBS Plugin: Implement Video Filter Source Source: https://context7.com/bennetthardwick/rust-obs-plugins/llms.txt This Rust code implements a video filter source for OBS Studio. It leverages the `obs-wrapper` crate to define source behavior, including initialization, settings updates, UI properties, and video rendering logic using custom shaders. Dependencies include the `obs-wrapper` crate and potentially a shader effect file. ```rust use obs_wrapper::{ graphics::*, media::video::*, obs_string, prelude::*, properties::*, source::* }; struct MyVideoFilter { source: SourceRef, effect: GraphicsEffect, intensity: f64, enabled: bool, } // Required: Define source ID and type impl Sourceable for MyVideoFilter { fn get_id() -> ObsString { obs_string!("my_video_filter") } fn get_type() -> SourceType { SourceType::Filter } fn create(ctx: &mut CreatableSourceContext, source: SourceRef) -> Self { let settings = &ctx.settings; // Load shader effect let mut effect = GraphicsEffect::from_effect_string( obs_string!(include_str!("./shader.effect")), obs_string!("shader.effect"), ).expect("Failed to load shader effect"); let intensity = settings.get(obs_string!("intensity")).unwrap_or(1.0); let enabled = settings.get(obs_string!("enabled")).unwrap_or(true); Self { source, effect, intensity, enabled, } } } // Display name in OBS UI impl GetNameSource for MyVideoFilter { fn get_name() -> ObsString { obs_string!("My Video Filter") } } // Handle settings changes impl UpdateSource for MyVideoVideoFilter { fn update(&mut self, settings: &mut DataObj, _context: &mut GlobalContext) { if let Some(intensity) = settings.get::(obs_string!("intensity")) { self.intensity = intensity; } if let Some(enabled) = settings.get::(obs_string!("enabled")) { self.enabled = enabled; } } } // Define configuration UI impl GetPropertiesSource for MyVideoFilter { fn get_properties(&mut self) -> Properties { let mut props = Properties::new(); props .add( obs_string!("enabled"), obs_string!("Enable Filter"), BoolProp, ) .add( obs_string!("intensity"), obs_string!("Effect Intensity"), NumberProp::new_float(0.01) .with_range(0.0..=2.0) .with_slider(), ); props } } // Render video frames impl VideoRenderSource for MyVideoFilter { fn video_render(&mut self, _context: &mut GlobalContext, render: &mut VideoRenderContext) { if !self.enabled { self.source.skip_video_filter(); return; } let effect = &mut self.effect; let source = &mut self.source; // Get shader parameters if let Some(mut intensity_param) = effect.get_effect_param_by_name::( obs_string!("intensity") ) { let target_cx = source.get_base_width(); let target_cy = source.get_base_height(); source.process_filter_tech( render, effect, (target_cx, target_cy), GraphicsColorFormat::RGBA, GraphicsAllowDirectRendering::NoDirectRendering, obs_string!("Draw"), |context, _effect| { intensity_param.set_float(context, self.intensity as f32); }, ); } } } ``` -------------------------------- ### Manipulate OBS Sources with Rust Source: https://context7.com/bennetthardwick/rust-obs-plugins/llms.txt This Rust code snippet shows how to query and modify properties of OBS sources, including their dimensions, visibility, and state. It also demonstrates media control functions for media sources and how to access target sources for filters. Dependencies include the 'obs_wrapper' crate. ```rust use obs_wrapper::{media::state::MediaState, obs_string, source::*}; fn manipulate_sources(source: &mut SourceRef) { // Query source properties let id = source.id(); let name = source.name().unwrap(); let source_id = source.source_id().unwrap(); let width = source.width(); let height = source.height(); let base_width = source.get_base_width(); let base_height = source.get_base_height(); println!("Source: {} ({})", name.as_str(), source_id.as_str()); println!("Dimensions: {}x{} (base: {}x{})", width, height, base_width, base_height); // Check source state let is_showing = source.showing(); let is_active = source.active(); let is_enabled = source.enabled(); println!("State - Showing: {}, Active: {}, Enabled: {}", is_showing, is_active, is_enabled); // Modify source source.set_name("New Source Name"); source.set_enabled(true); // Media control (for media sources) source.media_play_pause(false); // Play source.media_restart(); let duration = source.media_duration(); // milliseconds let current_time = source.media_time(); // milliseconds source.media_set_time(5000); // Seek to 5 seconds let state = source.media_state(); match state { MediaState::Playing => println!("Media is playing"), MediaState::Paused => println!("Media is paused"), MediaState::Stopped => println!("Media is stopped"), MediaState::Ended => println!("Media has ended"), MediaState::Error => println!("Media error"), _ => {} } source.media_stop(); source.media_next(); // Next track source.media_previous(); // Previous track // Access target source (for filters) source.do_with_target(|target| { let target_width = target.get_base_width(); let target_height = target.get_base_height(); println!("Target dimensions: {}x{}", target_width, target_height); }); } ``` -------------------------------- ### Implement Custom OBS Outputs in Rust Source: https://context7.com/bennetthardwick/rust-obs-plugins/llms.txt This Rust code demonstrates how to create a custom output (for streaming or recording) in OBS using the 'obs_wrapper' crate. It defines a struct that implements the 'Outputable', 'GetNameOutput', 'RawVideoOutput', and 'RawAudioOutput' traits, allowing for custom processing of raw video and audio data. ```rust use obs_wrapper::{ media::audio::*, media::video::*, obs_string, output::*, prelude::* }; struct CustomOutput { width: u32, height: u32, frame_count: u64, } impl Outputable for CustomOutput { fn get_id() -> ObsString { obs_string!("custom_output") } fn create(ctx: &mut CreatableOutputContext) -> Self { Self { width: 1920, height: 1080, frame_count: 0, } } fn start(&mut self) -> bool { println!("Output started"); true } fn stop(&mut self) { println!("Output stopped, total frames: {}", self.frame_count); } } impl GetNameOutput for CustomOutput { fn get_name() -> ObsString { obs_string!("Custom Output") } } impl RawVideoOutput for CustomOutput { fn raw_video(&mut self, video: &VideoDataSourceContext) { self.frame_count += 1; // Access raw video data let width = video.width(); let height = video.height(); let format = video.format(); // Process frame data based on format // Video data available through video context if self.frame_count % 100 == 0 { println!("Processed {} frames ({}x{}, {:?})", self.frame_count, width, height, format); } } } impl RawAudioOutput for CustomOutput { fn raw_audio(&mut self, audio: &mut AudioDataContext) { // Access audio samples for channel in 0..audio.channels() { if let Some(samples) = audio.get_channel_as_mut_slice(channel) { // Process audio samples (f32 values) for sample in samples.iter() { // Audio processing here } } } } } ``` -------------------------------- ### Load and Use HLSL Shader Effect in Rust Source: https://context7.com/bennetthardwick/rust-obs-plugins/llms.txt Loads an HLSL shader from a string, retrieves texture and color parameters, configures a sampler, and applies the shader effect to a video source during rendering. This enables custom visual transformations. ```rust use obs_wrapper::{graphics::*, obs_string, source::*}; struct ShaderFilter { effect: GraphicsEffect, texture_param: GraphicsEffectTextureParam, color_param: GraphicsEffectVec4Param, sampler: GraphicsSamplerState, } impl ShaderFilter { fn new() -> Self { // Load HLSL shader from string let shader_code = r#" uniform float4x4 ViewProj; uniform texture2d image; uniform float4 color_multiplier; sampler_state textureSampler { Filter = Linear; AddressU = Clamp; AddressV = Clamp; }; struct VertData { float4 pos : POSITION; float2 uv : TEXCOORD0; }; VertData VSDefault(VertData v_in) { VertData vert_out; vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); vert_out.uv = v_in.uv; return vert_out; } float4 PSColorFilter(VertData v_in) : TARGET { float4 rgba = image.Sample(textureSampler, v_in.uv); return rgba * color_multiplier; } technique Draw { pass { vertex_shader = VSDefault(v_in); pixel_shader = PSColorFilter(v_in); } } "#; let mut effect = GraphicsEffect::from_effect_string( obs_string!(shader_code), obs_string!("color_filter.effect"), ).expect("Failed to load shader"); // Get shader parameters by name let texture_param = effect .get_effect_param_by_name(obs_string!("image")) .expect("Failed to get texture param"); let color_param = effect .get_effect_param_by_name(obs_string!("color_multiplier")) .expect("Failed to get color param"); // Configure texture sampler let sampler = GraphicsSamplerState::from(GraphicsSamplerInfo::default()); Self { effect, texture_param, color_param, sampler, } } fn render(&mut self, source: &mut SourceRef, render: &mut VideoRenderContext, tint_color: Vec4) { let effect = &mut self.effect; let texture_param = &mut self.texture_param; let color_param = &mut self.color_param; let sampler = &mut self.sampler; let width = source.get_base_width(); let height = source.get_base_height(); source.process_filter_tech( render, effect, (width, height), GraphicsColorFormat::RGBA, GraphicsAllowDirectRendering::NoDirectRendering, obs_string!("Draw"), |context, _effect| { // Set shader parameters color_param.set_vec4(context, &tint_color); texture_param.set_next_sampler(context, sampler); }, ); } } ``` -------------------------------- ### Rust OBS Noise Gate Audio Filter Implementation Source: https://context7.com/bennetthardwick/rust-obs-plugins/llms.txt This Rust code defines a Noise Gate audio filter for OBS. It implements traits for OBS sources, allowing for real-time audio manipulation. Dependencies include the 'obs-wrapper' crate. The filter adjusts audio sample gain based on amplitude thresholds, attack, and release times. ```rust use obs_wrapper::{ media::audio::*, obs_register_module, obs_string, prelude::*, source::* }; struct NoiseGateFilter { threshold: f32, attack_time: f32, release_time: f32, current_gain: f32, sample_rate: f64, channels: usize, } impl Sourceable for NoiseGateFilter { fn get_id() -> ObsString { obs_string!("noise_gate_filter") } fn get_type() -> SourceType { SourceType::Filter } fn create(ctx: &mut CreatableSourceContext, _source: SourceRef) -> Self { let (sample_rate, channels) = ctx.with_audio(|audio| { (audio.sample_rate(), audio.channels()) }); let settings = &ctx.settings; let threshold = settings.get(obs_string!("threshold")).unwrap_or(-40.0); let attack_time = settings.get(obs_string!("attack_time")).unwrap_or(0.01); let release_time = settings.get(obs_string!("release_time")).unwrap_or(0.1); Self { threshold, attack_time, release_time, current_gain: 1.0, sample_rate: sample_rate as f64, channels, } } } impl GetNameSource for NoiseGateFilter { fn get_name() -> ObsString { obs_string!("Noise Gate Filter") } } impl UpdateSource for NoiseGateFilter { fn update(&mut self, settings: &mut DataObj, context: &mut GlobalContext) { if let Some(threshold) = settings.get::(obs_string!("threshold")) { self.threshold = threshold; } if let Some(attack) = settings.get::(obs_string!("attack_time")) { self.attack_time = attack; } if let Some(release) = settings.get::(obs_string!("release_time")) { self.release_time = release; } let sample_rate = context.with_audio(|audio| audio.sample_rate()); self.sample_rate = sample_rate as f64; } } impl GetPropertiesSource for NoiseGateFilter { fn get_properties(&mut self) -> Properties { let mut props = Properties::new(); props .add( obs_string!("threshold"), obs_string!("Threshold (dB)"), NumberProp::new_float(0.1) .with_range(-60.0..=0.0) .with_slider(), ) .add( obs_string!("attack_time"), obs_string!("Attack Time (seconds)"), NumberProp::new_float(0.001) .with_range(0.001..=1.0), ) .add( obs_string!("release_time"), obs_string!("Release Time (seconds)"), NumberProp::new_float(0.001) .with_range(0.001..=2.0), ); props } } impl FilterAudioSource for NoiseGateFilter { fn filter_audio(&mut self, audio: &mut AudioDataContext) { // Process each channel for channel_idx in 0..self.channels { if let Some(samples) = audio.get_channel_as_mut_slice(channel_idx) { for sample in samples.iter_mut() { // Calculate sample amplitude in dB let amplitude_db = 20.0 * sample.abs().log10(); // Determine target gain let target_gain = if amplitude_db > self.threshold { 1.0 } else { 0.0 }; // Apply attack/release envelope let rate = if target_gain > self.current_gain { 1.0 / (self.attack_time * self.sample_rate as f32) } else { 1.0 / (self.release_time * self.sample_rate as f32) }; self.current_gain += (target_gain - self.current_gain) * rate; // Apply gain to sample *sample *= self.current_gain; } } } } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.