Granular Synthesis

by soulwire

HTML

<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>

Babel + JSX

const context = new AudioContext()

class Granulizer {
	speed = 1
  rate = 1.0
  jitter = 0
  detune = 0
  grainSize = 0.1
  constructor(context, buffer) {
  	this.currentTime = 0
	  this.update = this.update.bind(this)
    this.context = context
    this.buffer = buffer
    this.compressor = context.createDynamicsCompressor()
    this.compressor.connect(context.destination)
    this.convolver = context.createConvolver()
    this.convolver.connect(this.compressor)
    //this.convolver.buffer = buffer
    //this.convolver.buffer = this.createRandomBuffer(0.5)
    this.convolver.buffer = this.createPartialBuffer(buffer, 5)
    this.master = this.convolver
  }
  createPartialBuffer(source, duration) {
  	const buffer = context.createBuffer(2, duration * this.context.sampleRate, this.context.sampleRate)
    const inL = source.getChannelData(0)
    const inR = source.getChannelData(1)
    const outL = buffer.getChannelData(0)
    const outR = buffer.getChannelData(1)
    for (let i = 0; i < buffer.length; i++) {
      outL[i] = inL[i]
      outR[i] = inR[i]
    }
    return buffer
  }
  createRandomBuffer(duration) {
    const buffer = context.createBuffer(2, duration * this.context.sampleRate, this.context.sampleRate)
    const left = buffer.getChannelData(0)
    const right = buffer.getChannelData(1)
    for (let i = 0; i < buffer.length; i++) {
      left[i] = Math.random() * 2 - 1
      right[i] = Math.random() * 2 - 1
    }
    return buffer
  }
  start() {
    this.lastUpdateTime = this.context.currentTime
    this.update()
  }
  stop() {
  	cancelAnimationFrame(this.frameRequest)
  }
  update() {
	  const delta = this.context.currentTime - this.lastUpdateTime
    if (delta > 0) {
    	this.currentTime += delta * this.speed
      if (this.currentTime > this.buffer.duration) {
	      this.currentTime -= this.buffer.duration
      } else if (this.currentTime < 0) {
      	this.currentTime += this.buffer.duration 
      }
      const source =...