Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update for Purescript 0.12 #9

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,28 @@
"tests"
],
"dependencies": {
"purescript-arrays": "^4.2.0",
"purescript-foldable-traversable": "^3.6.0",
"purescript-lists": "^4.10.0",
"purescript-arrays": "^5.1.1",
"purescript-foldable-traversable": "^4.1.1",
"purescript-lists": "^5.3.0",
"purescript-math": "^2.1.0",
"purescript-maybe": "^3.0.0",
"purescript-tuples": "^4.1.0",
"purescript-strings": "^3.3.1",
"purescript-eff": "^3.1.0",
"purescript-aff": "^4.0.0",
"purescript-maybe": "^4.0.1",
"purescript-tuples": "^5.1.0",
"purescript-strings": "^4.0.1",
"purescript-effect": "^2.0.0",
"purescript-aff": "^5.0.2",
"purescript-arraybuffer-types": "^2.0.0",
"jacereda/purescript-arraybuffer": "^6.0.0"
"jacereda/purescript-arraybuffer": "^8.0.2"
},
"devDependencies": {
"purescript-console": "^3.0.0",
"purescript-psci-support": "^3.0.0",
"purescript-dom": "^4.16.0",
"purescript-js-timers": "^3.0.0",
"purescript-affjax": "^5.0.0",
"purescript-assert": "^3.0.0",
"purescript-refs": "^3.0.0"
},
"resolutions": {
"purescript-arraybuffer-types": "^2.0.0"
"purescript-console": "^4.2.0",
"purescript-psci-support": "^4.0.0",
"purescript-web-dom": "^1.0.0",
"purescript-web-events": "^1.0.1",
"purescript-web-html": "^1.2.0",
"purescript-js-timers": "^4.0.1",
"purescript-affjax": "^7.0.0",
"purescript-assert": "^4.0.0",
"purescript-exceptions": "^4.0.0",
"purescript-refs": "^4.1.0"
}
}
83 changes: 27 additions & 56 deletions examples/decodeAsync/Main.purs
Original file line number Diff line number Diff line change
Expand Up @@ -4,60 +4,43 @@ import Prelude

import Audio.WebAudio.AudioBufferSourceNode (setBuffer, startBufferSource)
import Audio.WebAudio.BaseAudioContext (createBufferSource, currentTime, decodeAudioDataAsync, destination, newAudioContext)
import Audio.WebAudio.Types (AudioContext, AudioBuffer, AUDIO, connect)
import Control.Monad.Aff (Aff, Fiber, launchAff)
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Class (liftEff)
import Audio.WebAudio.Types (AudioContext, AudioBuffer, connect)
import Effect.Aff (Aff, Fiber, launchAff)
import Effect (Effect)
import Effect.Class (liftEffect)
import Control.Parallel (parallel, sequential)
import Data.Either (Either(..))
import Data.HTTP.Method (Method(..))
import Data.Traversable (traverse)
import Data.Maybe (Maybe(..))
import Data.Array ((!!))
import Network.HTTP.Affjax (AJAX, affjax, defaultRequest)
import Affjax (get)
import Affjax.ResponseFormat (arrayBuffer, ResponseFormatError)

type ElapsedTime = Number

-- | load a single sound buffer resource and decode it
loadSoundBuffer :: ∀ eff.
AudioContext
-> String
-> Aff
( ajax :: AJAX
, audio :: AUDIO
| eff
)
AudioBuffer
loadSoundBuffer :: AudioContext
-> String
-> Aff (Either ResponseFormatError AudioBuffer)
loadSoundBuffer ctx fileName = do
res <- affjax $ defaultRequest { url = fileName, method = Left GET }
buffer <- decodeAudioDataAsync ctx res.response
pure buffer
res <- get arrayBuffer fileName
traverse (decodeAudioDataAsync ctx) res.body

-- | load and decode an array of audio buffers from a set of resources
loadSoundBuffers :: ∀ e.
AudioContext
-> (Array String)
-> Aff
( ajax :: AJAX
, audio :: AUDIO
| e
)
(Array AudioBuffer)
loadSoundBuffers :: AudioContext
-> Array String
-> Aff (Array (Either ResponseFormatError AudioBuffer))
loadSoundBuffers ctx fileNames =
sequential $ traverse (\name -> parallel (loadSoundBuffer ctx name)) fileNames

-- | Play a sound at a sepcified elapsed time
playSoundAt :: ∀ eff.
AudioContext
-> Maybe AudioBuffer
-> ElapsedTime
-> Eff
( audio :: AUDIO
| eff )
Unit
playSoundAt :: AudioContext
-> Maybe (Either ResponseFormatError AudioBuffer)
-> ElapsedTime
-> Effect Unit
playSoundAt ctx mbuffer elapsedTime =
case mbuffer of
Just buffer ->
Just (Right buffer) ->
do
startTime <- currentTime ctx
src <- createBufferSource ctx
Expand All @@ -69,26 +52,14 @@ playSoundAt ctx mbuffer elapsedTime =
_ ->
pure unit

main :: ∀ eff.
Eff
( ajax :: AJAX
, audio :: AUDIO
| eff
)
(Fiber
( ajax :: AJAX
, audio :: AUDIO
| eff
)
Unit
)
main :: Effect (Fiber Unit)
main = launchAff $ do
ctx <- liftEff newAudioContext
ctx <- liftEffect newAudioContext
buffers <- loadSoundBuffers ctx ["hihat.wav", "kick.wav", "snare.wav"]
_ <- liftEff $ playSoundAt ctx (buffers !! 0) 0.0
_ <- liftEff $ playSoundAt ctx (buffers !! 1) 0.5
_ <- liftEff $ playSoundAt ctx (buffers !! 2) 1.0
_ <- liftEff $ playSoundAt ctx (buffers !! 0) 1.5
_ <- liftEff $ playSoundAt ctx (buffers !! 1) 2.0
_ <- liftEff $ playSoundAt ctx (buffers !! 2) 2.5
_ <- liftEffect $ playSoundAt ctx (buffers !! 0) 0.0
_ <- liftEffect $ playSoundAt ctx (buffers !! 1) 0.5
_ <- liftEffect $ playSoundAt ctx (buffers !! 2) 1.0
_ <- liftEffect $ playSoundAt ctx (buffers !! 0) 1.5
_ <- liftEffect $ playSoundAt ctx (buffers !! 1) 2.0
_ <- liftEffect $ playSoundAt ctx (buffers !! 2) 2.5
pure unit
28 changes: 11 additions & 17 deletions examples/gain/Main.purs
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,23 @@ import Audio.WebAudio.BaseAudioContext (createGain, currentTime, destination, ne
import Audio.WebAudio.AudioContext (createMediaElementSource)
import Audio.WebAudio.AudioParam (setValueAtTime)
import Audio.WebAudio.GainNode (gain)
import Audio.WebAudio.Types (connect, AUDIO)
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Console (CONSOLE, logShow)
import Control.Monad.Eff.Exception (EXCEPTION, throw)
import DOM (DOM)
import DOM.HTML (window)
import DOM.HTML.Types (htmlDocumentToNonElementParentNode)
import DOM.HTML.Window (document)
import DOM.Node.NonElementParentNode (getElementById)
import Audio.WebAudio.Types (connect)
import Effect (Effect)
import Effect.Console (logShow)
import Effect.Exception (throw)
import Web.HTML (window)
import Web.HTML.HTMLDocument (toNonElementParentNode) as HTMLDocument
import Web.HTML.Window (document)
import Web.DOM.NonElementParentNode (getElementById)
import Data.Maybe (Maybe(..))
import Data.Newtype (wrap)

-- | 3 secs after the audio begins playing, set the value (i.e., volume)
-- | of the gain node to 0.3 (i.e., a 70% reduction)

main :: Eff ( dom :: DOM
, audio :: AUDIO
, console :: CONSOLE
, exception :: EXCEPTION
) Unit
main :: Effect Unit
main = do
doc <- map htmlDocumentToNonElementParentNode (window >>= document)
noise <- getElementById (wrap "noise") doc
doc <- map HTMLDocument.toNonElementParentNode (window >>= document)
noise <- getElementById "noise" doc
case noise of
Just el -> void do
cx <- newAudioContext
Expand Down
63 changes: 30 additions & 33 deletions examples/square-wave/Main.purs
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,30 @@ module SquareWave where

import Prelude

import Audio.WebAudio.Types (AUDIO, AudioContext, GainNode, OscillatorNode, AudioContextState(..), connect)
import Audio.WebAudio.Types (AudioContext, GainNode, OscillatorNode, AudioContextState(..), connect)
import Audio.WebAudio.BaseAudioContext (createGain, createOscillator, currentTime, destination, newAudioContext, resume, state, suspend)
import Audio.WebAudio.AudioParam (getValue, setValue, setValueAtTime)
import Audio.WebAudio.GainNode (gain)
import Audio.WebAudio.Oscillator (OscillatorType(..), frequency, setOscillatorType, startOscillator)
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Exception (EXCEPTION, throw)
import Control.Monad.Eff.Ref (REF, Ref, newRef, readRef, writeRef)
import Control.Monad.Eff.Timer (IntervalId, TIMER, clearInterval, setInterval)
import DOM (DOM)
import DOM.Event.EventTarget (addEventListener, eventListener)
import DOM.Event.Types (EventTarget)
import DOM.HTML (window)
import DOM.HTML.Types (htmlDocumentToParentNode)
import DOM.HTML.Window (document)
import DOM.Node.ParentNode (querySelector)
import Effect (Effect)
import Effect.Exception (throw)
import Effect.Ref (Ref)
import Effect.Ref (new, read, write) as Ref
import Effect.Timer (IntervalId, clearInterval, setInterval)
import Web.Event.EventTarget (EventTarget, addEventListener, eventListener)
--import Web.Event.Types (EventTarget)
import Web.HTML (window)
import Web.HTML.HTMLDocument (toParentNode) as HTMLDocument
import Web.HTML.Window (document)
import Web.DOM.ParentNode (querySelector)
import Data.Maybe (Maybe(..))
import Data.Newtype (wrap)
import Unsafe.Coerce (unsafeCoerce)

beep :: ∀ e. AudioContext
beep :: AudioContext
-> OscillatorNode
-> GainNode
-> Eff (audio :: AUDIO, timer :: TIMER | e) Unit
-> Effect Unit
beep ctx osc g = do
freqParam <- frequency osc
f <- getValue freqParam
Expand All @@ -38,31 +38,24 @@ beep ctx osc g = do
_ <- setValueAtTime 0.001 (t + 0.2) gainParam
pure unit

controls ::
∀ e. Ref IntervalId
-> AudioContext
-> OscillatorNode
-> GainNode
-> Eff (audio :: AUDIO, timer :: TIMER, ref :: REF | e) Unit
controls :: Ref IntervalId
-> AudioContext
-> OscillatorNode
-> GainNode
-> Effect Unit
controls ref ctx osc g = do
s <- state ctx
if (s == SUSPENDED)
then do
resume ctx
t <- setInterval 1000 $ beep ctx osc g
writeRef ref t
Ref.write t ref
else do
suspend ctx
val <- readRef ref
val <- Ref.read ref
clearInterval val

main ::
∀ e. Eff ( audio :: AUDIO
, dom :: DOM
, exception :: EXCEPTION
, timer :: TIMER
, ref :: REF | e
) Unit
main :: Effect Unit
main = do
ctx <- newAudioContext

Expand All @@ -78,15 +71,19 @@ main = do

suspend ctx

let id = unsafeCoerce (newRef 0) :: Ref IntervalId
let id = unsafeCoerce (Ref.new 0) :: Ref IntervalId

doc <- map htmlDocumentToParentNode (window >>= document)
doc <- map HTMLDocument.toParentNode (window >>= document)
play <- querySelector (wrap "#play") doc
case play of
Just e -> addEventListener (wrap "click") (eventListener \_ -> controls id ctx osc g) false (unsafeCoerce e :: EventTarget)
Just e -> do
listener <- eventListener \_ -> controls id ctx osc g
addEventListener (wrap "click") listener false (unsafeCoerce e :: EventTarget)
Nothing -> throw "No 'play' button"
stop <- querySelector (wrap "#stop") doc
case stop of
Just e -> addEventListener (wrap "click") (eventListener \_ -> controls id ctx osc g) false (unsafeCoerce e :: EventTarget)
Just e -> do
listener <- eventListener \_ -> controls id ctx osc g
addEventListener (wrap "click") listener false (unsafeCoerce e :: EventTarget)
Nothing -> throw "No 'stop' button"
pure unit
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@
],
"license": "MIT",
"devDependencies": {
"text-encoding": "^0.7.0"
}
}
32 changes: 16 additions & 16 deletions src/Audio/WebAudio/AnalyserNode.purs
Original file line number Diff line number Diff line change
Expand Up @@ -7,51 +7,51 @@ module Audio.WebAudio.AnalyserNode

import Prelude (Unit)
import Data.ArrayBuffer.Types (ByteLength, Uint8Array, Float32Array)
import Audio.WebAudio.Types (AnalyserNode, AUDIO)
import Control.Monad.Eff (Eff)
import Audio.WebAudio.Types (AnalyserNode)
import Effect (Effect)
import Audio.WebAudio.Utils (unsafeGetProp, unsafeSetProp)


-- | The fftSize property's value must be a non-zero power of 2 in a range
-- | from 32 to 32768; its default value is 2048.
-- | If its value is not a power of 2, or it is outside the specified range,
-- | the exception INDEX_SIZE_ERR is thrown.
fftSize :: ∀ eff. AnalyserNode -> (Eff (audio :: AUDIO | eff) ByteLength)
fftSize :: AnalyserNode -> Effect ByteLength
fftSize n = unsafeGetProp "fftSize" n

setFftSize :: ∀ eff. ByteLength -> AnalyserNode -> (Eff (audio :: AUDIO | eff) Unit)
setFftSize :: ByteLength -> AnalyserNode -> Effect Unit
setFftSize size n = unsafeSetProp "fftSize" n size

frequencyBinCount :: ∀ eff. AnalyserNode -> (Eff (audio :: AUDIO | eff) ByteLength)
frequencyBinCount :: AnalyserNode -> Effect ByteLength
frequencyBinCount n = unsafeGetProp "frequencyBinCount" n

setFrequencyBinCount :: ∀ eff. ByteLength -> AnalyserNode -> (Eff (audio :: AUDIO | eff) Unit)
setFrequencyBinCount :: ByteLength -> AnalyserNode -> Effect Unit
setFrequencyBinCount count n = unsafeSetProp "frequencyBinCount" n count

minDecibels :: ∀ eff. AnalyserNode -> (Eff (audio :: AUDIO | eff) Number)
minDecibels :: AnalyserNode -> Effect Number
minDecibels n = unsafeGetProp "minDecibels" n

setMinDecibels :: ∀ eff. Number -> AnalyserNode -> (Eff (audio :: AUDIO | eff) Unit)
setMinDecibels :: Number -> AnalyserNode -> Effect Unit
setMinDecibels db n = unsafeSetProp "minDecibels" n db

maxDecibels :: ∀ eff. AnalyserNode -> (Eff (audio :: AUDIO | eff) Number)
maxDecibels :: AnalyserNode -> Effect Number
maxDecibels n = unsafeGetProp "maxDecibels" n

setMaxDecibels :: ∀ eff. Number -> AnalyserNode -> (Eff (audio :: AUDIO | eff) Unit)
setMaxDecibels :: Number -> AnalyserNode -> Effect Unit
setMaxDecibels db n = unsafeSetProp "maxDecibels" n db

smoothingTimeConstant :: ∀ eff. AnalyserNode -> (Eff (audio :: AUDIO | eff) Number)
smoothingTimeConstant :: AnalyserNode -> Effect Number
smoothingTimeConstant n = unsafeGetProp "smoothingTimeConstant" n

setSmoothingTimeConstant :: ∀ eff. Number -> AnalyserNode -> (Eff (audio :: AUDIO | eff) Unit)
setSmoothingTimeConstant :: Number -> AnalyserNode -> Effect Unit
setSmoothingTimeConstant tc n = unsafeSetProp "smoothingTimeConstant" n tc



foreign import getFloatFrequencyData :: ∀ eff. AnalyserNode -> Float32Array -> (Eff (audio :: AUDIO | eff) Unit)
foreign import getFloatFrequencyData :: AnalyserNode -> Float32Array -> Effect Unit

foreign import getByteFrequencyData :: ∀ eff. AnalyserNode -> Uint8Array -> (Eff (audio :: AUDIO | eff) Unit)
foreign import getByteFrequencyData :: AnalyserNode -> Uint8Array -> Effect Unit

foreign import getFloatTimeDomainData :: ∀ eff. AnalyserNode -> Float32Array -> (Eff (audio :: AUDIO | eff) Unit)
foreign import getFloatTimeDomainData :: AnalyserNode -> Float32Array -> Effect Unit

foreign import getByteTimeDomainData :: ∀ eff. AnalyserNode -> Uint8Array -> (Eff (audio :: AUDIO | eff) Unit)
foreign import getByteTimeDomainData :: AnalyserNode -> Uint8Array -> Effect Unit
Loading