lue-bird / elm-state-interface / Web.Audio

Play Audio as part of an Interface.

import Time
import Web
import Web.Audio

type alias State =
    { audioSource : Maybe (Result Web.AudioSourceLoadError Web.AudioSource)
    , audioStartTime : Maybe Time.Posix
    }

{ initialState =
    { audioSource = Nothing
    , audioStartTime = Nothing
    }
, interface =
    \state ->
        case state.audioSource of
            Just (Ok audioSource) ->
                case state.audioStartTime of
                    Just startTime
                        Web.Audio.fromSource audioSource startTime
                            |> Web.Audio.play


                    Nothing ->
                        Web.Time.posixRequest
                            |> Web.interfaceFutureMap
                                (\time -> { state | audioSTartTime = time |> Just })

            Nothing ->
                Web.Audio.sourceLoad "https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/Yodel_Sound_Effect.mp3"
                    |> Web.interfaceFutureMap
                        (\result -> { state | audioSource = result |> Just })

            Just (Err _) ->
                Web.Console.error "audio failed to load"
}

sourceLoad : String -> Web.Interface (Result Web.AudioSourceLoadError Web.AudioSource)

An Interface for fetching audio data from a given url and returning an AudioSource to use with fromSource.

fromSource : Web.AudioSource -> Time.Posix -> Web.Audio

Create Audio from an given loaded source which will play at a given time

-- play a song at half speed and wait 2 seconds after the usual song start time before starting
Web.Audio.fromSource
    myCoolSong
    (Duration.addTo usualSongStartTime (Duration.seconds 2))
    |> Web.Audio.speedScaleBy (Web.Audio.Parameter.at 0.5)

Note that in some browsers audio will be muted until the user interacts with the webpage.

play : Web.Audio -> Web.Interface future_

An Interface for playing Audio created with Audio.fromSource.

To play multiple audios:

[ audio0, audio1, audio2 ]
    |> List.map Web.Audio.play
    |> Web.interfaceBatch

volumeScaleBy : Web.AudioParameterTimeline -> Web.Audio -> Web.Audio

Scale how loud it is. 1 preserves the current volume, 0.5 halves it, and 0 mutes it. If the the volume is less than 0, 0 will be used instead.

speedScaleBy : Web.AudioParameterTimeline -> Web.Audio -> Web.Audio

Scale the playback rate by a given factor. This will also affect pitch.

For example, Web.Audio.speedScaleBy 0.5 means playback will take twice as long and the pitch will be one octave lower, see AudioBufferSourceNode.playbackRate

In general, to pitch by semitones:

Web.Audio.speedScaleBy
    (Web.Audio.Parameter.at (2 ^ (semitones / 12)))

Note: It would be possible to modify the signal to compensate for the pitch change, see Audio time stretching and pitch scaling. Help appreciated!

stereoPan : Web.AudioParameterTimeline -> Web.Audio -> Web.Audio

Change the stereo panning with a given a signed percentage parameter.

Web.Audio.pan -0.9 for example means that the sound is almost fully balanced towards the left speaker

addLinearConvolutionWith : Web.AudioSource -> Web.Audio -> Web.Audio

Usually used to apply reverb and or echo. Given a loaded AudioSource containing the impulse response, it performs a Convolution with the Audio

If you need some nice impulse wavs to try it out, there's a few at dhiogoboza/audio-convolution. If you know more nice ones, don't hesitate to open an issue or a PR.

addHighpassFromFrequency : Web.AudioParameterTimeline -> Web.Audio -> Web.Audio

Frequencies below a given cutoff parameter are attenuated; frequencies above it pass through.

Has a 12dB/octave rolloff and no peak at the cutoff.