diff options
Diffstat (limited to 'app/client')
36 files changed, 692 insertions, 295 deletions
diff --git a/app/client/api/index.js b/app/client/api/index.js index c19b78d..7551fb2 100644 --- a/app/client/api/index.js +++ b/app/client/api/index.js @@ -1,5 +1,5 @@ import { crud_actions } from './crud.actions' -import * as util from '../util' +import util from '../util' import * as parser from './parser' /* diff --git a/app/client/audio/index.js b/app/client/audio/index.js deleted file mode 100644 index 8b3da74..0000000 --- a/app/client/audio/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import Tone from 'tone' -import StartAudioContext from './startAudioContext' diff --git a/app/client/audio/lib/_draw.js b/app/client/audio/lib/_draw.js new file mode 100644 index 0000000..974fa62 --- /dev/null +++ b/app/client/audio/lib/_draw.js @@ -0,0 +1,139 @@ +import { + browser, requestAudioContext, + randint, randrange, clamp, mod, +} from './lib/util' + +import './lib/vendor/hidpi-canvas' + +import mouse from './lib/mouse' +import color from './lib/color' + +let w, h +let rx, ry + +const pixels_per_second = 512 // 1024 + +const canvas = document.createElement('canvas') +// document.body.appendChild(canvas) +// document.body.addEventListener('resize', resize) +resize() +recenter() +requestAnimationFrame(animate) + +// must request context after resizing +const ctx = canvas.getContext('2d') + +const scratch = document.createElement('canvas') +const scratchCtx = scratch.getContext('2d-lodpi') + +function resize(ww, hh){ + w = canvas.width = ww || window.innerWidth + h = canvas.height = hh || window.innerHeight + canvas.style.width = w + 'px' + canvas.style.height = h + 'px' +} +function recenter(){ + rx = randint(w), ry = randint(h) +} +let frame = null +function onFrame(fn){ + frame = fn +} +function animate(t){ + requestAnimationFrame(animate) + if (frame) { + frame(t) + frame = null + } + // ctx.save() + // ctx.globalAlpha = 0.0001 + // ctx.translate(w/2, h/2) + // ctx.rotate(0.1) + // ctx.translate(-rx, -ry) + // ctx.drawImage(canvas, 0, 0) + // ctx.restore() +} +function clear(n, x, y, ww, hh){ + ctx.fillStyle = 'rgba(255,255,255,' + (n || 0.9) + ')' + ctx.fillRect(x || 0, y || 0, ww || w, hh || h) + recenter() +} +function triangle(px,py,r){ + setTimeout( () => tri(px,py,r), Math.random()*10) + // setTimeout( () => tri(px,py,r), Math.random()*200) + // setTimeout( () => tri(px,py,r), Math.random()*300) +} +function tri(px, py, r) { + ctx.save() + ctx.globalCompositeOperation = 'multiply' + ctx.fillStyle = color.color((px+py)/(w+h), 0, 1, 0.2) + function p(){ + let theta = randrange(0, Math.PI*2) + let x = px + Math.cos(theta) * r + let y = py + Math.sin(theta) * r + return { x, y } + } + ctx.beginPath() + const p0 = p(), p1 = p(), p2 = p() + ctx.moveTo(p0.x, p0.y) + ctx.lineTo(p1.x, p1.y) + ctx.lineTo(p2.x, p2.y) + ctx.lineTo(p0.x, p0.y) + ctx.fill() + ctx.restore() +} +function line(y){ + ctx.beginPath() + ctx.moveTo(0, y) + ctx.lineTo(w, y) + ctx.strokeStyle = "#888" + ctx.strokeWidth = 1 + ctx.stroke() +} +function dot(x, y, r){ + ctx.fillStyle = "#f00" + ctx.beginPath() + ctx.moveTo(x, y) + ctx.arc(x, y, r, 0, 2*Math.PI) + ctx.fill() +} +function waveform(pcm, sr, pos, zoom){ + sr = sr || 44100 + pos = pos || 0 + + var width = w + var height = Math.floor(h/4) + var half_height = Math.floor(height/2) + var x0 = 0 + var y0 = 20 + var ymid = y0 + half_height + var max_width_in_seconds = width / pixels_per_second + var max_width_in_samples = max_width_in_seconds * sr + var pcm_length = pcm.length + var len = Math.min(pcm_length, max_width_in_samples) + var pcm_step = sr / pixels_per_second + var i + ctx.save() + + clear(1, x0, y0, width, height) + + line(ymid) + ctx.beginPath() + for (i = 0; i < width; i += 0.5) { + var si = Math.floor(pcm_step * i + pos) + if (si > pcm_length) break + var val = pcm[si] // -1, 1 + // ctx.moveTo(x0 + i, ymid) + ctx.lineTo(x0 + i, ymid + val * half_height) + } + ctx.strokeStyle = "rgba(250,20,0,0.9)" + ctx.strokeWidth = 1 + ctx.stroke() + ctx.restore() +} + +export default { + canvas, ctx, onFrame, resize, + triangle, clear, line, dot, + waveform, spectrum, raw_spectrum, +}
\ No newline at end of file diff --git a/app/client/audio/draw.js b/app/client/audio/lib/draw.js index 8caf8d8..f5ba3ac 100644 --- a/app/client/audio/draw.js +++ b/app/client/audio/lib/draw.js @@ -1,137 +1,6 @@ -import { - browser, requestAudioContext, - randint, randrange, clamp, mod, -} from './lib/util' - -import './lib/vendor/hidpi-canvas' - -import mouse from './lib/mouse' -import color from './lib/color' - -let w, h -let rx, ry - -const pixels_per_second = 512 // 1024 - -const canvas = document.createElement('canvas') -// document.body.appendChild(canvas) -// document.body.addEventListener('resize', resize) -resize() -recenter() -requestAnimationFrame(animate) - -// must request context after resizing -const ctx = canvas.getContext('2d') - const scratch = document.createElement('canvas') const scratchCtx = scratch.getContext('2d-lodpi') -function resize(ww, hh){ - w = canvas.width = ww || window.innerWidth - h = canvas.height = hh || window.innerHeight - canvas.style.width = w + 'px' - canvas.style.height = h + 'px' -} -function recenter(){ - rx = randint(w), ry = randint(h) -} -let frame = null -function onFrame(fn){ - frame = fn -} -function animate(t){ - requestAnimationFrame(animate) - if (frame) { - frame(t) - frame = null - } - // ctx.save() - // ctx.globalAlpha = 0.0001 - // ctx.translate(w/2, h/2) - // ctx.rotate(0.1) - // ctx.translate(-rx, -ry) - // ctx.drawImage(canvas, 0, 0) - // ctx.restore() -} -function clear(n, x, y, ww, hh){ - ctx.fillStyle = 'rgba(255,255,255,' + (n || 0.9) + ')' - ctx.fillRect(x || 0, y || 0, ww || w, hh || h) - recenter() -} -function triangle(px,py,r){ - setTimeout( () => tri(px,py,r), Math.random()*10) - // setTimeout( () => tri(px,py,r), Math.random()*200) - // setTimeout( () => tri(px,py,r), Math.random()*300) -} -function tri(px, py, r) { - ctx.save() - ctx.globalCompositeOperation = 'multiply' - ctx.fillStyle = color.color((px+py)/(w+h), 0, 1, 0.2) - function p(){ - let theta = randrange(0, Math.PI*2) - let x = px + Math.cos(theta) * r - let y = py + Math.sin(theta) * r - return { x, y } - } - ctx.beginPath() - const p0 = p(), p1 = p(), p2 = p() - ctx.moveTo(p0.x, p0.y) - ctx.lineTo(p1.x, p1.y) - ctx.lineTo(p2.x, p2.y) - ctx.lineTo(p0.x, p0.y) - ctx.fill() - ctx.restore() -} -function line(y){ - ctx.beginPath() - ctx.moveTo(0, y) - ctx.lineTo(w, y) - ctx.strokeStyle = "#888" - ctx.strokeWidth = 1 - ctx.stroke() -} -function dot(x, y, r){ - ctx.fillStyle = "#f00" - ctx.beginPath() - ctx.moveTo(x, y) - ctx.arc(x, y, r, 0, 2*Math.PI) - ctx.fill() -} -function waveform(pcm, sr, pos, zoom){ - sr = sr || 44100 - pos = pos || 0 - - var width = w - var height = Math.floor(h/4) - var half_height = Math.floor(height/2) - var x0 = 0 - var y0 = 20 - var ymid = y0 + half_height - var max_width_in_seconds = width / pixels_per_second - var max_width_in_samples = max_width_in_seconds * sr - var pcm_length = pcm.length - var len = Math.min(pcm_length, max_width_in_samples) - var pcm_step = sr / pixels_per_second - var i - ctx.save() - - clear(1, x0, y0, width, height) - - line(ymid) - ctx.beginPath() - for (i = 0; i < width; i += 0.5) { - var si = Math.floor(pcm_step * i + pos) - if (si > pcm_length) break - var val = pcm[si] // -1, 1 - // ctx.moveTo(x0 + i, ymid) - ctx.lineTo(x0 + i, ymid + val * half_height) - } - ctx.strokeStyle = "rgba(250,20,0,0.9)" - ctx.strokeWidth = 1 - ctx.stroke() - ctx.restore() -} - function spectrum(spec, x0, y0, ww, hh){ const data = spec.data const fft_size = spec.fft_size @@ -186,6 +55,7 @@ function spectrum(spec, x0, y0, ww, hh){ ctx.drawImage(scratch, x0, y0, width, height) ctx.restore() } + function raw_spectrum(spec, x0, y0, ww, hh, def_min_r, def_min_i){ const data = spec.data const fft_size = spec.fft_size @@ -262,9 +132,3 @@ function raw_spectrum(spec, x0, y0, ww, hh, def_min_r, def_min_i){ return { canvas: _scratch, imageData } } - -export default { - canvas, ctx, onFrame, resize, - triangle, clear, line, dot, - waveform, spectrum, raw_spectrum, -}
\ No newline at end of file diff --git a/app/client/audio/lib/index.js b/app/client/audio/lib/index.js new file mode 100644 index 0000000..ba96112 --- /dev/null +++ b/app/client/audio/lib/index.js @@ -0,0 +1,47 @@ +import Tone from 'tone' +import StartAudioContext from './startAudioContext' + +import { is_mobile } from '../util' + +export function requestAudioContext (fn) { + if (is_mobile) { + const container = document.createElement('div') + const button = document.createElement('div') + button.innerHTML = 'Tap to start - please unmute your phone' + Object.assign(container.style, { + display: 'block', + position: 'absolute', + width: '100%', + height: '100%', + zIndex: '10000', + top: '0px', + left: '0px', + backgroundColor: 'rgba(0, 0, 0, 0.8)', + }) + Object.assign(button.style, { + display: 'block', + position: 'absolute', + left: '50%', + top: '50%', + padding: '20px', + backgroundColor: '#7F33ED', + color: 'white', + fontFamily: 'monospace', + borderRadius: '3px', + transform: 'translate3D(-50%,-50%,0)', + textAlign: 'center', + lineHeight: '1.5', + width: '150px', + }) + container.appendChild(button) + document.body.appendChild(container) + StartAudioContext.setContext(Tone.context) + StartAudioContext.on(button) + StartAudioContext.onStarted(_ => { + container.remove() + fn() + }) + } else { + fn() + } +}
\ No newline at end of file diff --git a/app/client/audio/output.js b/app/client/audio/lib/output.js index 53901b3..53901b3 100644 --- a/app/client/audio/output.js +++ b/app/client/audio/lib/output.js diff --git a/app/client/audio/spectrum.js b/app/client/audio/lib/spectrum.js index f4a5444..f4a5444 100644 --- a/app/client/audio/spectrum.js +++ b/app/client/audio/lib/spectrum.js diff --git a/app/client/audio/startAudioContext.js b/app/client/audio/lib/startAudioContext.js index 0e257be..0e257be 100644 --- a/app/client/audio/startAudioContext.js +++ b/app/client/audio/lib/startAudioContext.js diff --git a/app/client/audio/pix2wav.js b/app/client/audio/pix2wav.js new file mode 100644 index 0000000..ccd36be --- /dev/null +++ b/app/client/audio/pix2wav.js @@ -0,0 +1,35 @@ +function render(pcm, 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) + draw.clear() + const { canvas, imageData } = draw.raw_spectrum(fft, 0, 256, 0, 256, _r, _i) + const dataURL = canvas.toDataURL("image/png") + if (zip) { + const fn = sprintf('frame_%05d.png', count) + zip.file(fn, dataURL.split(',')[1], {base64: true}) + } + return { fft, canvas, imageData } +} +function play(i) { + // console.log('play', i) + last_i = i + let player = players[clamp(i, 0, players.length)] + // const { canvas, imageData } = draw.raw_spectrum(fft, 0, 256, 0, 256, 1, 1) + // console.log(_r, _i) + // const { canvas, imageData } = draw.raw_spectrum(player.fft, 0, 256, 0, 256, _r, _i) + const new_fft = spectrum.fromImageData(player.imageData, 44100, _r, _i) + // gallery.innerHTML = '' + + // console.log(player.fft.data, new_fft.data) + const buf = spectrum.fromSpectrum(new_fft) + const _p = new Tone.Player(buf) + _p.connect(output) + _p.start(Tone.now()) + redraw(new_fft) +} +function redraw(new_fft){ + const { canvas, imageData } = draw.raw_spectrum(new_fft, 0, 256, 0, 256, _r, _i) +} + diff --git a/app/client/audio/ui.js b/app/client/audio/ui.js new file mode 100644 index 0000000..76ffb09 --- /dev/null +++ b/app/client/audio/ui.js @@ -0,0 +1,12 @@ +/* + +mouse.register({ + move: (x, y) => { + } +}) +keys.listen((z) => { + // console.log(z) + play(mod(z, players.length)) +}) + +*/ diff --git a/app/client/audio/wav2pix.js b/app/client/audio/wav2pix.js index 3e86c40..089816d 100644 --- a/app/client/audio/wav2pix.js +++ b/app/client/audio/wav2pix.js @@ -1,153 +1,78 @@ import Tone from 'tone' import JSZip from 'jszip' -import { sprintf } from 'sprintf-js' import FileSaver from 'file-saver' -import draw from './draw' -import keys from './lib/keys' -import mouse from './lib/mouse' +import draw from './lib/draw' import output from './lib/output' import spectrum from './lib/spectrum' import { - requestAudioContext, lerp, clamp, mod, -} from './lib/util' +} from '../util' + +import { requestAudioContext } from './lib' -let selfDrag = false let buffer -let players = [] -let gallery let sr = 44100 let last_i = 0 let _r = 8, _i = 8 -function init(){ - requestAudioContext(ready) - document.body.addEventListener('dragover', dragover) - document.body.addEventListener('dragstart', dragstart) - document.body.addEventListener('drop', drop) - document.querySelector("#upload").addEventListener('change', handleFileSelect) - // draw.onFrame(() => {}) - draw.resize(256, 256) - gallery = document.querySelector('#gallery') - mouse.register({ - move: (x, y) => { - } - }) - keys.listen((z) => { - // console.log(z) - play(mod(z, players.length)) - }) -} -function ready(){ -} -function dragover (e) { - e.preventDefault() -} -function dragstart (e) { - selfDrag = true -} -function drop (e) { - e.stopPropagation() - e.preventDefault() +let files, file_index = 0; - if (e.dataTransfer && ! selfDrag) { - if (e.dataTransfer.files.length) { - handleFileSelect(e) - } - } - else { - handleFileSelect(e) - } - selfDrag = false +const FRAME_LENGTH = 126 * 255 +const FRAME_OFFSET = FRAME_LENGTH / 4 + +function init() { + requestAudioContext(ready) + draw.resize(256, 256) } -let files, file_index = 0; -function handleFileSelect(e){ +function handleFileSelect(e) { files = e.dataTransfer ? e.dataTransfer.files : e.target.files loadNext() } -function loadNext(){ +function loadNext() { var file = files[file_index++] if (! file) return load(file) } -function load(file){ - players = [] - buffer = new Tone.Buffer(URL.createObjectURL(file), loadBuffer, (err) => console.error('err', err)) +function load(file) { + buffer = new Tone.Buffer( + URL.createObjectURL(file), + loadBuffer, + (err) => console.error('err', err) + ) } -function loadBuffer(){ +function loadBuffer() { + // dispatch console.log('loaded buffer', buffer) const pcm = buffer._buffer.getChannelData(0) - sr = buffer._buffer.sampleRate + const sr = buffer._buffer.sampleRate if (! pcm) return - const FRAME_LENGTH = 126 * 255 - const FRAME_OFFSET = FRAME_LENGTH / 4 + const zip = new JSZip() + const zip_folder = zip.folder("wav2pix_" + name); - var zip = new JSZip() - - var zip_folder = zip.folder("images"); - - for (var offset = 0, count = 0, _len = pcm.length - FRAME_LENGTH; offset < _len; offset += FRAME_OFFSET, count += 1) { - if ((count % 100) === 0) console.log(count) - // console.log('generating', count, offset) - // let player = render(pcm.slice(offset, offset+FRAME_LENGTH), count, zip_folder) + const offset = 0 + for (offset = 0, count = 0, _len = pcm.length - FRAME_LENGTH; + offset < _len; + offset += FRAME_OFFSET, count += 1 + ) { + if ((count % 100) === 0) { + // dispatch event instead.. + console.log(count) + } render(pcm.slice(offset, offset+FRAME_LENGTH), count, zip_folder) - // register(player, count) - // if (count > 20) break } + // dispatch event console.log('done exporting') - zip.generateAsync({type:"blob"}).then(function(content) { + zip.generateAsync({ type: "blob" }).then(content => { + // dispatch console.log('saving zip') - FileSaver.saveAs(content, "img2pix.zip") + // FileSaver.saveAs(content, "wav2pix_" + name + ".zip") setTimeout(loadNext, 1000) }) // play(0) } -function render(pcm, 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) - draw.clear() - const { canvas, imageData } = draw.raw_spectrum(fft, 0, 256, 0, 256, _r, _i) - const dataURL = canvas.toDataURL("image/png") - if (zip) { - const fn = sprintf('frame_%05d.png', count) - zip.file(fn, dataURL.split(',')[1], {base64: true}) - } - return { fft, canvas, imageData } -} -function play(i) { - // console.log('play', i) - last_i = i - let player = players[clamp(i, 0, players.length)] - // const { canvas, imageData } = draw.raw_spectrum(fft, 0, 256, 0, 256, 1, 1) - // console.log(_r, _i) - // const { canvas, imageData } = draw.raw_spectrum(player.fft, 0, 256, 0, 256, _r, _i) - const new_fft = spectrum.fromImageData(player.imageData, 44100, _r, _i) - // gallery.innerHTML = '' - // console.log(player.fft.data, new_fft.data) - const buf = spectrum.fromSpectrum(new_fft) - const _p = new Tone.Player(buf) - _p.connect(output) - _p.start(Tone.now()) - redraw(new_fft) -} -function redraw(new_fft){ - const { canvas, imageData } = draw.raw_spectrum(new_fft, 0, 256, 0, 256, _r, _i) -} -function register(player, i){ - // console.log('register', player) - players.push(player) - player.canvas.addEventListener('click', () => { - play(i) - }) - if (i < 20) { - gallery.appendChild(player.canvas) - } -} init() diff --git a/app/client/common/fileList.component.js b/app/client/common/fileList.component.js index b70ce55..70ee5b6 100644 --- a/app/client/common/fileList.component.js +++ b/app/client/common/fileList.component.js @@ -3,7 +3,7 @@ import { bindActionCreators } from 'redux' import { connect } from 'react-redux' import { Link } from 'react-router-dom'; import moment from 'moment' -import * as util from '../util' +import util from '../util' const defaultFields = new Set(['name', 'date', 'size']) diff --git a/app/client/dashboard/dashboardHeader.component.js b/app/client/dashboard/dashboardHeader.component.js index 62586b8..d27a324 100644 --- a/app/client/dashboard/dashboardHeader.component.js +++ b/app/client/dashboard/dashboardHeader.component.js @@ -2,7 +2,7 @@ import { h, Component } from 'preact' import { connect } from 'react-redux' import { bindActionCreators } from 'redux' -import * as util from '../util' +import util from '../util' class DashboardHeader extends Component { constructor(props){ diff --git a/app/client/dashboard/tasklist.component.js b/app/client/dashboard/tasklist.component.js index b43481f..56bb50b 100644 --- a/app/client/dashboard/tasklist.component.js +++ b/app/client/dashboard/tasklist.component.js @@ -1,7 +1,7 @@ import { h, Component } from 'preact' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' -import * as util from '../util' +import util from '../util' import actions from '../actions' diff --git a/app/client/dataset/dataset.component.js b/app/client/dataset/dataset.component.js index 14ad852..af734ad 100644 --- a/app/client/dataset/dataset.component.js +++ b/app/client/dataset/dataset.component.js @@ -1,7 +1,7 @@ import { h, Component } from 'preact' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' -import * as util from '../util' +import util from '../util' import actions from '../actions' diff --git a/app/client/index.jsx b/app/client/index.jsx index 51e92df..8a13687 100644 --- a/app/client/index.jsx +++ b/app/client/index.jsx @@ -5,7 +5,7 @@ import { BrowserRouter, Route } from 'react-router-dom' import { store, history } from './store' import * as socket from './socket' -import * as util from './util' +import util from './util' import Header from './common/header.component' import AudioPlayer from './common/audioPlayer/audioPlayer.component' diff --git a/app/client/modules/pix2pix/index.js b/app/client/modules/pix2pix/index.js index ffe5f6b..9e3d466 100644 --- a/app/client/modules/pix2pix/index.js +++ b/app/client/modules/pix2pix/index.js @@ -1,11 +1,14 @@ import { h, Component } from 'preact' import { Route, Link } from 'react-router-dom' +import util from '../../util' + import Pix2PixNew from './views/pix2pix.new' import Pix2PixShow from './views/pix2pix.show' import Pix2PixLive from './views/pix2pix.live' function router () { + document.body.style.backgroundImage = 'linear-gradient(' + (util.randint(40)+40) + 'deg, #fde, #ffe)' return ( <section> <Route exact path='/pix2pix/new/' component={Pix2PixNew} /> diff --git a/app/client/modules/pix2pix/pix2pix.actions.js b/app/client/modules/pix2pix/pix2pix.actions.js index 82311ad..8633c0a 100644 --- a/app/client/modules/pix2pix/pix2pix.actions.js +++ b/app/client/modules/pix2pix/pix2pix.actions.js @@ -7,13 +7,13 @@ import * as datasetLoader from '../../dataset/dataset.loader' import actions from '../../actions' -import { allProgress } from '../../util' +import util from '../../util' import pix2pixModule from './pix2pix.module' export const load_directories = (id) => (dispatch) => { const module = pix2pixModule.name - allProgress([ + util.allProgress([ datasetLoader.load(module), // actions.socket.list_directory({ module, dir: 'datasets' }), // actions.socket.list_directory({ module, dir: 'results' }), diff --git a/app/client/modules/pix2pix/views/pix2pix.new.js b/app/client/modules/pix2pix/views/pix2pix.new.js index 173777c..203a606 100644 --- a/app/client/modules/pix2pix/views/pix2pix.new.js +++ b/app/client/modules/pix2pix/views/pix2pix.new.js @@ -1,7 +1,4 @@ import { h, Component } from 'preact' -import { bindActionCreators } from 'redux' -import { connect } from 'react-redux' -import * as util from '../../../util' import NewDatasetForm from '../../../dataset/dataset.new' diff --git a/app/client/modules/pix2pix/views/pix2pix.show.js b/app/client/modules/pix2pix/views/pix2pix.show.js index ef4b906..2139c6c 100644 --- a/app/client/modules/pix2pix/views/pix2pix.show.js +++ b/app/client/modules/pix2pix/views/pix2pix.show.js @@ -1,7 +1,7 @@ import { h, Component } from 'preact' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' -import * as util from '../../../util' +import util from '../../../util' import * as pix2pixActions from '../pix2pix.actions' import * as pix2pixTasks from '../pix2pix.tasks' diff --git a/app/client/modules/pix2wav/index.js b/app/client/modules/pix2wav/index.js index 602d54e..9071d04 100644 --- a/app/client/modules/pix2wav/index.js +++ b/app/client/modules/pix2wav/index.js @@ -1,10 +1,18 @@ import { h, Component } from 'preact' import { Route, Link } from 'react-router-dom' +import util from '../../util' + +import Pix2WavNew from './views/pix2wav.new' +import Pix2WavShow from './views/pix2wav.show' +// import Pix2WavLive from './views/pix2wav.live' function router () { - // <Route exact path='/pix2pix/live/' component={Pix2PixLive} /> + document.body.style.backgroundImage = 'linear-gradient(' + (util.randint(40)+40) + 'deg, #fde, #ffe)' return ( <section> + <Route exact path='/pix2wav/new/' component={Pix2WavNew} /> + <Route exact path='/pix2wav/datasets/' component={Pix2WavShow} /> + <Route exact path='/pix2wav/datasets/:id/' component={Pix2WavShow} /> </section> ) } @@ -13,12 +21,11 @@ function links(){ return ( <span> <span>datasets</span> - <span><Link to="/pix2wav/live/">live</Link></span> </span> ) } export default { - name: 'pix2pix', + name: 'pix2wav', router, links, } diff --git a/app/client/modules/pix2wav/pix2wav.actions.js b/app/client/modules/pix2wav/pix2wav.actions.js new file mode 100644 index 0000000..08f1a97 --- /dev/null +++ b/app/client/modules/pix2wav/pix2wav.actions.js @@ -0,0 +1,57 @@ +import uuidv1 from 'uuid/v1' + +import socket from '../../socket' +import types from '../../types' + +import * as datasetLoader from '../../dataset/dataset.loader' + +import actions from '../../actions' + +import util from '../../util' + +import pix2wavModule from './pix2wav.module' + +export const load_directories = (id) => (dispatch) => { + const module = pix2wavModule.name + util.allProgress([ + datasetLoader.load(module), + // actions.socket.list_directory({ module, dir: 'datasets' }), + // actions.socket.list_directory({ module, dir: 'results' }), + // actions.socket.list_directory({ module, dir: 'output' }), + // actions.socket.disk_usage({ module, dir: 'datasets' }), + ], (percent, i, n) => { + dispatch({ type: types.app.load_progress, progress: { i, n }}) + }).then(res => { + const [datasetApiReport] = res //, datasets, results, output, datasetUsage, lossReport] = res + const { + folderLookup, + fileLookup, + datasetLookup, + folders, + files, + unsortedFolder, + } = datasetApiReport + dispatch({ + type: types.dataset.load, + data: { + module, + folderLookup, + fileLookup, + datasetLookup, + folders, files, + }, + }) + if (id) { + console.log('folder id', id) + dispatch({ + type: types.dataset.set_folder, + data: { + folder_id: id, + module + }, + }) + } + }).catch(e => { + console.error(e) + }) +} diff --git a/app/client/modules/pix2wav/pix2wav.tasks.js b/app/client/modules/pix2wav/pix2wav.tasks.js new file mode 100644 index 0000000..646e28c --- /dev/null +++ b/app/client/modules/pix2wav/pix2wav.tasks.js @@ -0,0 +1,7 @@ +import uuidv1 from 'uuid/v1' + +import socket from '../../socket' +import types from '../../types' + +import actions from '../../actions' + diff --git a/app/client/modules/pix2wav/views/pix2wav.new.js b/app/client/modules/pix2wav/views/pix2wav.new.js new file mode 100644 index 0000000..aff00aa --- /dev/null +++ b/app/client/modules/pix2wav/views/pix2wav.new.js @@ -0,0 +1,13 @@ +import { h, Component } from 'preact' + +import NewDatasetForm from '../../../dataset/dataset.new' + +import pix2wavModule from '../pix2wav.module' + +export default function Pix2WavNew ({ history }) { + return ( + <div class='app pix2wav'> + <NewDatasetForm module={pix2wavModule} history={history} /> + </div> + ) +} diff --git a/app/client/modules/pix2wav/views/pix2wav.show.js b/app/client/modules/pix2wav/views/pix2wav.show.js new file mode 100644 index 0000000..46a2436 --- /dev/null +++ b/app/client/modules/pix2wav/views/pix2wav.show.js @@ -0,0 +1,116 @@ +import { h, Component } from 'preact' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' +import util from '../../../util' + +import * as pix2wavActions from '../pix2wav.actions' +import * as pix2wavTasks from '../pix2wav.tasks' + +import Loading from '../../../common/loading.component' +import DatasetForm from '../../../dataset/dataset.form' +import NewDatasetForm from '../../../dataset/dataset.new' +import UploadStatus from '../../../dataset/upload.status' +import { FileList, FileRow } from '../../../common/fileList.component' + +import DatasetComponent from '../../../dataset/dataset.component' + +import pix2wavModule from '../pix2wav.module' + +class Pix2wavShow extends Component { + constructor(props){ + super(props) + this.datasetActions = this.datasetActions.bind(this) + } + componentWillMount(){ + const id = this.props.match.params.id || localStorage.getItem('pix2wav.last_id') + console.log('load dataset:', id) + const { match, pix2wav, actions } = this.props + if (id === 'new') return + if (id) { + if (parseInt(id)) localStorage.setItem('pix2wav.last_id', id) + if (! pix2wav.folder || pix2wav.folder.id !== id) { + actions.load_directories(id) + } + } + } + render(){ + const { pix2wav, match, history } = this.props + const { folderLookup } = (pix2wav.data || {}) + const folder = (folderLookup || {})[pix2wav.folder_id] || {} + + return ( + <div className='app pix2wav'> + <div class='heading'> + <div class='spaced'> + <h1>{folder ? folder.name : <Loading />}</h1> + <UploadStatus /> + </div> + </div> + {folder && folder.name && folder.name !== 'unsorted' && + <DatasetForm + title='Add Files' + module={pix2wavModule} + folder={folder} + canUpload canAddURL + /> + } + <DatasetComponent + loading={pix2wav.loading} + progress={pix2wav.progress} + id={pix2wav.folder_id} + module={pix2wavModule} + data={pix2wav.data} + folder={folder} + history={history} + onPickFile={(file, e) => { + e.preventDefault() + e.stopPropagation() + console.log('picked a file', file) + }} + datasetActions={this.datasetActions} + /> + </div> + ) + } + datasetActions(dataset, isFetching=false, isProcessing=false){ + const { pix2wav, remote } = this.props + const input = pix2wav.data.fileLookup[dataset.input[0]] + if (! input) return null + if (input.name && input.name.match(/(gif|jpe?g|png)$/i)) return null + return ( + <div> + <div class={'actions'}> + <span class='link' onClick={() => remote.train_task(dataset, pix2wav.folder_id, 1)}>train</span> + <span class='link' onClick={() => remote.train_task(dataset, pix2wav.folder_id, 2)}>2x</span> + <span class='link' onClick={() => remote.train_task(dataset, pix2wav.folder_id, 4)}>4x</span> + <span class='link' onClick={() => remote.train_task(dataset, pix2wav.folder_id, 6)}>6x</span> + <span class='link' onClick={() => remote.train_task(dataset, pix2wav.folder_id, 18)}>18x</span> + </div> + {dataset.isBuilt + ? <div class='subtext'> + {'fetched '} + <span class='link' onClick={() => remote.clear_cache_task(dataset)}>rm</span> + </div> + : isFetching + ? <div class='subtext'> + {'fetching'} + </div> + : <div class='subtext'> + <span class='link' onClick={() => remote.fetch_task(input.url, input.id, dataset.name)}>fetch</span> + </div> + } + </div> + ) + } +} + +const mapStateToProps = state => ({ + pix2wav: state.module.pix2wav, +}) + +const mapDispatchToProps = (dispatch, ownProps) => ({ + actions: bindActionCreators(pix2wavActions, dispatch), + remote: bindActionCreators(pix2wavTasks, dispatch), +}) + +export default connect(mapStateToProps, mapDispatchToProps)(Pix2wavShow) diff --git a/app/client/modules/samplernn/index.js b/app/client/modules/samplernn/index.js index 7d5e36e..485a9a4 100644 --- a/app/client/modules/samplernn/index.js +++ b/app/client/modules/samplernn/index.js @@ -1,5 +1,6 @@ import { h, Component } from 'preact' import { Route, Link } from 'react-router-dom' +import util from '../../util' import SampleRNNNew from './views/samplernn.new' import SampleRNNShow from './views/samplernn.show' @@ -8,6 +9,7 @@ import SampleRNNResults from './views/samplernn.results' import SampleRNNGraph from './views/samplernn.graph' function router () { + document.body.style.backgroundImage = 'linear-gradient(' + (util.randint(40)+40) + 'deg, #eef, #fef)' return ( <section> <Route exact path='/samplernn/new/' component={SampleRNNNew} /> diff --git a/app/client/modules/samplernn/samplernn.actions.js b/app/client/modules/samplernn/samplernn.actions.js index d0fda31..a957e25 100644 --- a/app/client/modules/samplernn/samplernn.actions.js +++ b/app/client/modules/samplernn/samplernn.actions.js @@ -7,13 +7,13 @@ import * as datasetLoader from '../../dataset/dataset.loader' import actions from '../../actions' -import { allProgress } from '../../util' +import util from '../../util' import samplernnModule from './samplernn.module' export const load_directories = (id) => (dispatch) => { const module = samplernnModule.name - allProgress([ + util.allProgress([ datasetLoader.load(module), actions.socket.list_directory({ module, dir: 'datasets' }), actions.socket.list_directory({ module, dir: 'results' }), diff --git a/app/client/modules/samplernn/views/samplernn.graph.js b/app/client/modules/samplernn/views/samplernn.graph.js index 821f1cb..9685802 100644 --- a/app/client/modules/samplernn/views/samplernn.graph.js +++ b/app/client/modules/samplernn/views/samplernn.graph.js @@ -2,7 +2,9 @@ import { h, Component } from 'preact' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' -import { lerp, norm, randint, randrange } from '../../../util' +import util from '../../../util' + +const { lerp, norm, randint, randrange } = util import * as samplernnActions from '../samplernn.actions' @@ -38,7 +40,7 @@ class SampleRNNGraph extends Component { canvas.style.width = canvas.width + 'px' canvas.style.height = canvas.height + 'px' - const ctx = canvas.getContext('2d') + const ctx = canvas.getContext('2d-lodpi') const w = canvas.width = canvas.width * devicePixelRatio const h = canvas.height = canvas.height * devicePixelRatio ctx.clearRect(0,0,w,h) diff --git a/app/client/modules/samplernn/views/samplernn.import.js b/app/client/modules/samplernn/views/samplernn.import.js index cce4aea..61df4da 100644 --- a/app/client/modules/samplernn/views/samplernn.import.js +++ b/app/client/modules/samplernn/views/samplernn.import.js @@ -1,7 +1,7 @@ import { h, Component } from 'preact' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' -import * as util from '../../../util' +import util from '../../../util' import * as samplernnActions from '../samplernn.actions' diff --git a/app/client/modules/samplernn/views/samplernn.new.js b/app/client/modules/samplernn/views/samplernn.new.js index 5f657c0..5640afc 100644 --- a/app/client/modules/samplernn/views/samplernn.new.js +++ b/app/client/modules/samplernn/views/samplernn.new.js @@ -1,7 +1,7 @@ import { h, Component } from 'preact' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' -import * as util from '../../../util' +import util from '../../../util' import NewDatasetForm from '../../../dataset/dataset.new' diff --git a/app/client/modules/samplernn/views/samplernn.results.js b/app/client/modules/samplernn/views/samplernn.results.js index 12367a3..3d448fc 100644 --- a/app/client/modules/samplernn/views/samplernn.results.js +++ b/app/client/modules/samplernn/views/samplernn.results.js @@ -2,8 +2,8 @@ import { h, Component } from 'preact' import { bindActionCreators } from 'redux' import { Link } from 'react-router-dom'; import { connect } from 'react-redux' +import util from '../../../util' -import * as util from '../../../util' import * as samplernnActions from '../samplernn.actions' import * as audioPlayerActions from '../../../common/audioPlayer/audioPlayer.actions' diff --git a/app/client/modules/samplernn/views/samplernn.show.js b/app/client/modules/samplernn/views/samplernn.show.js index f44deda..b7e0740 100644 --- a/app/client/modules/samplernn/views/samplernn.show.js +++ b/app/client/modules/samplernn/views/samplernn.show.js @@ -1,7 +1,7 @@ import { h, Component } from 'preact' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' -import * as util from '../../../util' +import util from '../../../util' import * as samplernnActions from '../samplernn.actions' import * as samplernnTasks from '../samplernn.tasks' diff --git a/app/client/queue/queue.reducer.js b/app/client/queue/queue.reducer.js index b9ed194..033acba 100644 --- a/app/client/queue/queue.reducer.js +++ b/app/client/queue/queue.reducer.js @@ -1,5 +1,5 @@ import types from '../types' -import * as util from '../util' +import util from '../util' import moment from 'moment' const queueInitialState = { diff --git a/app/client/util/hidpi-canvas.js b/app/client/util/hidpi-canvas.js new file mode 100644 index 0000000..f0a7a0d --- /dev/null +++ b/app/client/util/hidpi-canvas.js @@ -0,0 +1,170 @@ +/** + * HiDPI Canvas Polyfill (1.0.10) + * + * Author: Jonathan D. Johnson (http://jondavidjohn.com) + * Homepage: https://github.com/jondavidjohn/hidpi-canvas-polyfill + * Issue Tracker: https://github.com/jondavidjohn/hidpi-canvas-polyfill/issues + * License: Apache-2.0 +*/ +(function(prototype) { + + var pixelRatio = (function() { + var canvas = window.document.createElement('canvas'), + context = canvas.getContext('2d'), + backingStore = context.backingStorePixelRatio || + context.webkitBackingStorePixelRatio || + context.mozBackingStorePixelRatio || + context.msBackingStorePixelRatio || + context.oBackingStorePixelRatio || + context.backingStorePixelRatio || 1; + + return (window.devicePixelRatio || 1) / backingStore; + })(), + + forEach = function(obj, func) { + for (var p in obj) { + if (obj.hasOwnProperty(p)) { + func(obj[p], p); + } + } + }, + + ratioArgs = { + 'fillRect': 'all', + 'clearRect': 'all', + 'strokeRect': 'all', + 'moveTo': 'all', + 'lineTo': 'all', + 'arc': [0,1,2], + 'arcTo': 'all', + 'bezierCurveTo': 'all', + 'isPointinPath': 'all', + 'isPointinStroke': 'all', + 'quadraticCurveTo': 'all', + 'rect': 'all', + 'translate': 'all', + 'createRadialGradient': 'all', + 'createLinearGradient': 'all' + }; + + if (pixelRatio === 1) return; + + forEach(ratioArgs, function(value, key) { + prototype[key] = (function(_super) { + return function() { + var i, len, + args = Array.prototype.slice.call(arguments); + + if (value === 'all') { + args = args.map(function(a) { + return a * pixelRatio; + }); + } + else if (Array.isArray(value)) { + for (i = 0, len = value.length; i < len; i++) { + args[value[i]] *= pixelRatio; + } + } + + return _super.apply(this, args); + }; + })(prototype[key]); + }); + + // Stroke lineWidth adjustment + prototype.stroke = (function(_super) { + return function() { + this.lineWidth *= pixelRatio; + _super.apply(this, arguments); + this.lineWidth /= pixelRatio; + }; + })(prototype.stroke); + + // Text + // + prototype.fillText = (function(_super) { + return function() { + var args = Array.prototype.slice.call(arguments); + + args[1] *= pixelRatio; // x + args[2] *= pixelRatio; // y + + this.font = this.font.replace( + /(\d+)(px|em|rem|pt)/g, + function(w, m, u) { + return (m * pixelRatio) + u; + } + ); + + _super.apply(this, args); + + this.font = this.font.replace( + /(\d+)(px|em|rem|pt)/g, + function(w, m, u) { + return (m / pixelRatio) + u; + } + ); + }; + })(prototype.fillText); + + prototype.strokeText = (function(_super) { + return function() { + var args = Array.prototype.slice.call(arguments); + + args[1] *= pixelRatio; // x + args[2] *= pixelRatio; // y + + this.font = this.font.replace( + /(\d+)(px|em|rem|pt)/g, + function(w, m, u) { + return (m * pixelRatio) + u; + } + ); + + _super.apply(this, args); + + this.font = this.font.replace( + /(\d+)(px|em|rem|pt)/g, + function(w, m, u) { + return (m / pixelRatio) + u; + } + ); + }; + })(prototype.strokeText); +})(window.CanvasRenderingContext2D.prototype); +;(function(prototype) { + prototype.getContext = (function(_super) { + return function(type) { + var backingStore, ratio, context; + + + if (type == '2d-lodpi') { + context = _super.call(this, '2d'); + } + else if (type === '2d') { + context = _super.call(this, '2d'); + + backingStore = context.backingStorePixelRatio || + context.webkitBackingStorePixelRatio || + context.mozBackingStorePixelRatio || + context.msBackingStorePixelRatio || + context.oBackingStorePixelRatio || + context.backingStorePixelRatio || 1; + + ratio = (window.devicePixelRatio || 1) / backingStore; + + if (ratio > 1) { + this.style.height = this.height + 'px'; + this.style.width = this.width + 'px'; + this.width *= ratio; + this.height *= ratio; + } + } + else { + context = _super.call(this, type); + } + + return context; + }; + })(prototype.getContext); +})(window.HTMLCanvasElement.prototype); diff --git a/app/client/util/index.js b/app/client/util/index.js index a811dcf..4ce1245 100644 --- a/app/client/util/index.js +++ b/app/client/util/index.js @@ -2,17 +2,13 @@ import * as sort from './sort' import * as format from './format' import * as maths from './math' -export { - sort, - ...maths, - ...format, -} +import './hidpi-canvas' -export const is_iphone = !!((navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i))) -export const is_ipad = !!(navigator.userAgent.match(/iPad/i)) -export const is_android = !!(navigator.userAgent.match(/Android/i)) -export const is_mobile = is_iphone || is_ipad || is_android -export const is_desktop = ! is_mobile; +const is_iphone = !!((navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i))) +const is_ipad = !!(navigator.userAgent.match(/iPad/i)) +const is_android = !!(navigator.userAgent.match(/Android/i)) +const is_mobile = is_iphone || is_ipad || is_android +const is_desktop = ! is_mobile; const htmlClassList = document.body.parentNode.classList htmlClassList.add(is_desktop ? 'desktop' : 'mobile') @@ -20,9 +16,7 @@ htmlClassList.remove('loading') // window.debug = false -document.body.style.backgroundImage = 'linear-gradient(' + (randint(40)+40) + 'deg, #fde, #ffe)' - -export const allProgress = (promises, progress_cb) => { +const allProgress = (promises, progress_cb) => { let d = 0 progress_cb(0, 0, promises.length) promises.forEach((p) => { @@ -34,3 +28,13 @@ export const allProgress = (promises, progress_cb) => { }) return Promise.all(promises) } + +document.body.style.backgroundImage = 'linear-gradient(' + (maths.randint(40)+40) + 'deg, #fde, #ffe)' + +export default { + ...maths, + ...format, + sort, + allProgress, + is_iphone, is_ipad, is_android, is_mobile, is_desktop, +} diff --git a/app/client/util/math.js b/app/client/util/math.js index 253bacd..c301ffd 100644 --- a/app/client/util/math.js +++ b/app/client/util/math.js @@ -1,13 +1,12 @@ -export function mod(n,m){ return n-(m * Math.floor(n/m)) } -export function clamp(n,a,b) { return n<a?a:n<b?n:b } -export function norm(n,a,b) { return (n-a) / (b-a) } -export function lerp(n,a,b) { return (b-a)*n+a } -export function mix(n,a,b) { return a*(1-n)+b*n } -export function randint(n) { return Math.floor(Math.random()*n) } +export const mod = (n,m) => n-(m * Math.floor(n/m)) +export const clamp = (n,a,b) => n<a?a:n<b?n:b +export const norm = (n,a,b) => (n-a) / (b-a) +export const lerp = (n,a,b) => (b-a)*n+a +export const mix = (n,a,b) => a*(1-n)+b*n +export const randint = (n) => Math.floor(Math.random()*n) export function randrange(a,b){ return Math.random() * (b-a) + a } export function randsign(){ return Math.random() >= 0.5 ? -1 : 1 } export function choice (a){ return a[ Math.floor(Math.random() * a.length) ] } -export function lerp(n,a,b){ return (b-a)*n+a } export function angle(x0,y0,x1,y1){ return Math.atan2(y1-y0,x1-x0) } export function dist(x0,y0,x1,y1){ return Math.sqrt(Math.pow(x1-x0,2)+Math.pow(y1-y0,2)) } export function xor(a,b){ a=!!a; b=!!b; return (a||b) && !(a&&b) } |
