packages feed

musicw 0.3.2 → 0.3.5

raw patch · 5 files changed

+204/−6 lines, 5 files

Files

musicw.cabal view
@@ -1,5 +1,5 @@ name:                musicw-version:             0.3.2+version:             0.3.5 synopsis:            Sound synthesis library, to be used with GHCJS and Web Audio API description:         A library for sound synthesis, currently targeting GHCJS and the Web Audio API. Used in the Inner Ear and Estuary projects. homepage:            https://github.com/dktr0/musicw/blob/master/README.md
src/Sound/MusicW/AudioContext.hs view
@@ -45,10 +45,26 @@ foreign import javascript safe   "if (window.___ac == null) { \   \    window.___ac = new (window.AudioContext || window.webkitAudioContext)(\-  \      { latencyHint: \"playback\", sampleRate: 48000 } \+  \      { sampleRate: 48000 } \   \      );\   \} $r = window.___ac;"   getGlobalAudioContext :: IO AudioContext++foreign import javascript safe+  "if (window.___ac == null) { \+  \    window.___ac = new (window.AudioContext || window.webkitAudioContext)(\+  \      { latencyHint: \"playback\", sampleRate: 48000 } \+  \      );\+  \} $r = window.___ac;"+  getGlobalAudioContextPlayback :: IO AudioContext++foreign import javascript safe+  "if (window.___ac == null) { \+  \    window.___ac = new (window.AudioContext || window.webkitAudioContext)(\+  \      { latencyHint: \"interactive\", sampleRate: 48000 } \+  \      );\+  \} $r = window.___ac;"+  getGlobalAudioContextInteractive :: IO AudioContext  foreign import javascript unsafe   "$1.currentTime"
src/Sound/MusicW/Node.hs view
@@ -243,6 +243,14 @@   setNodeField node "isSink" True   setNodeField node "startable" False +createMicrophone :: AudioIO m => m Node+createMicrophone = do+  ctx <- audioContext+  node <- liftIO $ js_createMicrophone ctx+  setNodeField node "isSource" True+  setNodeField node "isSink" False+  setNodeField node "startable" False+ createMediaStreamDestination :: AudioIO m => m Node createMediaStreamDestination = do   ctx <- audioContext@@ -420,6 +428,14 @@ foreign import javascript unsafe   "$1.createScriptProcessor(void 0, $2, $3)"   js_createScriptProcessor :: AudioContext -> Int -> Int -> IO Node++foreign import javascript safe+  "$r = $1.createGain();\+  \navigator.mediaDevices.getUserMedia({ audio: true, video: false}).then(function(stream) {\+  \  var x = new MediaStreamAudioSourceNode($1,{mediaStream: stream});\+  \  x.connect($r);\+  \});"+  js_createMicrophone :: AudioContext -> IO Node  foreign import javascript unsafe   "$1.createMediaStreamDestination()"
src/Sound/MusicW/SynthDef.hs view
@@ -181,6 +181,9 @@ audioIn :: AudioIO m => SynthDef m NodeRef audioIn = addNodeBuilder (0,1) $ createGain 1.0 -- TODO: hard-coded single input channel will be problematic later +microphone :: AudioIO m => SynthDef m NodeRef+microphone = addNodeBuilder (0,1) createMicrophone + resink :: AudioIO m => NodeRef -> NodeRef -> SynthDef m NodeRef resink target input = connect input target >> return target 
src/Sound/MusicW/Worklets.hs view
@@ -53,6 +53,9 @@ safeDivideWorklet :: AudioIO m => NodeRef -> NodeRef -> SynthDef m NodeRef safeDivideWorklet in1 in2 = audioWorklet "safeDivide-processor" [in1,in2] +unsafeDivideWorklet :: AudioIO m => NodeRef -> NodeRef -> SynthDef m NodeRef+unsafeDivideWorklet in1 in2 = audioWorklet "unsafeDivide-processor" [in1,in2]+ powWorklet :: AudioIO m => NodeRef -> NodeRef -> SynthDef m NodeRef powWorklet in1 in2 = audioWorklet "pow-processor" [in1,in2] @@ -65,20 +68,52 @@ clipWorklet :: AudioIO m => NodeRef -> NodeRef -> NodeRef -> SynthDef m NodeRef clipWorklet lo hi input = audioWorklet "clip-processor" [lo,hi,input] +maxWorklet :: AudioIO m => NodeRef -> NodeRef -> SynthDef m NodeRef+maxWorklet in1 in2 = audioWorklet "max-processor" [in1,in2]++minWorklet :: AudioIO m => NodeRef -> NodeRef -> SynthDef m NodeRef+minWorklet in1 in2 = audioWorklet "min-processor" [in1,in2]++whiteNoiseWorklet :: AudioIO m => SynthDef m NodeRef+whiteNoiseWorklet = audioWorklet "white-noise-processor" []++sinToSqrWorklet :: AudioIO m => NodeRef -> SynthDef m NodeRef+sinToSqrWorklet x = audioWorklet "sin-to-sqr-processor" [x]++sinToTriWorklet :: AudioIO m => NodeRef -> SynthDef m NodeRef+sinToTriWorklet x = audioWorklet "sin-to-tri-processor" [x]+++-- | sinToSawWorklet is for producing an ideal (ie. not band-limited) sawtooth+-- wave (a phasor, in other words) from two phase-aligned sine waves. The first+-- sine wave argument should be at one quarter the desired frequency, and the second+-- sine wave argument should be at half the desired frequency.++sinToSawWorklet :: AudioIO m => NodeRef -> NodeRef -> SynthDef m NodeRef+sinToSawWorklet x y = audioWorklet "sin-to-saw-processor" [x,y]++-- | stepWorklet produces an output by selecting from a list of inputs on the basis+-- of another, "selector" input from from 0-1. The space of 0-1 is divided over however+-- many inputs are provided in the argument, and the output at any given sample only+-- comes from one of the inputs (there is no mixing or cross-fading between the inputs).++stepWorklet :: AudioIO m => [NodeRef] -> NodeRef -> SynthDef m NodeRef+stepWorklet xs y = audioWorklet "step-processor" (y:xs)+ audioWorklet :: AudioIO m => String -> [NodeRef] -> SynthDef m NodeRef audioWorklet workletName inputs = do   let iChnls = length inputs -- NOTE limiting assumption that each input NodeRef provides only one channel of input   let oChnls = 1 -- NOTE limiting assumption that each audio worklet provides only one channel of output   y <- addNodeBuilder (iChnls,oChnls) $ createAudioWorkletNode iChnls oChnls workletName-  zipWithM (\x n -> connect' x 0 y n) inputs [0..]+  zipWithM_ (\x n -> connect' x 0 y n) inputs [0..]   return y  createAudioWorkletNode :: AudioIO m => Int -> Int -> String -> m Node createAudioWorkletNode inChnls outChnls workletName = do   ctx <- audioContext   node <- liftIO $ js_createAudioWorkletNode ctx (toJSString workletName) inChnls outChnls-  setNodeField node "isSource" (outChnls > 0)-  setNodeField node "isSink" (inChnls > 0)+  _ <- setNodeField node "isSource" (outChnls > 0)+  _ <- setNodeField node "isSink" (inChnls > 0)   setNodeField node "startable" False  foreign import javascript safe@@ -319,6 +354,21 @@ \ }\ \ registerProcessor('safeDivide-processor',SafeDivideProcessor);\ \ \+\ class UnsafeDivideProcessor extends AudioWorkletProcessor {\+\  static get parameterDescriptors() { return []; }\+\  constructor() { super(); }\+\  process(inputs,outputs,parameters) {\+\    const input1 = inputs[0];\+\    const input2 = inputs[1];\+\    const output = outputs[0];\+\    for(let i = 0; i < input1[0].length; i++) {\+\      output[0][i] = input1[0][i] / input2[0][i];\+\    }\+\    return true;\+\  }\+\ }\+\ registerProcessor('unsafeDivide-processor',UnsafeDivideProcessor);\+\ \ \ class PowProcessor extends AudioWorkletProcessor {\ \  static get parameterDescriptors() { return []; }\ \  constructor() { super(); }\@@ -376,4 +426,117 @@ \    return true;\ \  }\ \ }\-\ registerProcessor('clip-processor',ClipProcessor);"+\ registerProcessor('clip-processor',ClipProcessor);\+\ \+\ class MaxProcessor extends AudioWorkletProcessor {\+\  static get parameterDescriptors() { return []; }\+\  constructor() { super(); }\+\  process(inputs,outputs,parameters) {\+\    const in1 = inputs[0];\+\    const in2 = inputs[1];\+\    const output = outputs[0];\+\    for(let i = 0; i < in1[0].length; i++) {\+\      output[0][i] = Math.max(in1[0][i],in2[0][i]);\+\    }\+\    return true;\+\  }\+\ }\+\ registerProcessor('max-processor',MaxProcessor);\+\ \+\ class MinProcessor extends AudioWorkletProcessor {\+\  static get parameterDescriptors() { return []; }\+\  constructor() { super(); }\+\  process(inputs,outputs,parameters) {\+\    const in1 = inputs[0];\+\    const in2 = inputs[1];\+\    const output = outputs[0];\+\    for(let i = 0; i < in1[0].length; i++) {\+\      output[0][i] = Math.min(in1[0][i],in2[0][i]);\+\    }\+\    return true;\+\  }\+\ }\+\ registerProcessor('min-processor',MinProcessor);\+\ \+\ class WhiteNoiseProcessor extends AudioWorkletProcessor {\+\ \+\  static get parameterDescriptors() { return []; }\+\  constructor() { super(); }\+\  process(inputs,outputs,parameters) {\+\    const output = outputs[0];\+\    for(let i = 0; i < output[0].length; i++) {\+\      output[0][i] = Math.random()*2-1;\+\    }\+\    return true;\+\  }\+\ }\+\ registerProcessor('white-noise-processor',WhiteNoiseProcessor);\+\ \+\ class SinToSqrProcessor extends AudioWorkletProcessor {\+\ \+\  static get parameterDescriptors() { return []; }\+\  constructor() { super(); }\+\  process(inputs,outputs,parameters) {\+\    const input = inputs[0];\+\    const output = outputs[0];\+\    for(let i = 0; i < output[0].length; i++) {\+\      output[0][i] = (input[0][i] >= 0) ? 1 : -1;\+\    }\+\    return true;\+\  }\+\ }\+\ registerProcessor('sin-to-sqr-processor',SinToSqrProcessor);\+\ \+\ class SinToTriProcessor extends AudioWorkletProcessor {\+\ \+\  static get parameterDescriptors() { return []; }\+\  constructor() { super(); this.MULT = 4/Math.PI; }\+\  process(inputs,outputs,parameters) {\+\    const input = inputs[0];\+\    const output = outputs[0];\+\    for(let i = 0; i < output[0].length; i++) {\+\      output[0][i] = Math.abs(Math.asin(input[0][i]))*this.MULT-1;\+\    }\+\    return true;\+\  }\+\ }\+\ registerProcessor('sin-to-tri-processor',SinToTriProcessor);\+\ \+\ class SinToSawProcessor extends AudioWorkletProcessor {\+\  static get parameterDescriptors() { return []; }\+\  constructor() { super(); this.MULT = 4/Math.PI; }\+\  process(inputs,outputs,parameters) {\+\    const input1 = inputs[0];\+\    const input2 = inputs[1];\+\    const output = outputs[0];\+\    var a;\+\    for(let i = 0; i < output[0].length; i++) {\+\      a = Math.abs(Math.asin(input1[0][i]))*this.MULT;\+\      output[0][i] = (input2[0][i] >= 0) ? (a-1) : (1-a);\+\    }\+\    return true;\+\  }\+\ }\+\ registerProcessor('sin-to-saw-processor',SinToSawProcessor);\+\ \+\ class StepProcessor extends AudioWorkletProcessor {\+\  static get parameterDescriptors() { return []; }\+\  constructor() { super(); }\+\  process(inputs,outputs,parameters) {\+\    const output = outputs[0];\+\    if(inputs.length < 2) { for(let i = 0; i < output[0].length; i++) output[0][i] = 0;}\+\    else if(inputs.length == 2) { for(let i = 0; i < output[0].length; i++) output[0][i] = inputs[1][i];}\+\    else {\+\      var a,n = inputs.length - 1;\+\      for(let i = 0; i < output[0].length; i++) {\+\        a = inputs[0][0][i] * 0.5 + 0.5;\+\        a = Math.floor ((a - Math.trunc(a)) * n);\+\        a = (a >= 0) ? a : 0;\+\        a = (a < n) ? a : (n-1);\+\        output[0][i] = inputs[1+a][0][i];\+\      }\+\    }\+\    return true;\+\  }\+\ }\+\ registerProcessor('step-processor',StepProcessor);"