Skip to content

wityAudioProfile — Audio Loudness Analysis

Lambda service that measures actual audio loudness over time from a wity-scene document. Downloads all ws-video and ws-audio media, decodes their audio tracks via FFmpeg, computes windowed RMS loudness, applies XML volume multipliers, and returns per-element and power-mixed loudness profiles in dBFS.

Unlike the rendering pipeline, this is a standalone analysis service — not routed through witySceneRender. Call wityAudioProfile directly.

Node.js / Lambda only. Requires FFmpeg.


analyzeAudioProfile(sceneXml, options)

js
import { analyzeAudioProfile } from './index.js';  // internal service

analyzeAudioProfile(
  sceneXml: string,
  options?: {
    windowMs?:   number,   // RMS window size in ms (default 100)
    sampleRate?: number,   // decode sample rate Hz (default 16000)
  }
): Promise<AudioProfileResult>
OptionTypeDefaultDescription
windowMsnumber100RMS measurement window size in milliseconds
sampleRatenumber16000PCM decode sample rate. Lower = faster, less resolution

Output shape

ts
interface AudioProfileResult {
  sceneDuration: number;          // resolved scene duration in seconds
  windowMs:      number;          // window size used
  sampleRate:    number;          // sample rate used
  elements:      ElementProfile[];
  mixed:         LoudnessProfile; // power-sum mix of all element profiles
}

interface ElementProfile {
  id:       string;
  tag:      'ws-video' | 'ws-audio';
  src:      string;
  begin:    number;               // scene timeline offset (seconds)
  dur:      number | null;        // null = resolved from source duration
  volume:   number;               // XML volume attribute (0–1)
  hasAudio: boolean;              // false if file has no audio track or muted="true"
  profile:  LoudnessProfile | null;  // null if hasAudio is false or decode failed
}

interface LoudnessProfile {
  startTime:   number;     // scene timeline offset of window[0] (seconds)
  windowCount: number;     // number of windows
  windowMs:    number;     // window size in ms
  rmsLinear:   number[];   // per-window RMS amplitude 0.0–1.0, volume-adjusted
  rmsDbfs:     number[];   // per-window dBFS (20 * log10(rmsLinear)); -Infinity for silence
  peakDbfs:    number;     // loudest window in dBFS
  avgDbfs:     number;     // RMS average in dBFS
}

Volume adjustment: rmsLinear values have the element's XML volume multiplier applied before dBFS conversion — what you see is what you'd hear in the final mix.

Mixed profile: Power-additive (sum of rms²sqrt) across all elements, mapped to the scene timeline. startTime is always 0.


What is processed

Element typeProcessed?
ws-videoYes — audio track decoded; skipped if muted="true" or no audio track
ws-audioYes — audio decoded
ws-rect, ws-text, ws-imageNo — silently ignored

Lambda deployment

Function name: wityAudioProfile

Input

json
{
  "sceneXml": "<wity-scene>...</wity-scene>",
  "options": {
    "windowMs":   100,
    "sampleRate": 16000
  }
}

Response

The full AudioProfileResult object:

json
{
  "sceneDuration": 15.0,
  "windowMs": 100,
  "sampleRate": 16000,
  "elements": [
    {
      "id": "v1", "tag": "ws-video", "src": "https://...", "begin": 0, "dur": 15,
      "volume": 0.8, "hasAudio": true,
      "profile": {
        "startTime": 0, "windowCount": 150, "windowMs": 100,
        "rmsLinear": [0.12, 0.15, "..."],
        "rmsDbfs": [-18.4, -16.5, "..."],
        "peakDbfs": -6.2, "avgDbfs": -18.1
      }
    }
  ],
  "mixed": {
    "startTime": 0, "windowCount": 150, "windowMs": 100,
    "rmsLinear": ["..."], "rmsDbfs": ["..."],
    "peakDbfs": -5.8, "avgDbfs": -16.3
  }
}

Lambda config

SettingValue
Function namewityAudioProfile
Memory1024 MB
Timeout120 s
Ephemeral storage2048 MB
RuntimeNode.js 20
FFmpeg layerarn:aws:lambda:ap-south-1:175033217214:layer:ffmpeg:1

Edge cases

ScenarioBehaviour
No audio track in video filehasAudio: false, profile: null
muted="true" on ws-videoTreated as no audio
Infinite durSource duration probed via ffprobe; clamped to sceneDur - begin
trimOut setFFmpeg -to trimOut limits decode window
Empty scene (no ws-video/ws-audio)Returns empty elements[] and a zero mixed profile
Decode error on one elementElement included with hasAudio: true, profile: null; error logged; other elements continue