summaryrefslogtreecommitdiff
path: root/app/client/audio/wav2pix.js
blob: e561bae560f3f54add6083cc058db3a7f61d4a6d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import types from '../types'

import Tone from 'tone'
import JSZip from 'jszip'
import { sprintf } from 'sprintf-js'

import * as draw from './lib/draw'
import output from './lib/output'
import spectrum from './lib/spectrum'

import { requestAudioContext } from './lib'

export const FRAME_LENGTH = 126 * 255
export const FRAME_STEP = Math.round(FRAME_LENGTH / 4)

const _r = 8
const _i = 8

export { spectrum }
// requestAudioContext(() => {})

export const loadBuffer = file => {
  return new Promise((resolve, reject) => {
    const url = URL.createObjectURL(file)
    let buffer = new Tone.Buffer(
      url,
      loadBuffer,
      err => {
        console.error('err', err)
        reject(err)
      }
    )
    function loadBuffer() {
      URL.revokeObjectURL(url)
      resolve(buffer)
    }
  })
}

export const loadPCM = (file) => {
  return new Promise((resolve, reject) => {
    // if we've already fetched this file...
    if (file.pcm) {
      return resolve(file)
    }
    loadBuffer(file).then(buffer => {
      const pcm = buffer._buffer.getChannelData(0)
      const sr = buffer._buffer.sampleRate
      if (! pcm) return reject()
      console.log(pcm.length, sr)
      resolve({ file, buffer, pcm, sr })
    })
  })
}

export const renderFrames = (file, { frame_step=FRAME_STEP, frame_start=0, max=12 }) => dispatch => {
  return new Promise((resolve, reject) => {
    loadPCM(file).then((pcmProps) => {
      const { file, buffer, pcm, sr } = pcmProps
      dispatch({ type: types.wav2pix.load })
      let frames = []
      let count = 0
      let _len = pcm.length - FRAME_LENGTH
      let offset = Math.round(_len * frame_start)
      for (;
            offset < _len && count < max;
            offset += frame_step, count += 1
          ) {
        frames.push(render(pcm.slice(offset, offset+FRAME_LENGTH), sr, count))
      }
      dispatch({ type: types.wav2pix.finish, message: 'Rendered ' + count + ' images' })
      resolve({ pcm: pcmProps, frames })
    })
  })
}

export const buildZip = (name, file, { frame_step=FRAME_STEP, frame_start=0, max=10000 }) => dispatch => {
  return new Promise((resolve, reject) => {
    loadPCM(file).then(({ buffer, pcm, sr }) => {
      dispatch({ type: types.wav2pix.load })

      const zip = new JSZip()
      const zip_folder = zip.folder("wav2pix_" + name);

      let steps = (pcm.length - FRAME_LENGTH) / frame_step
      console.log(steps)

      let count = 0
      let _len = pcm.length - FRAME_LENGTH
      let offset = Math.round(_len * frame_start)
      for (;
            offset < _len && count < max;
            offset += frame_step, count += 1
          ) {
        if ((count % 10) === 0) {
          dispatch({ type: types.wav2pix.progress, progress: { i: count / max * 6, n: 6 } })
        }
        render(pcm.slice(offset, offset+FRAME_LENGTH), sr, count, zip_folder)
      }

      // dispatch event
      dispatch({ type: types.wav2pix.finish, message: 'Rendered ' + count + ' images' })
      zip.generateAsync({ type: "blob" }).then(content => {
        dispatch({ type: types.wav2pix.zip, size: content.size })
        // FileSaver.saveAs(content, "wav2pix_" + name + ".zip")
        resolve({
          zip: content,
          filename: "wav2pix_" + name + ".zip",
          count
        })
      })
    })
  })
}

function render(pcm, sr, count, zip){
  const fft = spectrum.toSpectrum(pcm, sr)
  // console.log('render', fft)
  // const pcm_rev = pcm.slice().reverse()
  // const spec_rev = spectrum.toSpectrum(pcm_rev, spec.sr)
  const { canvas, imageData } = draw.raw_spectrum(fft, 0, 256, 0, 256, _r, _i)
  if (zip) {
    const name = sprintf('frame_%05d.png', count)
    const dataURL = canvas.toDataURL("image/png")
    zip.file(name, dataURL.split(',')[1], {base64: true})
  }
  return { fft, canvas, imageData }
}