diff --git a/assets/template.html b/assets/template.html index 7fcf68c..ff07a2d 100644 --- a/assets/template.html +++ b/assets/template.html @@ -292,6 +292,7 @@ + diff --git a/bin/web/css/demo.css b/bin/web/css/demo.css index 9d6d978..7ebf71d 100755 --- a/bin/web/css/demo.css +++ b/bin/web/css/demo.css @@ -964,3 +964,6 @@ h4{ margin-bottom: -3px; box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.7), 0 3px 4px rgba(0, 0, 0, 0.7); } +.invisible { + display: none; +} diff --git a/bin/web/js/audio.js b/bin/web/js/audio.js index 036856f..2dbfeaa 100644 --- a/bin/web/js/audio.js +++ b/bin/web/js/audio.js @@ -19,6 +19,7 @@ const AudioMappingOptions = function() { this.max_out = 1.0; this.smoothing = config.audio.defaultSmoothing; this.sync = 'volume'; + this.source = 'microphone'; this.value = 0.0; }; @@ -270,8 +271,26 @@ const Audio = function(tp, record) { const ld = panel.querySelector(toCssClass(`audio_letterDelay${propTitle}`,'#')); mappingOptions.letterDelay = typeof ld.value === 'number' ? ld.value : parseInt(ld.value); } + mappingOptions.source = panel.querySelector(toCssClass(`audio_source${propTitle}`, '#')).value; }; + const source_Dom = document.createElement('select'); + source_Dom.id = toCssClass(`audio_source${propTitle}`); + const source_mic = document.createElement('option'); + source_mic.value = 'microphone'; + source_mic.innerHTML = 'microphone'; + source_Dom.append(source_mic); + FS.readdir(config.fs.idbfsAudioDir) + .forEach((file) => { + if (file[0] !== '.') { + const source_file = document.createElement('option'); + source_file.value = file; + source_file.innerHTML = file; + source_Dom.append(source_file); + } + }); + audioOptions.append(source_Dom); + const min_max_Dom = document.createElement('div'); min_max_Dom.classList.add('audio_min_max'); const min_Cont = document.createElement('div'); @@ -391,6 +410,7 @@ const Audio = function(tp, record) { fft_Dom.append(fft_imgDom); fft_Dom.append(fft_selectDom); audioOptions.append(fft_Dom); + source_Dom.addEventListener('change', updateMappingOptions); min_inputDom.addEventListener('change', updateMappingOptions); max_inputDom.addEventListener('change', updateMappingOptions); smoothing_inputDom.addEventListener('change', updateMappingOptions); @@ -588,6 +608,56 @@ const Audio = function(tp, record) { } }); }; + const audioFileStuff = {}; + const readAudioFiles = () => { + FS.readdir(config.fs.idbfsAudioDir).forEach((file) => { + if (file.indexOf('.') !== 0 && !audioFileStuff.hasOwnProperty(file)) { + const audioElement = document.createElement('audio'); + audioElement.classList.add('invisible'); + audioElement.classList.add('audio_file'); + audioElement.classList.add(toCssClass(`audio_file${file}`)); + document.querySelector('body').append(audioElement); + + const arr = FS.readFile(`${config.fs.idbfsAudioDir}/${file}`); + let type = 'audio/wav'; + const filesplit = file.split('.'); + const extension = filesplit[filesplit.length - 1]; + if (extension === 'wav') { + type = 'audio/wav'; + } else if (extension === 'mp3') { + type = 'audio/mpeg'; + } else if (extension === 'ogg') { + type = 'audio/ogg'; + } + + const src = URL.createObjectURL( + new Blob([arr], { + type + }) + ); + + audioElement.src = src; + + const source = audioCtx.createMediaElementSource(audioElement); + source.connect(audioCtx.destination); + const analyser = audioCtx.createAnalyser(); + analyser.fftSize = config.audio.fftBandsAnalysed; + const bufferLength = analyser.frequencyBinCount; + const dataArray = new Uint8Array(bufferLength); + + source.connect(analyser); + + audioElement.play(); + + audioFileStuff[file] = { + dataArray, + analyser, + audioElement, + }; + } + }); + }; + const init = () => { if (!started) { @@ -647,6 +717,8 @@ const Audio = function(tp, record) { analyser.smoothingTimeConstant = 0.85; window.analyser = analyser; + readAudioFiles(); + //const distortion = audioCtx.createWaveShaper(); //const gainNode = audioCtx.createGain(); //const biquadFilter = audioCtx.createBiquadFilter(); @@ -800,7 +872,11 @@ const Audio = function(tp, record) { canvasKeys = Object.keys(canvasCombos); drawVisual = requestAnimationFrame(drawAlt); - analyser.getByteFrequencyData(dataArrayAlt); + //analyser.getByteFrequencyData(dataArrayAlt); + //Object.keys(audioFileStuff).forEach((afs) => { + //afs.analyser.ByteFrequencyData(afs.dataArray); + //}); + audioFileStuff['hito_steyerl_about_suicide_cameras.ogg'].analyser.getByteFrequencyData(dataArrayAlt); for (let i = 0; i < canvasKeys.length; i++) { canvasCombos[canvasKeys[i]][1].fillStyle = "rgb(0, 0, 0)"; // AUDIO COLOR diff --git a/bin/web/js/config.js b/bin/web/js/config.js index 11f13b8..5da5973 100644 --- a/bin/web/js/config.js +++ b/bin/web/js/config.js @@ -114,6 +114,7 @@ const config = { fs: { idbfsDir: '/idbfs', idbfsFontDir: '/idbfs/fonts', + idbfsAudioDir: '/idbfs/audio', idbfsTmpDir: '/idbfs/tmp', }, timeline: { diff --git a/bin/web/js/main.js b/bin/web/js/main.js index 3719162..1b9a936 100644 --- a/bin/web/js/main.js +++ b/bin/web/js/main.js @@ -156,6 +156,11 @@ const findInjectPanel = () => { bottomButtonsContainer.append(hideuiButton); hideuiButton.classList.add("main_panel_button"); } + const audiofileButton = document.querySelector('#upload_audio'); + if (audiofileButton !== null) { + bottomButtonsContainer.append(audiofileButton); + audiofileButton.classList.add("main_panel_button"); + } const exportButton = document.querySelector('#exporter_open'); if (exportButton !== null) { bottomButtonsContainer.append(exportButton); @@ -562,4 +567,21 @@ const initPanels = () => { document.addEventListener('keypress', handleUiKeypress); }); } + let audiofileButton = document.querySelector('#upload_audio'); + if (audiofileButton === null) { + audiofileButton = tp.getPanel().querySelector('#upload_audio'); + } + if (audiofileButton !== null) { + audiofileButton.addEventListener('click', () => { + uploadFile('audio') + .then((file) => { + moduleFS + .save(file) + .then(() => { + console.log('ermh... done uploading?', file); + }); + }); + }); + } + }; diff --git a/bin/web/js/moduleFS.js b/bin/web/js/moduleFS.js index 3611916..a3d872d 100644 --- a/bin/web/js/moduleFS.js +++ b/bin/web/js/moduleFS.js @@ -13,6 +13,9 @@ const ModuleFS = function() { if (!FS.analyzePath(config.fs.idbfsFontDir).exists) { FS.mkdir(config.fs.idbfsFontDir); } + if (!FS.analyzePath(config.fs.idbfsAudioDir).exists) { + FS.mkdir(config.fs.idbfsAudioDir); + } if (!FS.analyzePath(config.fs.idbfsTmpDir).exists) { FS.mkdir(config.fs.idbfsTmpDir); } @@ -59,6 +62,19 @@ const ModuleFS = function() { .then(() => { resolve(filePath); }); + } else if (file.type.indexOf('audio') === 0) { + var uint8View = new Uint8Array(file.arrayBuffer); + console.log('trying to save the audio file, file, uint8View', file, uint8View); + if (!FS.analyzePath(`${config.fs.idbfsAudioDir}/${file.name}`).exists) { + FS.createDataFile(config.fs.idbfsAudioDir, file.name, uint8View, true, true); + this.syncfs(MODE_WRITE_TO_PERSISTENT) + .then(() => { + resolve(true); + }); + } else { + alert(`It seems as if an audiofile with the name "${file.name}" already exists. Please rename your file and upload again, thanks <3`); + resolve(false); + } } else { resolve(false); } diff --git a/bin/web/js/utils.js b/bin/web/js/utils.js index 958ce23..166753c 100644 --- a/bin/web/js/utils.js +++ b/bin/web/js/utils.js @@ -119,7 +119,7 @@ function uploadFile(expectedType = 'application/json') { let reader = new FileReader(); - if (expectedType === 'application/zip' || file.type === 'application/zip') { + if (expectedType === 'application/zip' || file.type === 'application/zip' || file.type.indexOf('audio') === 0) { reader.onload = (e) => { const f = e.target.result; console.log(e, file.name, file.size, file.type, f);