summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authorJules Laplace <julescarbon@gmail.com>2018-03-08 02:54:23 +0100
committerJules Laplace <julescarbon@gmail.com>2018-03-08 02:54:23 +0100
commit25033d7d9d393e444069ed82cfa0c914f9770f36 (patch)
treef9daf6596ddb1cbb24ac19f58a1b35f79ce44981 /client
parent735b1f59762023fa652fb6fe36bf8312a350300c (diff)
build
Diffstat (limited to 'client')
-rw-r--r--client/draw.js112
-rw-r--r--client/index.js74
-rw-r--r--client/lib/spectrum.js89
3 files changed, 189 insertions, 86 deletions
diff --git a/client/draw.js b/client/draw.js
index 3dab322..bed5f80 100644
--- a/client/draw.js
+++ b/client/draw.js
@@ -1,7 +1,3 @@
-import Tone from 'tone'
-
-import output from './lib/output'
-
import {
browser, requestAudioContext,
randint, randrange, clamp, mod,
@@ -13,9 +9,14 @@ import color from './lib/color'
let w, h
let rx, ry
+const pixels_per_second = 1024
+
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
+const scratch = document.createElement('canvas')
+const scratchCtx = scratch.getContext('2d')
+
document.body.appendChild(canvas)
document.body.addEventListener('resize', resize)
resize()
@@ -94,7 +95,6 @@ function waveform(pcm, sr, pos, zoom){
var x0 = 0
var y0 = 20
var ymid = y0 + half_height
- var pixels_per_second = 1024
var max_width_in_seconds = width / pixels_per_second
var max_width_in_samples = max_width_in_seconds * sr
var pcm_length = pcm.length
@@ -120,69 +120,22 @@ function waveform(pcm, sr, pos, zoom){
ctx.restore()
}
-const signalWindows = require('signal-windows').windows
-const FFTJS = require('fft.js')
-const fft_size = 2048
-const fft_overlap = fft_size / 4
-const half_fft_size = fft_size / 2
-const fft = new FFTJS(fft_size)
+function spectrum(spec, x0, y0, ww, hh){
+ const data = spec.data
+ const fft_size = spec.fft_size
+ const half_fft_size = spec.fft_size / 2
+ const spec_len = data.length
-function toSpectrum(pcm){
- const ham = signalWindows.construct('ham', fft_size)
- const pcm_in = new Array(fft_size)
- const pcm_length = pcm.length
- const pcm_q_length = Math.ceil(pcm_length / fft_size) * fft_size
- let i, j, fft_out, spec = [];
- for (i = 0; i < pcm_q_length; i += fft_overlap) {
- for (j = 0; j < fft_size; j++) {
- pcm_in[j] = pcm[i+j] * ham[j] || 0
- }
- fft_out = fft.createComplexArray()
- fft.realTransform(fft_out, pcm_in)
- fft.completeSpectrum(fft_out)
- spec.push(fft_out)
- }
- return spec
-}
-function fromSpectrum(spec, sr){
- const spec_len = spec.length
- const ham = signalWindows.construct('ham', fft_size)
- const out = fft.createComplexArray()
- const pcm_length = fft_overlap * spec_len
- const audioBuffer = Tone.context.createBuffer(1, pcm_length, sr)
- const pcm = audioBuffer.getChannelData(0);
- let i, j, u, v, _r, _i, col
- for (i = 0; i < spec_len; i++) {
- col = spec[i]
- fft.inverseTransform(out, col)
- u = i * (fft_overlap)
- for (j = fft_size * 1/4; j < fft_size * 3/4; j++) {
- pcm[u+j] = out[j*2] / ham[j] || 0
- }
- }
- const player = new Tone.Player(audioBuffer)
- player.connect(output)
- player.start(Tone.now() + pcm_length / sr)
- // console.log(Tone.now() + pcm_length / sr)
- return audioBuffer
-}
-function spectrum(pcm, sr){
- sr = sr || 44100
- const spec = toSpectrum(pcm)
-
- ctx.save()
-
- const scratch = document.createElement('canvas')
- scratch.width = spec.length
+ scratch.width = data.length
scratch.height = half_fft_size
- const scratchCtx = scratch.getContext('2d')
var imageData = ctx.createImageData(scratch.width, scratch.height)
- var data = imageData.data
+ var pixels = imageData.data
+
+ let i, j, u, v, _r, _i, col, hsl
- let i, j, u, v, _r, _i, col, hsl, spec_len = spec.length
for (i = 0; i < spec_len; i++) {
- col = spec[i]
+ col = data[i]
for (j = 0; j < half_fft_size; j++) {
u = ((half_fft_size - j) * spec_len + i) * 4
@@ -191,36 +144,35 @@ function spectrum(pcm, sr){
_i = mod(col[v+1], Math.PI*2) / (Math.PI*2)
hsl = color.hsl2rgb((_i + 1) / 2, 1.0, 1 - Math.abs(_r / 10))
// red - real part
- // data[u] = _r * 127 + 127
+ // pixels[u] = _r * 127 + 127
// // green - imag part
- // data[u+1] = _i * 127 + 127
+ // pixels[u+1] = _i * 127 + 127
// // blue - magnitude
- // data[u+2] = Math.sqrt(Math.pow(_r, 2) + Math.pow(_i, 2)) * 128 + 127
- // data[u+3] = 255
- data[u] = hsl[0]
- data[u+1] = hsl[1]
- data[u+2] = hsl[2]
- data[u+3] = 255
+ // pixels[u+2] = Math.sqrt(Math.pow(_r, 2) + Math.pow(_i, 2)) * 128 + 127
+ // pixels[u+3] = 255
+ pixels[u] = hsl[0]
+ pixels[u+1] = hsl[1]
+ pixels[u+2] = hsl[2]
+ pixels[u+3] = 255
}
}
scratchCtx.putImageData(imageData, 0, 0)
- var pcm_length = pcm.length
- var pixels_per_second = 1024
+ var pcm_length = spec.fft_overlap * spec_len
+
+ x0 = x0 || 0
+ y0 = y0 || Math.floor(h/4)
+ ww = ww || window.innerWidth
+ hh = hh || h/4
- const width = Math.round(pcm_length / sr * pixels_per_second) // ok not really this
- const height = Math.floor(h*2/3)
+ const width = Math.round(pcm_length / spec.sr * pixels_per_second)
+ const height = Math.floor(hh)
- const x0 = 0
- const y0 = Math.floor(h/4) + 20
+ ctx.save()
clear(1, x0, y0, w, height)
ctx.drawImage(scratch, x0, y0, width, height)
-
ctx.restore()
-
- const new_pcm = fromSpectrum(spec, sr)
- console.log(new_pcm)
}
export default {
diff --git a/client/index.js b/client/index.js
index 7a01b55..2b09f5f 100644
--- a/client/index.js
+++ b/client/index.js
@@ -7,6 +7,7 @@ import keys from './lib/keys'
import color from './lib/color'
import mouse from './lib/mouse'
import output from './lib/output'
+import spectrum from './lib/spectrum'
import { Hall } from './lib/hall'
@@ -34,9 +35,11 @@ let samplers = {}
let sampler
requestAudioContext( () => {
- samplers.smash = new Sampler('samples/smash/g{}.mp3', 12)
+ // samplers.smash = new Sampler('samples/smash/g{}.mp3', 12)
+ samplers.earth = new Sampler('samples/earth/earth{}.wav', 20)
// samplers.glass = new Sampler('samples/glass/0{}Particle.mp3', 20)
// samplers.kalimba = new Sampler('samples/kalimba/380731__cabled-mess__sansula-08-c-raw.wav', 10)
+ sampler = samplers.earth
samplers.choice = (m,n) => {
const r = Math.random()
if (r < m) return samplers.smash
@@ -45,7 +48,7 @@ requestAudioContext( () => {
}
Tone.Buffer.on('load', function(){
console.log('all buffers are loaded.')
- redraw()
+ // redraw()
})
})
@@ -59,19 +62,78 @@ function redraw(){
draw.clear()
}
+function manipulate(spec){
+ const data = spec.data
+ const sr = spec.sr
+ const fft_size = spec.fft_size
+ const fft_overlap = spec.fft_overlap
+ const spec_len = data.length
+
+ let i, j, u, v, _r, _i
+
+ let aa = []
+ for (i = 0; i < fft_size; i++) {
+ aa[i] = i
+ }
+ shuffle(aa)
+
+ let new_data = [], new_col, col
+ let bands = 2 << 4
+ let band, band_index
+ let band_size = Math.floor(fft_size / bands)
+ for (i = 0; i < spec_len; i++) {
+ col = data[i]
+ new_col = new_data[i] = data[i].concat()
+ data[i][2] = 0
+ for (j = 0; j < fft_size; j++) {
+ band = Math.floor(j / band_size) * band_size
+ band_index = j % band_size
+
+ new_col[j] = col[ band + (band_size - band_index) ]
+
+ // spectrum inversion
+ // new_col[j] = data[i][ fft_size - j - 1]
+
+ // erase mirrored half of fft
+ new_col[j + fft_size] = 0
+ }
+ new_col[2] = 0
+ }
+
+ spec.data = new_data //.reverse()
+ // col = data[i]
+ // for (j = 0; j < fft_size; j++) {
+ // _r = j*2
+ // _i = j*2+1
+ // col[_r] = col[_r] / 2
+ // col[_i] = col[_i]
+ // }
+ // }
+}
+
keys.listen(index => {
// trigger(Math.random(), ((index+7) % SPEAKER_COUNT) / SPEAKER_COUNT, 0, samplers.smash)
- const sample = samplers.smash.play(100, Tone.now(), output)
- console.log(Tone.now())
+ const sample = sampler.play(100, Tone.now(), output)
const buf = sample._buffer.get()
if (! buf) return
const pcm = buf.getChannelData(0)
const sr = buf.sampleRate
const duration = buf.duration
- console.log(duration.toFixed(2) + " s.")
+ const spec = spectrum.toSpectrum(pcm, sr)
+
draw.clear()
draw.waveform(pcm)
- draw.spectrum(pcm)
+ draw.spectrum(spec, 0, window.innerHeight/4 + 20)
+
+ manipulate(spec)
+
+ const audioBuffer = spectrum.fromSpectrum(spec)
+ const player = new Tone.Player(audioBuffer)
+ player.connect(output)
+ player.start(Tone.now() + pcm.length / sr)
+
+ // const new_spec = spectrum.toSpectrum(audioBuffer.getChannelData(0), sr)
+ draw.spectrum(spec, 0, window.innerHeight * 1/2 + 40)
})
mouse.register({
diff --git a/client/lib/spectrum.js b/client/lib/spectrum.js
new file mode 100644
index 0000000..2b30792
--- /dev/null
+++ b/client/lib/spectrum.js
@@ -0,0 +1,89 @@
+import Tone from 'tone'
+
+import output from './output'
+
+const signalWindows = require('signal-windows').windows
+const FFTJS = require('fft.js')
+
+const fft_size = 2 << 10
+const fft_overlap = fft_size / 4
+const half_fft_size = fft_size / 2
+
+const fft = new FFTJS(fft_size)
+
+function toSpectrum(pcm, sr){
+ sr = sr || 44100
+ const ham = signalWindows.construct('ham', fft_size)
+ const pcm_in = new Array(fft_size)
+ const pcm_length = pcm.length
+ const pcm_q_length = Math.ceil(pcm_length / fft_size) * fft_size
+ let i, j, fft_out, data = [];
+ for (i = -fft_size; i < pcm_q_length; i += fft_overlap) {
+ for (j = 0; j < fft_size; j++) {
+ pcm_in[j] = pcm[i+j] * ham[j] || 0
+ }
+ fft_out = fft.createComplexArray()
+ fft.realTransform(fft_out, pcm_in)
+ fft.completeSpectrum(fft_out)
+ data.push(fft_out)
+ }
+ return {
+ data,
+ sr,
+ fft_size,
+ fft_overlap,
+ }
+}
+
+function fromSpectrum(spec){
+ const data = spec.data
+ const sr = spec.sr
+ const fft_size = spec.fft_size
+ const fft_overlap = spec.fft_overlap
+ const spec_len = data.length
+
+ const ham = signalWindows.construct('ham', fft_size)
+ const out = fft.createComplexArray()
+ const pcm_length = fft_overlap * spec_len
+
+ const audioBuffer = Tone.context.createBuffer(1, pcm_length, sr)
+ const pcm = audioBuffer.getChannelData(0);
+
+ let i, j, u, v, _r, _i, col
+
+ for (i = 0; i < spec_len; i++) {
+ col = data[i]
+ fft.inverseTransform(out, col)
+ u = i * (fft_overlap)
+ // for (j = fft_size * 1/4; j < fft_size * 3/4; j++) {
+ // pcm[u+j] = out[j*2] / ham[j] || 0
+ // }
+ for (j = 0; j < fft_size; j++) {
+ pcm[u+j] += out[j*2] * ham[j] || 0
+ }
+ }
+
+ fadeInOut(pcm, fft_size)
+
+ return audioBuffer
+}
+
+function fadeInOut(pcm, fade_size){
+ const pcm_length = pcm.length
+ let fade = 0, i
+ for (i = 0; i < fade_size; i++) {
+ fade = i / (fade_size)
+ fade *= fade
+ pcm[i] *= fade
+ pcm[pcm_length - i] *= fade
+ }
+}
+function fadeOut(pcm){
+
+}
+
+export default {
+ toSpectrum,
+ fromSpectrum
+}
+