diff options
| author | Jules Laplace <julescarbon@gmail.com> | 2018-06-06 03:38:41 +0200 |
|---|---|---|
| committer | Jules Laplace <julescarbon@gmail.com> | 2018-06-06 03:38:41 +0200 |
| commit | 24a47dfa9d25c943bf1b51a1daf87140f76b3fbb (patch) | |
| tree | 38fe4ad6816e0958d5083fe16120a047c6ee94d3 /app/client | |
| parent | 2538fbd5471a61d51742281df0e019a2dd4ea24e (diff) | |
displaying these gray ass thumbnails
Diffstat (limited to 'app/client')
| -rw-r--r-- | app/client/api/crud.types.js | 8 | ||||
| -rw-r--r-- | app/client/audio/lib/draw.js | 9 | ||||
| -rw-r--r-- | app/client/audio/lib/index.js | 2 | ||||
| -rw-r--r-- | app/client/audio/lib/spectrum.js | 2 | ||||
| -rw-r--r-- | app/client/audio/pix2wav.js | 14 | ||||
| -rw-r--r-- | app/client/audio/wav2pix.js | 145 | ||||
| -rw-r--r-- | app/client/common/index.js | 22 | ||||
| -rw-r--r-- | app/client/common/progress.component.js | 1 | ||||
| -rw-r--r-- | app/client/dataset/dataset.new.js | 2 | ||||
| -rw-r--r-- | app/client/modules/pix2pix/views/pix2pix.show.js | 2 | ||||
| -rw-r--r-- | app/client/modules/pix2wav/pix2wav.reducer.js | 22 | ||||
| -rw-r--r-- | app/client/modules/pix2wav/views/pix2wav.show.js | 12 | ||||
| -rw-r--r-- | app/client/modules/pix2wav/views/spectrogram.upload.js | 132 | ||||
| -rw-r--r-- | app/client/modules/samplernn/views/samplernn.show.js | 2 | ||||
| -rw-r--r-- | app/client/types.js | 6 |
15 files changed, 301 insertions, 80 deletions
diff --git a/app/client/api/crud.types.js b/app/client/api/crud.types.js index 630bf83..83be34d 100644 --- a/app/client/api/crud.types.js +++ b/app/client/api/crud.types.js @@ -1,8 +1,11 @@ export const as_type = (a, b) => [a, b].join('_').toUpperCase() +export const with_type = (type, actions) => + actions.reduce((a, b) => (a[b] = as_type(type, b)) && a, {}) + export const crud_type = (type, actions=[]) => - actions.concat([ + with_type(type, actions.concat([ 'index_loading', 'index', 'index_error', @@ -24,5 +27,4 @@ export const crud_type = (type, actions=[]) => 'upload_complete', 'upload_error', 'sort', - ]) - .reduce((a, b) => (a[b] = as_type(type, b)) && a, {}) + ])) diff --git a/app/client/audio/lib/draw.js b/app/client/audio/lib/draw.js index e523b6a..d4bb817 100644 --- a/app/client/audio/lib/draw.js +++ b/app/client/audio/lib/draw.js @@ -1,6 +1,11 @@ +import util from '../../util' + const scratch = document.createElement('canvas') const scratchCtx = scratch.getContext('2d-lodpi') +const w = 256 +const h = 256 + export function spectrum(spec, x0, y0, ww, hh){ const data = spec.data const fft_size = spec.fft_size @@ -103,8 +108,8 @@ export function raw_spectrum(spec, x0, y0, ww, hh, def_min_r, def_min_i){ imag = col[v+1] mean_r += real mean_i += imag - _r = clamp((real - min_r) / delta_r * 255, 0, 255) - _i = clamp((imag - min_i) / delta_i * 255, 0, 255) + _r = util.clamp((real - min_r) / delta_r * 255, 0, 255) + _i = util.clamp((imag - min_i) / delta_i * 255, 0, 255) // hsl = color.hsl2rgb((_i + 1) / 2, 1.0, 1 - Math.abs(_r / 10)) pixels[u+0] = _r diff --git a/app/client/audio/lib/index.js b/app/client/audio/lib/index.js index ba96112..2d89ff6 100644 --- a/app/client/audio/lib/index.js +++ b/app/client/audio/lib/index.js @@ -1,7 +1,7 @@ import Tone from 'tone' import StartAudioContext from './startAudioContext' -import { is_mobile } from '../util' +import { is_mobile } from '../../util' export function requestAudioContext (fn) { if (is_mobile) { diff --git a/app/client/audio/lib/spectrum.js b/app/client/audio/lib/spectrum.js index f4a5444..c7252f1 100644 --- a/app/client/audio/lib/spectrum.js +++ b/app/client/audio/lib/spectrum.js @@ -1,6 +1,6 @@ import Tone from 'tone' -import { shuffle, quantize, mod } from '../util' +import { shuffle, quantize, mod } from '../../util' import { windows as signalWindows } from 'signal-windows' import FFTJS from 'fft.js' diff --git a/app/client/audio/pix2wav.js b/app/client/audio/pix2wav.js index ccd36be..1b103b4 100644 --- a/app/client/audio/pix2wav.js +++ b/app/client/audio/pix2wav.js @@ -1,17 +1,3 @@ -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 diff --git a/app/client/audio/wav2pix.js b/app/client/audio/wav2pix.js index e0a10fd..e9233e5 100644 --- a/app/client/audio/wav2pix.js +++ b/app/client/audio/wav2pix.js @@ -1,3 +1,5 @@ +import types from '../types' + import Tone from 'tone' import JSZip from 'jszip' import FileSaver from 'file-saver' @@ -6,73 +8,104 @@ import * as draw from './lib/draw' import output from './lib/output' import spectrum from './lib/spectrum' -import { - lerp, clamp, mod, -} from '../util' - import { requestAudioContext } from './lib' -let buffer -let sr = 44100 -let last_i = 0 -let _r = 8, _i = 8 - -let files, file_index = 0; - const FRAME_LENGTH = 126 * 255 const FRAME_OFFSET = FRAME_LENGTH / 4 -function init() { - requestAudioContext(ready) - draw.resize(256, 256) -} -function handleFileSelect(e) { - files = e.dataTransfer ? e.dataTransfer.files : e.target.files - loadNext() +const _r = 8 +const _i = 8 + +// 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) + } + }) } -function loadNext() { - var file = files[file_index++] - if (! file) return - load(file) + +export const loadPCM = (file) => { + return new Promise((resolve, reject) => { + loadBuffer(file).then(buffer => { + const pcm = buffer._buffer.getChannelData(0) + const sr = buffer._buffer.sampleRate + if (! pcm) return reject() + console.log(buffer, pcm, sr) + resolve({ buffer, pcm, sr }) + }) + }) } -function load(file) { - buffer = new Tone.Buffer( - URL.createObjectURL(file), - loadBuffer, - (err) => console.error('err', err) - ) + +export const renderFrames = (file, { frame_offset=FRAME_OFFSET, max=10 }) => dispatch => { + return new Promise((resolve, reject) => { + loadPCM(file).then(({ buffer, pcm, sr }) => { + dispatch({ type: types.wav2pix.loaded_buffer }) + let canvases = [] + for (let offset = 0, count = 0, _len = pcm.length - FRAME_LENGTH; + offset < _len && count < max; + offset += frame_offset, count += 1 + ) { + canvases.push(render(pcm.slice(offset, offset+FRAME_LENGTH), sr, count)) + } + dispatch({ type: types.wav2pix.draw_finish }) + resolve(canvases) + }) + }) } -function loadBuffer() { - // dispatch - console.log('loaded buffer', buffer) - const pcm = buffer._buffer.getChannelData(0) - const sr = buffer._buffer.sampleRate - if (! pcm) return - const zip = new JSZip() - const zip_folder = zip.folder("wav2pix_" + name); +export const buildZip = (name, file, opt) => dispatch => { + return new Promise((resolve, reject) => { + const frame_offset = opt.frame_offset || FRAME_OFFSET + loadPCM(file).then(({ buffer, pcm, sr }) => { + dispatch({ type: types.wav2pix.loaded_buffer }) - 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) - } + const zip = new JSZip() + const zip_folder = zip.folder("wav2pix_" + name); - // dispatch event - console.log('done exporting') - zip.generateAsync({ type: "blob" }).then(content => { - // dispatch - console.log('saving zip') - // FileSaver.saveAs(content, "wav2pix_" + name + ".zip") - setTimeout(loadNext, 1000) + for (let offset = 0, count = 0, _len = pcm.length - FRAME_LENGTH; + offset < _len; + offset += frame_offset, count += 1 + ) { + if ((count % 100) === 0) { + dispatch({ type: types.wav2pix.draw_progress, count }) + } + render(pcm.slice(offset, offset+FRAME_LENGTH), sr, count, zip_folder) + } + + // dispatch event + dispatch({ type: types.wav2pix.draw_finish }) + zip.generateAsync({ type: "blob" }).then(content => { + dispatch({ type: types.wav2pix.load_zip }) + // FileSaver.saveAs(content, "wav2pix_" + name + ".zip") + resolve(content) + }) + }) }) - // play(0) } -init() +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 } +} + diff --git a/app/client/common/index.js b/app/client/common/index.js new file mode 100644 index 0000000..de3e5b4 --- /dev/null +++ b/app/client/common/index.js @@ -0,0 +1,22 @@ +import Button from './button.component' +import { FileList, FileRow } from './fileList.component' +import FileUpload from './fileUpload.component' +import Gallery from './gallery.component' +import Group from './group.component' +import Header from './header.component' +import Loading from './loading.component' +import Param from './param.component' +import ParamGroup from './paramGroup.component' +import Player from './player.component' +import Progress from './progress.component' +import Select from './select.component' +import Slider from './slider.component' +import TextInput from './textInput.component' + +export { + Loading, Progress, Header, + FileList, FileRow, FileUpload, + Gallery, Player, + Group, ParamGroup, Param, + TextInput, Slider, Select, Button, +}
\ No newline at end of file diff --git a/app/client/common/progress.component.js b/app/client/common/progress.component.js index 364f232..5882239 100644 --- a/app/client/common/progress.component.js +++ b/app/client/common/progress.component.js @@ -1,6 +1,7 @@ import { h, Component } from 'preact' export default function Progress({progress}) { + if (! progress) return const { i, n } = progress const a = [] for (let j = 0; j < n; j++) { diff --git a/app/client/dataset/dataset.new.js b/app/client/dataset/dataset.new.js index bc169c7..a74e0bf 100644 --- a/app/client/dataset/dataset.new.js +++ b/app/client/dataset/dataset.new.js @@ -32,7 +32,7 @@ function NewDatasetForm (props) { ) } -const mapStateToProps = state => state +const mapStateToProps = state => ({}) const mapDispatchToProps = (dispatch, ownProps) => ({ actions: bindActionCreators(datasetActions, dispatch), diff --git a/app/client/modules/pix2pix/views/pix2pix.show.js b/app/client/modules/pix2pix/views/pix2pix.show.js index 2139c6c..9c55b0b 100644 --- a/app/client/modules/pix2pix/views/pix2pix.show.js +++ b/app/client/modules/pix2pix/views/pix2pix.show.js @@ -31,6 +31,8 @@ class Pix2pixShow extends Component { if (! pix2pix.folder || pix2pix.folder.id !== id) { actions.load_directories(id) } + } else { + this.props.history.push('/pix2pix/new/') } } render(){ diff --git a/app/client/modules/pix2wav/pix2wav.reducer.js b/app/client/modules/pix2wav/pix2wav.reducer.js index 0b55b07..8db1046 100644 --- a/app/client/modules/pix2wav/pix2wav.reducer.js +++ b/app/client/modules/pix2wav/pix2wav.reducer.js @@ -4,6 +4,7 @@ import datasetReducer from '../../dataset/dataset.reducer' const pix2wavInitialState = { loading: true, progress: { i: 0, n: 0 }, + status: '', error: null, folder_id: 0, data: null, @@ -15,6 +16,27 @@ const pix2wavReducer = (state = pix2wavInitialState, action) => { } switch (action.type) { + case types.wav2pix.loaded_buffer: + return { + ...state, + status: 'Loaded buffer', + } + case types.wav2pix.draw_progress: + console.log(action) + return { + ...state, + status: 'Rendering frame /', + } + case types.wav2pix.draw_finish: + return { + ...state, + status: 'Render complete', + } + case types.wav2pix.load_zip: + return { + ...state, + status: 'Built zip file', + } default: return state } diff --git a/app/client/modules/pix2wav/views/pix2wav.show.js b/app/client/modules/pix2wav/views/pix2wav.show.js index acb99b1..19f303d 100644 --- a/app/client/modules/pix2wav/views/pix2wav.show.js +++ b/app/client/modules/pix2wav/views/pix2wav.show.js @@ -12,6 +12,8 @@ import NewDatasetForm from '../../../dataset/dataset.new' import UploadStatus from '../../../dataset/upload.status' import { FileList, FileRow } from '../../../common/fileList.component' +import SpectrogramUpload from './spectrogram.upload' + import DatasetComponent from '../../../dataset/dataset.component' import pix2wavModule from '../pix2wav.module' @@ -31,6 +33,8 @@ class Pix2wavShow extends Component { if (! pix2wav.folder || pix2wav.folder.id !== id) { actions.load_directories(id) } + } else { + this.props.history.push('/pix2wav/new/') } } render(){ @@ -46,6 +50,14 @@ class Pix2wavShow extends Component { <UploadStatus /> </div> </div> + <SpectrogramUpload + loading={pix2wav.loading} + progress={pix2wav.progress} + id={pix2wav.folder_id} + module={pix2wavModule} + data={pix2wav.data} + folder={folder} + /> <DatasetComponent loading={pix2wav.loading} progress={pix2wav.progress} diff --git a/app/client/modules/pix2wav/views/spectrogram.upload.js b/app/client/modules/pix2wav/views/spectrogram.upload.js new file mode 100644 index 0000000..a0a2708 --- /dev/null +++ b/app/client/modules/pix2wav/views/spectrogram.upload.js @@ -0,0 +1,132 @@ +import { h, Component } from 'preact' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' +import moment from 'moment' +import util from '../../../util' + +import * as pix2wavActions from '../pix2wav.actions' +import * as pix2wavTasks from '../pix2wav.tasks' + +import { + Loading, Progress, + Group, Param, FileUpload, TextInput, Button +} from '../../../common' + +import * as wav2pixActions from '../../../audio/wav2pix' + +import pix2wavModule from '../pix2wav.module' + +class SpectrogramUpload extends Component { + constructor(props){ + super(props) + this.state = { + file: null, + name: "", + frames: [], + } + const audioElement = document.createElement('audio') + audioElement.addEventListener('loadedmetadata', () => { + this.setState({ duration: audioElement.duration }) + }) + this.audioElement = audioElement + } + pickFile(file){ + let name = file.name.split('.')[0] + .replace(/\s+/g, '_') + .replace(/-/g, '_') + .replace(/_+/g, '_') + this.setState({ file, name }) + this.audioElement.src = URL.createObjectURL(file) + console.log(file.size) + if (file.size < 2 << 20) { + console.log('booooooooo') + this.props.wav2pix.renderFrames(file, {}) + .then(frames => { + console.log(frames) + this.setState({ + ...this.state, frames + }) + }) + } + console.log(file) + // get info on the file... size, etc + } + buildZip(){ + const { file } = this.state + + } + render(){ + // loading={pix2wav.loading} + // progress={pix2wav.progress} + // id={pix2wav.folder_id} + // module={pix2wavModule} + // data={pix2wav.data} + // folder={folder} + const { file, frames } = this.state + return ( + <div className='row'> + <div className='col spectrogramBuilder'> + <Group title='Spectrogram Builder'> + <p> + {"Convert your sounds into spectrograms. "} + {"Sound files can be WAV, MP3, AIFF, or FLAC. "} + <b>2 minutes max.</b> + </p> + <FileUpload + title='Choose a sound file' + mime='image.*' + onUpload={file => this.pickFile(file)} + /> + <TextInput + title='Dataset name' + onChange={e => this.setState({ name: e.target.value })} + value={this.state.name} + /> + <Button + onClick={() => this.buildZip()} + >Build Zip</Button> + <Progress /> + {file && this.renderMetadata(file)} + </Group> + </div> + <div ref={(c) => { this.canvases = c }} id='pix2wav_canvases' /> + </div> + ) + } + renderMetadata(file){ + const { duration } = this.state + const size = util.hush_size(file.size) + return ( + <div className='fileMetadata'> + {file.size > 2 << 20 && + <p> + <i>Careful, your file is larger than 2 MB.</i> + </p>} + <Param title='Name'>{file.name}</Param> + <Param title='Type'>{file.type}</Param> + <Param title='Size'><span className={size[0]}>{size[1]}</span></Param> + <Param title='Date'>{moment(file.lastModifiedDate).format("YYYY-MM-DD h:mm a")}</Param> + <Param title='Duration'>{Math.floor(duration) + ' s.'}</Param> + <br /> + <Param title='Status'>{this.props.pix2wav.status}</Param> + </div> + ) + } + componentDidUpdate(){ + const canvases = (this.state.frames || []).map(c => { + this.canvases.append(c.canvas) + }) + } +} + +const mapStateToProps = state => ({ + pix2wav: state.module.pix2wav, +}) + +const mapDispatchToProps = (dispatch, ownProps) => ({ + actions: bindActionCreators(pix2wavActions, dispatch), + remote: bindActionCreators(pix2wavTasks, dispatch), + wav2pix: bindActionCreators(wav2pixActions, dispatch), +}) + +export default connect(mapStateToProps, mapDispatchToProps)(SpectrogramUpload) diff --git a/app/client/modules/samplernn/views/samplernn.show.js b/app/client/modules/samplernn/views/samplernn.show.js index b7e0740..a905b7c 100644 --- a/app/client/modules/samplernn/views/samplernn.show.js +++ b/app/client/modules/samplernn/views/samplernn.show.js @@ -33,6 +33,8 @@ class SampleRNNShow extends Component { console.log('looooooooooad', id) actions.load_directories(id) } + } else { + this.props.history.push('/samplernn/new/') } } render(){ diff --git a/app/client/types.js b/app/client/types.js index 7193c9a..3ef6366 100644 --- a/app/client/types.js +++ b/app/client/types.js @@ -1,4 +1,4 @@ -import { crud_type } from './api/crud.types' +import { crud_type, with_type } from './api/crud.types' export default { system: { @@ -96,7 +96,6 @@ export default { // update checkpoint settings // reset checkpoint settings // queue new checkpoint - // }, pix2pix: { init: 'PIX2PIX_INIT', @@ -106,4 +105,7 @@ export default { init: 'PIX2WAV_INIT', set_folder: 'PIX2WAV_SET_FOLDER', }, + wav2pix: with_type('wav2pix', [ + 'loaded_buffer', 'draw_progress', 'draw_finish', 'load_zip', 'rendered_frames', + ]) } |
