{"spec_id":"waveform-audio","library":"makie","language":"julia","code":"# anyplot.ai\n# waveform-audio: Audio Waveform Plot\n# Library: makie 0.22.10 | Julia 1.11.9\n# Quality: 93/100 | Created: 2026-06-03\n\nusing CairoMakie\nusing Colors\nusing Random\nusing Statistics\n\nRandom.seed!(42)\n\nconst THEME       = get(ENV, \"ANYPLOT_THEME\", \"light\")\nconst PAGE_BG     = THEME == \"light\" ? colorant\"#FAF8F1\" : colorant\"#1A1A17\"\nconst ELEVATED_BG = THEME == \"light\" ? colorant\"#FFFDF6\" : colorant\"#242420\"\nconst INK         = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nconst INK_SOFT    = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\nconst IMPRINT_PALETTE = [\n    colorant\"#009E73\", colorant\"#C475FD\", colorant\"#4467A3\", colorant\"#BD8233\",\n    colorant\"#AE3030\", colorant\"#2ABCCD\", colorant\"#954477\", colorant\"#99B314\",\n]\nconst BRAND = IMPRINT_PALETTE[1]\n\n# Data — synthetic seismogram: noise floor, P-wave arrival at 5 s, S-wave at 10 s\nsample_rate = 1000\nduration    = 30.0\nn_samples   = Int(sample_rate * duration)\nt           = collect(range(0.0, duration, length=n_samples))\n\nnoise = 0.015 .* randn(n_samples)\n\np_start = Int(5.0 * sample_rate) + 1\np_end   = min(Int(8.0 * sample_rate), n_samples)\nt_p     = collect(range(0.0, 3.0, length=p_end - p_start + 1))\np_wave  = zeros(n_samples)\np_wave[p_start:p_end] .= 0.3 .* sin.(2π .* 3.0 .* t_p) .* exp.(-0.6 .* t_p)\n\ns_start = Int(10.0 * sample_rate) + 1\ns_end   = min(Int(22.0 * sample_rate), n_samples)\nt_s     = collect(range(0.0, 12.0, length=s_end - s_start + 1))\ns_wave  = zeros(n_samples)\ns_wave[s_start:s_end] .= 0.85 .* sin.(2π .* 1.5 .* t_s) .* exp.(-0.25 .* t_s)\n\namplitude = noise .+ p_wave .+ s_wave\n\n# Min/max envelope (100 ms windows) avoids aliasing artifacts in dense waveform\nwindow_size = 100\nn_windows   = div(n_samples, window_size)\nt_env   = [mean(t[(i-1)*window_size+1 : i*window_size]) for i in 1:n_windows]\namp_min = [minimum(amplitude[(i-1)*window_size+1 : i*window_size]) for i in 1:n_windows]\namp_max = [maximum(amplitude[(i-1)*window_size+1 : i*window_size]) for i in 1:n_windows]\n\n# Plot\nfig = Figure(\n    size            = (1600, 900),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    title              = \"Earthquake Seismogram · waveform-audio · julia · makie · anyplot.ai\",\n    titlesize          = 20,\n    titlecolor         = INK,\n    xlabel             = \"Time (seconds)\",\n    ylabel             = \"Normalized Amplitude\",\n    xlabelsize         = 14,\n    ylabelsize         = 14,\n    xticklabelsize     = 12,\n    yticklabelsize     = 12,\n    xlabelcolor        = INK,\n    ylabelcolor        = INK,\n    xticklabelcolor    = INK_SOFT,\n    yticklabelcolor    = INK_SOFT,\n    xtickcolor         = INK_SOFT,\n    ytickcolor         = INK_SOFT,\n    backgroundcolor    = PAGE_BG,\n    topspinevisible    = false,\n    rightspinevisible  = false,\n    leftspinecolor     = INK_SOFT,\n    bottomspinecolor   = INK_SOFT,\n    xgridvisible       = false,\n    ygridvisible       = true,\n    ygridcolor         = RGBAf(INK.r, INK.g, INK.b, 0.12),\n    yticks             = [-1.0, -0.5, 0.0, 0.5, 1.0],\n)\n\nxlims!(ax, 0.0, duration)\nylims!(ax, -1.1, 1.1)\n\n# Subtle noise-floor shading behind waveform (±2σ of background noise)\nnoise_floor = 0.015 * 2.0\nband!(ax, [0.0, duration], [-noise_floor, -noise_floor], [noise_floor, noise_floor];\n    color = RGBAf(BRAND.r, BRAND.g, BRAND.b, 0.08))\n\n# Waveform envelope fill — semi-transparent Imprint brand green with stroke outline\nband!(ax, t_env, amp_min, amp_max; color = (BRAND, 0.72))\nlines!(ax, t_env, amp_max; color = (BRAND, 0.55), linewidth = 0.8)\nlines!(ax, t_env, amp_min; color = (BRAND, 0.55), linewidth = 0.8)\n\n# Zero-amplitude reference line\nhlines!(ax, [0.0]; color = INK_SOFT, linewidth = 1.2)\n\n# P-wave and S-wave arrival annotations\nvlines!(ax, [5.0]; color = RGBAf(INK.r, INK.g, INK.b, 0.35), linewidth = 1.0, linestyle = :dash)\nvlines!(ax, [10.0]; color = RGBAf(INK.r, INK.g, INK.b, 0.35), linewidth = 1.0, linestyle = :dash)\ntext!(ax, 5.3, 0.95; text = \"P-wave\", fontsize = 11, color = INK_SOFT, align = (:left, :top))\ntext!(ax, 10.3, 0.95; text = \"S-wave\", fontsize = 11, color = INK_SOFT, align = (:left, :top))\n\n# Save\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}