flowlang-cc / elm-audio-graph / AudioGraph

The AudioGraph module provides methods to construct detailed, type safe, web audio processing graphs in Elm. You can then use the AudioGraph.Encode module to serialise these graphs into JSON for proper reconstruction in javascript.

Definition


type AudioGraph
    = AudioGraph ({ nodes : Dict NodeID AudioNode, connections : List Connection })

The AudioGraph keeps track of all active audio nodes and their connections.

createAudioGraph : AudioGraph

The primary method of creating a new AudioGraph. It is empty except for the default destination node stored under "__destination" NodeID. This typically represents the speaker output of your device.

See createAudioDestinationNote for more information.

AudioGraph Manipulations

setNode : NodeID -> AudioNode -> AudioGraph -> AudioGraph

Inserts a new AudioNode into the graph with the supplied id string. If a node already exists at the supplied id, the current node is replaced with the new one.

getNode : NodeID -> AudioGraph -> Maybe AudioNode

Queries the graph for the AudioNode at the supplied id string. Can return Just AudioNode or Nothing if no node exists at that id.

removeNode : NodeID -> AudioGraph -> AudioGraph

Removes the AudioNode at the supplied id string from the graph. This is a no-op if no node exists at that id.

addConnection : Connection -> AudioGraph -> AudioGraph

Adds a new connection for the graph to track. There is a guard to prevent duplicate connections being added.

removeConnection : Connection -> AudioGraph -> AudioGraph

Removes the supplied connection from the graph. If the connection doesn't exist this is a no-op.

Audio Nodes


type AudioNode
    = AudioNode ({ nodeType : NodeType, params : List AudioParam, properties : List NodeProperty, inputs : List NodeInput, numOutputs : Basics.Int })

AudioNodes are the central focus of an AudioGraph. They represent any arbitrary audio processing node in a graph and can have any number of inputs, outputs, parameters, and properties.


type alias NodeID =
String

A simple type alias for more expressive type annotations. NodeIDs are used as keys in the AudioGraph nodes dictionary.


type NodeType
    = AnalyserNode
    | AudioBufferSourceNode
    | AudioDestinationNode
    | BiquadFilterNode
    | ChannelMergerNode
    | ChannelSplitterNode
    | ConstantSourceNode
    | ConvolverNode
    | DelayNode
    | DynamicsCompressorNode
    | GainNode
    | IIRFilterNode
    | OscillatorNode
    | PannerNode
    | StereoPannerNode
    | WaveShaperNode

Describes what type of node an AudioNode represents. These are 1:1 mappings of the audio nodes detailed in the Web Audio API so refer here for more information on each node.


type AudioParam
    = AudioParam ({ label : String, value : Units.Value })

The AudioParam type represents a Web Audio audio param. The follow description is abridged from the Web Audio API docs:

The Web Audio API's AudioParam interface represents an audio-related parameter, usually a parameter of an AudioNode (such as GainNode.gain)

There are two kinds of AudioParam, a-rate and k-rate parameters:

The distinction between a-rate and k-rate is useful to know when processing audio, but does not impact how params are used. All AudioParams can be modulated by AudioNodes.


type NodeProperty
    = NodeProperty ({ label : String, value : Units.Value })

A NodeProperty is used in much the same way as an AudioParam. The key distinction is that NodeProperties cannot be modulated by other AudioNodes.

While their values can be updated programmatically, they cannot be continuously modulated by an audio signal.


type NodeInput
    = InputChannel Basics.Int
    | InputParam String

Every AudioNode can have some number of inputs, and these inputs can correspond to a direct audio input channel on the node, or an AudioParam.

Audio Node Constructors

createAnalyserNode : AudioNode

Creates an AnalyserNode.

AudioNode
    { nodeType = AnalyserNode
    , params = []
    , properties =
        [ NodeProperty { label = "fftSize", value = FFT_Size 2048 }
        , NodeProperty { label = "minDecibels", value = Decibels -100 }
        , NodeProperty { label = "maxDecibels", value = Decibels -30 }
        , NodeProperty { label = "smoothingTimeConstant", value = Number 0.8 }
        ]
    , inputs =
        [ InputChannel 0
        ]
    , numOutputs = 1
    }

createAudioBufferSourceNode : AudioNode

Creates an AudioBufferSourceNode.

AudioNode
    { nodeType = AudioBufferSourceNode
    , params =
        [ AudioParam { label = "detune", value = Cents 0 }
        , AudioParam { label = "playbackRate", value = Number 1.0 }
        ]
    , properties =
        [ NodeProperty { label = "buffer", value = Buffer [] }
        , NodeProperty { label = "loop", value = Attribute False }
        , NodeProperty { label = "loopStart", value = Number 0 }
        , NodeProperty { label = "loopEnd", value = Number 0 }
        ]
    , inputs =
        [ InputParam "detune"
        , InputParam "playerbackRate"
        ]
    , numOutputs = 1
    }

createAudioDestinationNode : AudioNode

Creates an AudioDestinationNode.

AudioNode
    { nodeType = AudioDestinationNode
    , params = []
    , properties = []
    , inputs =
        [ InputChannel 0
        ]
    , numOutputs = 0
    }

createBiquadFilterNode : AudioNode

Creates a BiquadFilterNode.

AudioNode
    { nodeType = BiquadFilterNode
    , params =
        [ AudioParam { label = "frequency", value = Hertz 350 }
        , AudioParam { label = "detune", value = Cents 0 }
        , AudioParam { label = "Q", value = Number 1.0 }
        ]
    , properties =
        [ NodeProperty { label = "type", value = FilterType Lowpass }
        ]
    , inputs =
        [ InputParam "frequency"
        , InputParam "detune"
        , InputParam "Q"
        ]
    , numOutputs = 1
    }

createChannelMergerNode : AudioNode

Creates a ChannelMergerNode.

AudioNode
    { nodeType = ChannelMergerNode
    , params = []
    , properties = []
    , inputs =
        [ InputChannel 0
        , InputChannel 1
        , InputChannel 2
        , InputChannel 3
        , InputChannel 4
        , InputChannel 5
        ]
    , numOutputs = 1
    }

createChannelSplitterNode : AudioNode

Creates a ChannelSplitterNode.

AudioNode
    { nodeType = ChannelSplitterNode
    , params = []
    , properties = []
    , inputs =
        [ InputChannel 0
        ]
    , numOutputs = 6
    }

createConstantSourceNode : AudioNode

Creates a ConstantSourceNode.

AudioNode
    { nodeType = ConstantSourceNode
    , params =
        [ AudioParam { label = "offset", value = Number 1.0 }
        ]
    , properties = []
    , inputs =
        [ InputParam "offset"
        ]
    , numOutputs = 1
    }

createConvolverNode : AudioNode

Creates a ConvolverNode.

AudioNode
    { nodeType = ConvolverNode
    , params = []
    , properties =
        [ NodeProperty { label = "buffer", value = Buffer [] }
        , NodeProperty { label = "normalize", value = Attribute False }
        ]
    , inputs =
        [ InputChannel 0
        ]
    , numOutputs = 1
    }

createDelayNode : AudioNode

Creates a DelayNode.

AudioNode
    { nodeType = DelayNode
    , params =
        [ AudioParam { label = "delayTime", value = Number 0 }
        ]
    , properties =
        [ NodeProperty { label = "maxDelayTime", value = Number 1.0 }
        ]
    , inputs =
        [ InputChannel 0
        , InputParam "delayTime"
        ]
    , numOutputs = 1
    }

createDynamicsCompressorNode : AudioNode

Creates a DynamicsCompressorNode.

AudioNode
    { nodeType = DynamicsCompressorNode
    , params =
        [ AudioParam { label = "threshold", value = Decibels -24 }
        , AudioParam { label = "knee", value = Decibels 30 }
        , AudioParam { label = "ratio", value = Number 12 }
        , AudioParam { label = "attack", value = Number 0.003 }
        , AudioParam { label = "release", value = Number 0.25 }
        ]
    , properties = []
    , inputs =
        [ InputChannel 0
        , InputParam "threshold"
        , InputParam "knee"
        , InputParam "ratio"
        , InputParam "attack"
        , InputParam "release"
        ]
    , numOutputs = 1
    }

createGainNode : AudioNode

Creates a GainNode.

AudioNode
    { nodeType = GainNode
    , params =
        [ AudioParam { label = "gain", value = Number 1.0 }
        ]
    , properties = []
    , inputs =
        [ InputChannel 0
        , InputParam "gain"
        ]
    , numOutputs = 1
    }

createIIRFilterNode : AudioNode

Creates an IIRFilterNode.

AudioNode
    { nodeType = IIRFilterNode
    , params =
        [ AudioParam { label = "feedforward", value = Coefficients [] }
        , AudioParam { label = "feedbackward", value = Coefficients [] }
        ]
    , properties = []
    , inputs =
        [ InputChannel 0
        , InputParam "feedforward"
        , InputParam "feedbackward"
        ]
    , numOutputs = 1
    }

createOscillatorNode : AudioNode

Creates an OscillatorNode.

AudioNode
    { nodeType = OscillatorNode
    , params =
        [ AudioParam { label = "frequency", value = Hertz 350 }
        , AudioParam { label = "detune", value = Cents 0 }
        ]
    , properties =
        [ NodeProperty { label = "type", value = WaveformType Sine }
        ]
    , inputs =
        [ InputParam "frequency"
        , InputParam "detune"
        ]
    , numOutputs = 1
    }

createPannerNode : AudioNode

Creates a PannerNode.

AudioNode
    { nodeType = PannerNode
    , params =
        [ AudioParam { label = "orientationX", value = Number 1 }
        , AudioParam { label = "orientationY", value = Number 0 }
        , AudioParam { label = "orientationZ", value = Number 0 }
        , AudioParam { label = "positionX", value = Number 0 }
        , AudioParam { label = "positionY", value = Number 0 }
        , AudioParam { label = "positionZ", value = Number 0 }
        ]
    , properties =
        [ NodeProperty { label = "coneInnerAngle", value = Number 360 }
        , NodeProperty { label = "coneOuterAngle", value = Number 0 }
        , NodeProperty { label = "coneOuterGain", value = Number 0 }
        , NodeProperty { label = "distanceModel", value = DistanceModelType Inverse }
        , NodeProperty { label = "maxDistance", value = Number 10000 }
        , NodeProperty { label = "panningModel", value = PanningModelType EqualPower }
        , NodeProperty { label = "refDistance", value = Number 1 }
        , NodeProperty { label = "rolloffFactor", value = Number 1 }
        ]
    , inputs =
        [ InputChannel 0
        , InputParam "orientationX"
        , InputParam "orientationY"
        , InputParam "orientationZ"
        , InputParam "positionX"
        , InputParam "positionY"
        , InputParam "positionZ"
        ]
    , numOutputs = 1
    }

createStereoPannerNode : AudioNode

Creates a StereoPannerNode.

AudioNode
    { nodeType = StereoPannerNode
    , params =
        [ AudioParam { label = "pan", value = Number 0 }
        ]
    , properties = []
    , inputs =
        [ InputChannel 0
        , InputParam "pan"
        ]
    , numOutputs = 1
    }

createWaveShaperNode : AudioNode

Creates a WaveShaperNode.

AudioNode
    { nodeType = WaveShaperNode
    , params = []
    , properties =
        [ NodeProperty { label = "curve", value = WaveshaperCurve [] }
        , NodeProperty { label = "oversample", value = OversampleType None }
        ]
    , inputs =
        [ InputChannel 0
        ]
    , numOutputs = 1
    }

AudioNode Manipulations

updateParam : String -> Units.Value -> AudioNode -> AudioNode

Update the Value stored in an AudioParam.

Note: If an AudioNode is connected to this param, updateParam will have no effect.

updateProperty : String -> Units.Value -> AudioNode -> AudioNode

Update the Value stored in a NodeProperty.

Connecting AudioNodes


type alias Connection =
{ outputNode : NodeID
, outputChannel : Basics.Int
, inputNode : NodeID
, inputDestination : NodeInput 
}

A Connection describes how one AudioNode connects to another. A connection can exist in two forms: either a node can connect directly to another node's audio input, or a node can connect to another node's params. The type of connection is detailed by the inputDestination field.

See the NodeInput definition for more information.

-- Connect the output of "oscA" to the first input
-- of "gain".
connect "oscA" 0 "gain" (InputChannel 0)

-- Connect the output of "oscB" to the frequency param
-- of "oscA" to perform frequency modulation.
connect "oscB" 0 "oscA" (InputParam "frequency")

connect : NodeID -> Basics.Int -> NodeID -> NodeInput -> Connection

A simple helper function to create a Connection. This is the preferred way to construct Connections to avoid breaking API changes if the Conncection type alias changes.