// Peak meter overlay for audio debugging #include "effects/peak_meter_effect.h" #include "gpu/post_process_helper.h" #include "gpu/shader_composer.h" #include "util/fatal_error.h" PeakMeter::PeakMeter(const GpuContext& ctx, const std::vector& inputs, const std::vector& outputs, float start_time, float end_time) : Effect(ctx, inputs, outputs, start_time, end_time) { HEADLESS_RETURN_IF_NULL(ctx_.device); const char* shader_main = R"( struct VertexOutput { @builtin(position) position: vec4f, @location(0) uv: vec2f, }; @group(0) @binding(0) var inputSampler: sampler; @group(0) @binding(1) var inputTexture: texture_2d; @group(0) @binding(2) var uniforms: CommonUniforms; @vertex fn vs_main(@builtin(vertex_index) vertexIndex: u32) -> VertexOutput { var output: VertexOutput; var pos = array( vec2f(-1.0, -1.0), vec2f(3.0, -1.0), vec2f(-1.0, 3.0) ); output.position = vec4f(pos[vertexIndex], 0.0, 1.0); output.uv = pos[vertexIndex] * 0.5 + 0.5; return output; } @fragment fn fs_main(input: VertexOutput) -> @location(0) vec4f { let bar_y_min = 0.005; let bar_y_max = 0.015; let bar_x_min = 0.015; let bar_x_max = 0.250; let in_bar_y = input.uv.y >= bar_y_min && input.uv.y <= bar_y_max; let in_bar_x = input.uv.x >= bar_x_min && input.uv.x <= bar_x_max; if (in_bar_y && in_bar_x) { let uv_x = (input.uv.x - bar_x_min) / (bar_x_max - bar_x_min); let factor = step(uv_x, uniforms.audio_intensity); return mix(vec4f(0.0, 0.0, 0.0, 1.0), vec4f(1.0, 0.0, 0.0, 1.0), factor); } return textureSample(inputTexture, inputSampler, input.uv); } )"; std::string shader_code = ShaderComposer::Get().Compose({"common_uniforms"}, shader_main); pipeline_.set(create_post_process_pipeline( ctx_.device, WGPUTextureFormat_RGBA8Unorm, shader_code.c_str())); } void PeakMeter::render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, NodeRegistry& nodes) { WGPUTextureView input_view = nodes.get_view(input_nodes_[0]); WGPUTextureView output_view = nodes.get_view(output_nodes_[0]); pp_update_bind_group(ctx_.device, pipeline_.get(), bind_group_.get_address(), input_view, uniforms_buffer_.get(), {nullptr, 0}); run_fullscreen_pass(encoder, pipeline_.get(), bind_group_.get(), output_view, WGPULoadOp_Load); }