From 400da27e0683dd017156656b3f54cc283e4bdfcd Mon Sep 17 00:00:00 2001 From: Sean1572 Date: Wed, 18 Aug 2021 12:57:52 -0700 Subject: [PATCH 01/22] Added firefox compablity changes --- audino/frontend/src/components/reference.js | 1 - .../src/plugin/spectrogram/spectrogram.js | 1 + .../src/wavesurfer.js/src/webaudio.js | 1431 +++++++++-------- 3 files changed, 729 insertions(+), 704 deletions(-) diff --git a/audino/frontend/src/components/reference.js b/audino/frontend/src/components/reference.js index 38a5c96e..f034acdf 100644 --- a/audino/frontend/src/components/reference.js +++ b/audino/frontend/src/components/reference.js @@ -68,7 +68,6 @@ class Reference extends React.Component { wavesurfer.zoom(screenSize / wavesurfer.getDuration()); wavesurfer.spectrogram._onUpdate(screenSize); } - wavesurfer.enableDragSelection({ color: 'rgba(0, 102, 255, 0.3)' }); }); wavesurfer.on('pause', () => { diff --git a/audino/frontend/src/wavesurfer.js/src/plugin/spectrogram/spectrogram.js b/audino/frontend/src/wavesurfer.js/src/plugin/spectrogram/spectrogram.js index f4a34afd..bd9a1cca 100644 --- a/audino/frontend/src/wavesurfer.js/src/plugin/spectrogram/spectrogram.js +++ b/audino/frontend/src/wavesurfer.js/src/plugin/spectrogram/spectrogram.js @@ -4,6 +4,7 @@ const colormap = require('colormap'); class Spectrogram { constructor(wavesurfer, spectrCc, imageData, pixels, heightFactor) { + console.log("spectrogvram") this.wavesurfer = wavesurfer; this.spectrCc = spectrCc; this.imageData = imageData; diff --git a/audino/frontend/src/wavesurfer.js/src/webaudio.js b/audino/frontend/src/wavesurfer.js/src/webaudio.js index a04fbe1b..f2e09ce8 100644 --- a/audino/frontend/src/wavesurfer.js/src/webaudio.js +++ b/audino/frontend/src/wavesurfer.js/src/webaudio.js @@ -11,734 +11,759 @@ const FINISHED = 'finished'; * @extends {Observer} */ export default class WebAudio extends util.Observer { - /** scriptBufferSize: size of the processing buffer */ - static scriptBufferSize = 256; - - /** audioContext: allows to process audio with WebAudio API */ - audioContext = null; - - /** @private */ - offlineAudioContext = null; - - /** @private */ - stateBehaviors = { - [PLAYING]: { - init() { - this.addOnAudioProcess(); - }, - getPlayedPercents() { - const duration = this.getDuration(); - return this.getCurrentTime() / duration || 0; - }, - getCurrentTime() { - return this.startPosition + this.getPlayedTime(); - } - }, - [PAUSED]: { - init() { - this.removeOnAudioProcess(); - }, - getPlayedPercents() { - const duration = this.getDuration(); - return this.getCurrentTime() / duration || 0; - }, - getCurrentTime() { - return this.startPosition; - } - }, - [FINISHED]: { - init() { - this.removeOnAudioProcess(); - this.fireEvent('finish'); - }, - getPlayedPercents() { - return 1; - }, - getCurrentTime() { - return this.getDuration(); - } - } - }; - - /** - * Does the browser support this backend - * - * @return {boolean} Whether or not this browser supports this backend - */ - supportsWebAudio() { - return !!(window.AudioContext || window.webkitAudioContext); - } - - /** - * Get the audio context used by this backend or create one - * - * @return {AudioContext} Existing audio context, or creates a new one - */ - getAudioContext() { - if (!window.WaveSurferAudioContext) { - window.WaveSurferAudioContext = new (window.AudioContext || window.webkitAudioContext)(); - } - return window.WaveSurferAudioContext; - } - - /** - * Get the offline audio context used by this backend or create one - * - * @param {number} sampleRate The sample rate to use - * @return {OfflineAudioContext} Existing offline audio context, or creates - * a new one - */ - getOfflineAudioContext(sampleRate) { - if (!window.WaveSurferOfflineAudioContext) { - window.WaveSurferOfflineAudioContext = new (window.OfflineAudioContext || - window.webkitOfflineAudioContext)(1, 2, sampleRate); - } - return window.WaveSurferOfflineAudioContext; - } - - /** - * Construct the backend - * - * @param {WavesurferParams} params Wavesurfer parameters - */ - constructor(params) { - super(); + /** scriptBufferSize: size of the processing buffer */ + static scriptBufferSize = 256; + /** audioContext: allows to process audio with WebAudio API */ + audioContext = null; /** @private */ - this.params = params; - /** ac: Audio Context instance */ - this.ac = params.audioContext || (this.supportsWebAudio() ? this.getAudioContext() : {}); + offlineAudioContext = null; /** @private */ - this.lastPlay = this.ac.currentTime; - /** @private */ - this.startPosition = 0; - /** @private */ - this.scheduledPause = null; - /** @private */ - this.states = { - [PLAYING]: Object.create(this.stateBehaviors[PLAYING]), - [PAUSED]: Object.create(this.stateBehaviors[PAUSED]), - [FINISHED]: Object.create(this.stateBehaviors[FINISHED]) + stateBehaviors = { + [PLAYING]: { + init() { + this.addOnAudioProcess(); + }, + getPlayedPercents() { + const duration = this.getDuration(); + return this.getCurrentTime() / duration || 0; + }, + getCurrentTime() { + return this.startPosition + this.getPlayedTime(); + } + }, + [PAUSED]: { + init() { + this.removeOnAudioProcess(); + }, + getPlayedPercents() { + const duration = this.getDuration(); + return this.getCurrentTime() / duration || 0; + }, + getCurrentTime() { + return this.startPosition; + } + }, + [FINISHED]: { + init() { + this.removeOnAudioProcess(); + this.fireEvent('finish'); + }, + getPlayedPercents() { + return 1; + }, + getCurrentTime() { + return this.getDuration(); + } + } }; + + /** + * Does the browser support this backend + * + * @return {boolean} Whether or not this browser supports this backend + */ + supportsWebAudio() { + return !!(window.AudioContext || window.webkitAudioContext); + } + + /** + * Get the audio context used by this backend or create one + * + * @return {AudioContext} Existing audio context, or creates a new one + */ + getAudioContext() { + if (!window.WaveSurferAudioContext) { + window.WaveSurferAudioContext = new (window.AudioContext || + window.webkitAudioContext)(); + } + return window.WaveSurferAudioContext; + } + + /** + * Get the offline audio context used by this backend or create one + * + * @param {number} sampleRate The sample rate to use + * @return {OfflineAudioContext} Existing offline audio context, or creates + * a new one + */ + getOfflineAudioContext(sampleRate) { + if (!window.WaveSurferOfflineAudioContext) { + window.WaveSurferOfflineAudioContext = new (window.OfflineAudioContext || + window.webkitOfflineAudioContext)(1, 2, sampleRate); + } + return window.WaveSurferOfflineAudioContext; + } + + /** + * Construct the backend + * + * @param {WavesurferParams} params Wavesurfer parameters + */ + constructor(params) { + super(); + /** @private */ + this.params = params; + /** ac: Audio Context instance */ + this.ac = + params.audioContext || + (this.supportsWebAudio() ? this.getAudioContext() : {}); + /**@private */ + this.lastPlay = this.ac.currentTime; + /** @private */ + this.startPosition = 0; + /** @private */ + this.scheduledPause = null; + /** @private */ + this.states = { + [PLAYING]: Object.create(this.stateBehaviors[PLAYING]), + [PAUSED]: Object.create(this.stateBehaviors[PAUSED]), + [FINISHED]: Object.create(this.stateBehaviors[FINISHED]) + }; + /** @private */ + this.buffer = null; + /** @private */ + this.filters = []; + /** gainNode: allows to control audio volume */ + this.gainNode = null; + /** @private */ + this.mergedPeaks = null; + /** @private */ + this.offlineAc = null; + /** @private */ + this.peaks = null; + /** @private */ + this.playbackRate = 1; + /** analyser: provides audio analysis information */ + this.analyser = null; + /** scriptNode: allows processing audio */ + this.scriptNode = null; + /** @private */ + this.source = null; + /** @private */ + this.splitPeaks = []; + /** @private */ + this.state = null; + /** @private */ + this.explicitDuration = params.duration; + /** + * Boolean indicating if the backend was destroyed. + */ + this.destroyed = false; + } + + /** + * Initialise the backend, called in `wavesurfer.createBackend()` + */ + init() { + this.createVolumeNode(); + this.createScriptNode(); + this.createAnalyserNode(); + + this.setState(PAUSED); + this.setPlaybackRate(this.params.audioRate); + this.setLength(0); + } + /** @private */ - this.buffer = null; - /** @private */ - this.filters = []; - /** gainNode: allows to control audio volume */ - this.gainNode = null; - /** @private */ - this.mergedPeaks = null; - /** @private */ - this.offlineAc = null; - /** @private */ - this.peaks = null; - /** @private */ - this.playbackRate = 1; - /** analyser: provides audio analysis information */ - this.analyser = null; - /** scriptNode: allows processing audio */ - this.scriptNode = null; - /** @private */ - this.source = null; - /** @private */ - this.splitPeaks = []; + disconnectFilters() { + if (this.filters) { + this.filters.forEach(filter => { + filter && filter.disconnect(); + }); + this.filters = null; + // Reconnect direct path + this.analyser.connect(this.gainNode); + } + } + + /** + * @private + * + * @param {string} state The new state + */ + setState(state) { + if (this.state !== this.states[state]) { + this.state = this.states[state]; + this.state.init.call(this); + } + } + + /** + * Unpacked `setFilters()` + * + * @param {...AudioNode} filters One or more filters to set + */ + setFilter(...filters) { + this.setFilters(filters); + } + + /** + * Insert custom Web Audio nodes into the graph + * + * @param {AudioNode[]} filters Packed filters array + * @example + * const lowpass = wavesurfer.backend.ac.createBiquadFilter(); + * wavesurfer.backend.setFilter(lowpass); + */ + setFilters(filters) { + // Remove existing filters + this.disconnectFilters(); + + // Insert filters if filter array not empty + if (filters && filters.length) { + this.filters = filters; + + // Disconnect direct path before inserting filters + this.analyser.disconnect(); + + // Connect each filter in turn + filters + .reduce((prev, curr) => { + prev.connect(curr); + return curr; + }, this.analyser) + .connect(this.gainNode); + } + } + /** Create ScriptProcessorNode to process audio */ + createScriptNode() { + if (this.params.audioScriptProcessor) { + this.scriptNode = this.params.audioScriptProcessor; + } else { + if (this.ac.createScriptProcessor) { + this.scriptNode = this.ac.createScriptProcessor( + WebAudio.scriptBufferSize + ); + } else { + this.scriptNode = this.ac.createJavaScriptNode( + WebAudio.scriptBufferSize + ); + } + } + this.scriptNode.connect(this.ac.destination); + } + /** @private */ - this.state = null; + addOnAudioProcess() { + this.scriptNode.onaudioprocess = () => { + const time = this.getCurrentTime(); + + if (time >= this.getDuration()) { + this.setState(FINISHED); + this.fireEvent('pause'); + } else if (time >= this.scheduledPause) { + this.pause(); + } else if (this.state === this.states[PLAYING]) { + this.fireEvent('audioprocess', time); + } + }; + } + /** @private */ - this.explicitDuration = params.duration; + removeOnAudioProcess() { + this.scriptNode.onaudioprocess = null; + } + /** Create analyser node to perform audio analysis */ + createAnalyserNode() { + this.analyser = this.ac.createAnalyser(); + this.analyser.connect(this.gainNode); + } + /** - * Boolean indicating if the backend was destroyed. + * Create the gain node needed to control the playback volume. + * */ - this.destroyed = false; - } - - /** - * Initialise the backend, called in `wavesurfer.createBackend()` - */ - init() { - this.createVolumeNode(); - this.createScriptNode(); - this.createAnalyserNode(); - - this.setState(PAUSED); - this.setPlaybackRate(this.params.audioRate); - this.setLength(0); - } - - /** @private */ - disconnectFilters() { - if (this.filters) { - this.filters.forEach(filter => { - filter && filter.disconnect(); - }); - this.filters = null; - // Reconnect direct path - this.analyser.connect(this.gainNode); - } - } - - /** - * @private - * - * @param {string} state The new state - */ - setState(state) { - if (this.state !== this.states[state]) { - this.state = this.states[state]; - this.state.init.call(this); - } - } - - /** - * Unpacked `setFilters()` - * - * @param {...AudioNode} filters One or more filters to set - */ - setFilter(...filters) { - this.setFilters(filters); - } - - /** - * Insert custom Web Audio nodes into the graph - * - * @param {AudioNode[]} filters Packed filters array - * @example - * const lowpass = wavesurfer.backend.ac.createBiquadFilter(); - * wavesurfer.backend.setFilter(lowpass); - */ - setFilters(filters) { - // Remove existing filters - this.disconnectFilters(); - - // Insert filters if filter array not empty - if (filters && filters.length) { - this.filters = filters; - - // Disconnect direct path before inserting filters - this.analyser.disconnect(); - - // Connect each filter in turn - filters - .reduce((prev, curr) => { - prev.connect(curr); - return curr; - }, this.analyser) - .connect(this.gainNode); - } - } - - /** Create ScriptProcessorNode to process audio */ - createScriptNode() { - if (this.params.audioScriptProcessor) { - this.scriptNode = this.params.audioScriptProcessor; - } else if (this.ac.createScriptProcessor) { - this.scriptNode = this.ac.createScriptProcessor(WebAudio.scriptBufferSize); - } else { - this.scriptNode = this.ac.createJavaScriptNode(WebAudio.scriptBufferSize); - } - this.scriptNode.connect(this.ac.destination); - } - - /** @private */ - addOnAudioProcess() { - this.scriptNode.onaudioprocess = () => { - const time = this.getCurrentTime(); - - if (time >= this.getDuration()) { - this.setState(FINISHED); - this.fireEvent('pause'); - } else if (time >= this.scheduledPause) { - this.pause(); - } else if (this.state === this.states[PLAYING]) { - this.fireEvent('audioprocess', time); - } - }; - } - - /** @private */ - removeOnAudioProcess() { - this.scriptNode.onaudioprocess = () => {}; - } - - /** Create analyser node to perform audio analysis */ - createAnalyserNode() { - this.analyser = this.ac.createAnalyser(); - this.analyser.connect(this.gainNode); - } - - /** - * Create the gain node needed to control the playback volume. - * - */ - createVolumeNode() { - // Create gain node using the AudioContext - if (this.ac.createGain) { - this.gainNode = this.ac.createGain(); - } else { - this.gainNode = this.ac.createGainNode(); - } - // Add the gain node to the graph - this.gainNode.connect(this.ac.destination); - } - - /** - * Set the sink id for the media player - * - * @param {string} deviceId String value representing audio device id. - * @returns {Promise} A Promise that resolves to `undefined` when there - * are no errors. - */ - setSinkId(deviceId) { - if (deviceId) { - /** - * The webaudio API doesn't currently support setting the device - * output. Here we create an HTMLAudioElement, connect the - * webaudio stream to that element and setSinkId there. - */ - const audio = new window.Audio(); - if (!audio.setSinkId) { - return Promise.reject(new Error('setSinkId is not supported in your browser')); - } - audio.autoplay = true; - const dest = this.ac.createMediaStreamDestination(); - this.gainNode.disconnect(); - this.gainNode.connect(dest); - audio.srcObject = dest.stream; - - return audio.setSinkId(deviceId); - } - return Promise.reject(new Error(`Invalid deviceId: ${deviceId}`)); - } - - /** - * Set the audio volume - * - * @param {number} value A floating point value between 0 and 1. - */ - setVolume(value) { - this.gainNode.gain.setValueAtTime(value, this.ac.currentTime); - } - - /** - * Get the current volume - * - * @return {number} value A floating point value between 0 and 1. - */ - getVolume() { - return this.gainNode.gain.value; - } - - /** - * Decode an array buffer and pass data to a callback - * - * @private - * @param {ArrayBuffer} arraybuffer The array buffer to decode - * @param {function} callback The function to call on complete. - * @param {function} errback The function to call on error. - */ - decodeArrayBuffer(arraybuffer, callback, errback) { - if (!this.offlineAc) { - this.offlineAc = this.getOfflineAudioContext( - this.ac && this.ac.sampleRate ? this.ac.sampleRate : 44100 - ); - } - if ('webkitAudioContext' in window) { - // Safari: no support for Promise-based decodeAudioData enabled - // Enable it in Safari using the Experimental Features > Modern WebAudio API option - this.offlineAc.decodeAudioData(arraybuffer, data => callback(data), errback); - } else { - this.offlineAc - .decodeAudioData(arraybuffer) - .then(data => callback(data)) - .catch(err => errback(err)); - } - } - - /** - * Set pre-decoded peaks - * - * @param {number[]|Number.} peaks Peaks data - * @param {?number} duration Explicit duration - */ - setPeaks(peaks, duration) { - if (duration != null) { - this.explicitDuration = duration; - } - this.peaks = peaks; - } - - /** - * Set the rendered length (different from the length of the audio) - * - * @param {number} length The rendered length - */ - setLength(length) { - // No resize, we can preserve the cached peaks. - if (this.mergedPeaks && length === 2 * this.mergedPeaks.length - 1 + 2) { - return; - } - - this.splitPeaks = []; - this.mergedPeaks = []; - // Set the last element of the sparse array so the peak arrays are - // appropriately sized for other calculations. - const channels = this.buffer ? this.buffer.numberOfChannels : 1; - let c; - for (c = 0; c < channels; c++) { - this.splitPeaks[c] = []; - this.splitPeaks[c][2 * (length - 1)] = 0; - this.splitPeaks[c][2 * (length - 1) + 1] = 0; - } - this.mergedPeaks[2 * (length - 1)] = 0; - this.mergedPeaks[2 * (length - 1) + 1] = 0; - } - - /** - * Compute the max and min value of the waveform when broken into subranges. - * - * @param {number} length How many subranges to break the waveform into. - * @param {number} first First sample in the required range. - * @param {number} last Last sample in the required range. - * @return {number[]|Number.} Array of 2* peaks or array of arrays of - * peaks consisting of (max, min) values for each subrange. - */ - getPeaks(length, first, last) { - if (this.peaks) { - return this.peaks; - } - if (!this.buffer) { - return []; - } - - first = first || 0; - last = last || length - 1; - - this.setLength(length); - - if (!this.buffer) { - return this.params.splitChannels ? this.splitPeaks : this.mergedPeaks; + createVolumeNode() { + // Create gain node using the AudioContext + if (this.ac.createGain) { + this.gainNode = this.ac.createGain(); + } else { + this.gainNode = this.ac.createGainNode(); + } + // Add the gain node to the graph + this.gainNode.connect(this.ac.destination); + } + + /** + * Set the sink id for the media player + * + * @param {string} deviceId String value representing audio device id. + * @returns {Promise} A Promise that resolves to `undefined` when there + * are no errors. + */ + setSinkId(deviceId) { + if (deviceId) { + /** + * The webaudio API doesn't currently support setting the device + * output. Here we create an HTMLAudioElement, connect the + * webaudio stream to that element and setSinkId there. + */ + let audio = new window.Audio(); + if (!audio.setSinkId) { + return Promise.reject( + new Error('setSinkId is not supported in your browser') + ); + } + audio.autoplay = true; + const dest = this.ac.createMediaStreamDestination(); + this.gainNode.disconnect(); + this.gainNode.connect(dest); + audio.srcObject = dest.stream; + + return audio.setSinkId(deviceId); + } else { + return Promise.reject(new Error('Invalid deviceId: ' + deviceId)); + } + } + + /** + * Set the audio volume + * + * @param {number} value A floating point value between 0 and 1. + */ + setVolume(value) { + this.gainNode.gain.setValueAtTime(value, this.ac.currentTime); } /** - * The following snippet fixes a buffering data issue on the Safari - * browser which returned undefined It creates the missing buffer based - * on 1 channel, 4096 samples and the sampleRate from the current - * webaudio context 4096 samples seemed to be the best fit for rendering - * will review this code once a stable version of Safari TP is out + * Get the current volume + * + * @return {number} value A floating point value between 0 and 1. */ - if (!this.buffer.length) { - const newBuffer = this.createBuffer(1, 4096, this.sampleRate); - this.buffer = newBuffer.buffer; + getVolume() { + return this.gainNode.gain.value; } - const sampleSize = this.buffer.length / length; - const sampleStep = ~~(sampleSize / 10) || 1; - const channels = this.buffer.numberOfChannels; - let c; + /** + * Decode an array buffer and pass data to a callback + * + * @private + * @param {ArrayBuffer} arraybuffer The array buffer to decode + * @param {function} callback The function to call on complete. + * @param {function} errback The function to call on error. + */ + async decodeArrayBuffer(arraybuffer, callback, errback) { + if (!this.offlineAc) { + this.offlineAc = this.getOfflineAudioContext( + this.ac && this.ac.sampleRate ? this.ac.sampleRate : 44100 + ); + } + if ('webkitAudioContext' in window) { + // Safari: no support for Promise-based decodeAudioData enabled + // Enable it in Safari using the Experimental Features > Modern WebAudio API option + this.offlineAc.decodeAudioData( + arraybuffer, + data => callback(data), + errback + ); + } else { + + /*const context = new (window.AudioContext || window.webkitAudioContext)(); + const audiobuffer = await context.decodeAudioData( arraybuffer ); + console.log(audiobuffer) + callback(audiobuffer)*/ + console.log("here") + var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); + await audioCtx.decodeAudioData(arraybuffer, (data) => { + callback(data) + console.log("here") + }, + err => errback(err)) + } + } + + /** + * Set pre-decoded peaks + * + * @param {number[]|Number.} peaks Peaks data + * @param {?number} duration Explicit duration + */ + setPeaks(peaks, duration) { + if (duration != null) { + this.explicitDuration = duration; + } + this.peaks = peaks; + } + + /** + * Set the rendered length (different from the length of the audio) + * + * @param {number} length The rendered length + */ + setLength(length) { + // No resize, we can preserve the cached peaks. + if (this.mergedPeaks && length == 2 * this.mergedPeaks.length - 1 + 2) { + return; + } + + this.splitPeaks = []; + this.mergedPeaks = []; + // Set the last element of the sparse array so the peak arrays are + // appropriately sized for other calculations. + const channels = this.buffer ? this.buffer.numberOfChannels : 1; + let c; + for (c = 0; c < channels; c++) { + this.splitPeaks[c] = []; + this.splitPeaks[c][2 * (length - 1)] = 0; + this.splitPeaks[c][2 * (length - 1) + 1] = 0; + } + this.mergedPeaks[2 * (length - 1)] = 0; + this.mergedPeaks[2 * (length - 1) + 1] = 0; + } + + /** + * Compute the max and min value of the waveform when broken into subranges. + * + * @param {number} length How many subranges to break the waveform into. + * @param {number} first First sample in the required range. + * @param {number} last Last sample in the required range. + * @return {number[]|Number.} Array of 2* peaks or array of arrays of + * peaks consisting of (max, min) values for each subrange. + */ + getPeaks(length, first, last) { + if (this.peaks) { + return this.peaks; + } + if (!this.buffer) { + return []; + } + + first = first || 0; + last = last || length - 1; - for (c = 0; c < channels; c++) { - const peaks = this.splitPeaks[c]; - const chan = this.buffer.getChannelData(c); - let i; + this.setLength(length); + + if (!this.buffer) { + return this.params.splitChannels + ? this.splitPeaks + : this.mergedPeaks; + } - for (i = first; i <= last; i++) { - const start = ~~(i * sampleSize); - const end = ~~(start + sampleSize); /** - * Initialize the max and min to the first sample of this - * subrange, so that even if the samples are entirely - * on one side of zero, we still return the true max and - * min values in the subrange. + * The following snippet fixes a buffering data issue on the Safari + * browser which returned undefined It creates the missing buffer based + * on 1 channel, 4096 samples and the sampleRate from the current + * webaudio context 4096 samples seemed to be the best fit for rendering + * will review this code once a stable version of Safari TP is out */ - let min = chan[start]; - let max = min; - let j; + if (!this.buffer.length) { + const newBuffer = this.createBuffer(1, 4096, this.sampleRate); + this.buffer = newBuffer.buffer; + } - for (j = start; j < end; j += sampleStep) { - const value = chan[j]; + const sampleSize = this.buffer.length / length; + const sampleStep = ~~(sampleSize / 10) || 1; + const channels = this.buffer.numberOfChannels; + let c; + + for (c = 0; c < channels; c++) { + const peaks = this.splitPeaks[c]; + const chan = this.buffer.getChannelData(c); + let i; + + for (i = first; i <= last; i++) { + const start = ~~(i * sampleSize); + const end = ~~(start + sampleSize); + /** + * Initialize the max and min to the first sample of this + * subrange, so that even if the samples are entirely + * on one side of zero, we still return the true max and + * min values in the subrange. + */ + let min = chan[start]; + let max = min; + let j; + + for (j = start; j < end; j += sampleStep) { + const value = chan[j]; + + if (value > max) { + max = value; + } + + if (value < min) { + min = value; + } + } + + peaks[2 * i] = max; + peaks[2 * i + 1] = min; + + if (c == 0 || max > this.mergedPeaks[2 * i]) { + this.mergedPeaks[2 * i] = max; + } + + if (c == 0 || min < this.mergedPeaks[2 * i + 1]) { + this.mergedPeaks[2 * i + 1] = min; + } + } + } + + return this.params.splitChannels ? this.splitPeaks : this.mergedPeaks; + } - if (value > max) { - max = value; - } + /** + * Get the position from 0 to 1 + * + * @return {number} Position + */ + getPlayedPercents() { + return this.state.getPlayedPercents.call(this); + } - if (value < min) { - min = value; - } + /** @private */ + disconnectSource() { + if (this.source) { + this.source.disconnect(); + } + } + /** + * Destroy all references with WebAudio, disconnecting audio nodes and closing Audio Context + */ + destroyWebAudio() { + this.disconnectFilters(); + this.disconnectSource(); + this.gainNode.disconnect(); + this.scriptNode.disconnect(); + this.analyser.disconnect(); + + // close the audioContext if closeAudioContext option is set to true + if (this.params.closeAudioContext) { + // check if browser supports AudioContext.close() + if ( + typeof this.ac.close === 'function' && + this.ac.state != 'closed' + ) { + this.ac.close(); + } + // clear the reference to the audiocontext + this.ac = null; + // clear the actual audiocontext, either passed as param or the + // global singleton + if (!this.params.audioContext) { + window.WaveSurferAudioContext = null; + } else { + this.params.audioContext = null; + } + // clear the offlineAudioContext + window.WaveSurferOfflineAudioContext = null; + } + } + /** + * This is called when wavesurfer is destroyed + */ + destroy() { + if (!this.isPaused()) { + this.pause(); } + this.unAll(); + this.buffer = null; + this.destroyed = true; - peaks[2 * i] = max; - peaks[2 * i + 1] = min; + this.destroyWebAudio(); + } + + /** + * Loaded a decoded audio buffer + * + * @param {Object} buffer Decoded audio buffer to load + */ + load(buffer) { + this.startPosition = 0; + this.lastPlay = this.ac.currentTime; + this.buffer = buffer; + this.createSource(); + } - if (c === 0 || max > this.mergedPeaks[2 * i]) { - this.mergedPeaks[2 * i] = max; + /** @private */ + createSource() { + this.disconnectSource(); + this.source = this.ac.createBufferSource(); + + // adjust for old browsers + this.source.start = this.source.start || this.source.noteGrainOn; + this.source.stop = this.source.stop || this.source.noteOff; + + this.setPlaybackRate(this.playbackRate); + this.source.buffer = this.buffer; + this.source.connect(this.analyser); + } + + /** + * @private + * + * some browsers require an explicit call to #resume before they will play back audio + */ + resumeAudioContext() { + if (this.ac.state == 'suspended') { + this.ac.resume && this.ac.resume(); } + } + + /** + * Used by `wavesurfer.isPlaying()` and `wavesurfer.playPause()` + * + * @return {boolean} Whether or not this backend is currently paused + */ + isPaused() { + return this.state !== this.states[PLAYING]; + } - if (c === 0 || min < this.mergedPeaks[2 * i + 1]) { - this.mergedPeaks[2 * i + 1] = min; + /** + * Used by `wavesurfer.getDuration()` + * + * @return {number} Duration of loaded buffer + */ + getDuration() { + if (this.explicitDuration) { + return this.explicitDuration; } - } - } - - return this.params.splitChannels ? this.splitPeaks : this.mergedPeaks; - } - - /** - * Get the position from 0 to 1 - * - * @return {number} Position - */ - getPlayedPercents() { - return this.state.getPlayedPercents.call(this); - } - - /** @private */ - disconnectSource() { - if (this.source) { - this.source.disconnect(); - } - } - - /** - * Destroy all references with WebAudio, disconnecting audio nodes and closing Audio Context - */ - destroyWebAudio() { - this.disconnectFilters(); - this.disconnectSource(); - this.gainNode.disconnect(); - this.scriptNode.disconnect(); - this.analyser.disconnect(); - - // close the audioContext if closeAudioContext option is set to true - if (this.params.closeAudioContext) { - // check if browser supports AudioContext.close() - if (typeof this.ac.close === 'function' && this.ac.state !== 'closed') { - this.ac.close(); - } - // clear the reference to the audiocontext - this.ac = null; - // clear the actual audiocontext, either passed as param or the - // global singleton - if (!this.params.audioContext) { - window.WaveSurferAudioContext = null; - } else { - this.params.audioContext = null; - } - // clear the offlineAudioContext - window.WaveSurferOfflineAudioContext = null; - } - } - - /** - * This is called when wavesurfer is destroyed - */ - destroy() { - if (!this.isPaused()) { - this.pause(); - } - this.unAll(); - this.buffer = null; - this.destroyed = true; - - this.destroyWebAudio(); - } - - /** - * Loaded a decoded audio buffer - * - * @param {Object} buffer Decoded audio buffer to load - */ - load(buffer) { - this.startPosition = 0; - this.lastPlay = this.ac.currentTime; - this.buffer = buffer; - this.createSource(); - } - - /** @private */ - createSource() { - this.disconnectSource(); - this.source = this.ac.createBufferSource(); - - // adjust for old browsers - this.source.start = this.source.start || this.source.noteGrainOn; - this.source.stop = this.source.stop || this.source.noteOff; - - this.source.playbackRate.setValueAtTime(this.playbackRate, this.ac.currentTime); - this.source.buffer = this.buffer; - this.source.connect(this.analyser); - } - - /** - * @private - * - * some browsers require an explicit call to #resume before they will play back audio - */ - resumeAudioContext() { - if (this.ac.state === 'suspended') { - this.ac.resume && this.ac.resume(); - } - } - - /** - * Used by `wavesurfer.isPlaying()` and `wavesurfer.playPause()` - * - * @return {boolean} Whether or not this backend is currently paused - */ - isPaused() { - return this.state !== this.states[PLAYING]; - } - - /** - * Used by `wavesurfer.getDuration()` - * - * @return {number} Duration of loaded buffer - */ - getDuration() { - if (this.explicitDuration) { - return this.explicitDuration; - } - if (!this.buffer) { - return 0; - } - return this.buffer.duration; - } - - /** - * Used by `wavesurfer.seekTo()` - * - * @param {number} start Position to start at in seconds - * @param {number} end Position to end at in seconds - * @return {{start: number, end: number}} Object containing start and end - * positions - */ - seekTo(start, end) { - if (!this.buffer) { - return; - } - - this.scheduledPause = null; - - if (start == null) { - start = this.getCurrentTime(); - if (start >= this.getDuration()) { - start = 0; - } - } - if (end == null) { - end = this.getDuration(); - } - - this.startPosition = start; - this.lastPlay = this.ac.currentTime; - - if (this.state === this.states[FINISHED]) { - this.setState(PAUSED); - } - - return { - start, - end - }; - } - - /** - * Get the playback position in seconds - * - * @return {number} The playback position in seconds - */ - getPlayedTime() { - return (this.ac.currentTime - this.lastPlay) * this.playbackRate; - } - - /** - * Plays the loaded audio region. - * - * @param {number} start Start offset in seconds, relative to the beginning - * of a clip. - * @param {number} end When to stop relative to the beginning of a clip. - */ - play(start, end) { - if (!this.buffer) { - return; - } - - // need to re-create source on each playback - this.createSource(); - - const adjustedTime = this.seekTo(start, end); - - start = adjustedTime.start; - end = adjustedTime.end; - - this.scheduledPause = end; - - this.source.start(0, start); - - this.resumeAudioContext(); - - this.setState(PLAYING); - - this.fireEvent('play'); - } - - /** - * Pauses the loaded audio. - */ - pause() { - this.scheduledPause = null; - - this.startPosition += this.getPlayedTime(); - try { - this.source && this.source.stop(0); - } catch (err) { - // Calling stop can throw the following 2 errors: - // - RangeError (The value specified for when is negative.) - // - InvalidStateNode (The node has not been started by calling start().) - // We can safely ignore both errors, because: - // - The range is surely correct - // - The node might not have been started yet, in which case we just want to carry on without causing any trouble. - } - - this.setState(PAUSED); - - this.fireEvent('pause'); - } - - /** - * Returns the current time in seconds relative to the audio-clip's - * duration. - * - * @return {number} The current time in seconds - */ - getCurrentTime() { - return this.state.getCurrentTime.call(this); - } - - /** - * Returns the current playback rate. (0=no playback, 1=normal playback) - * - * @return {number} The current playback rate - */ - getPlaybackRate() { - return this.playbackRate; - } - - /** - * Set the audio source playback rate. - * - * @param {number} value The playback rate to use - */ - setPlaybackRate(value) { - this.playbackRate = value || 1; - this.source && this.source.playbackRate.setValueAtTime(this.playbackRate, this.ac.currentTime); - } - - /** - * Set a point in seconds for playback to stop at. - * - * @param {number} end Position to end at - * @version 3.3.0 - */ - setPlayEnd(end) { - this.scheduledPause = end; - } + if (!this.buffer) { + return 0; + } + return this.buffer.duration; + } + + /** + * Used by `wavesurfer.seekTo()` + * + * @param {number} start Position to start at in seconds + * @param {number} end Position to end at in seconds + * @return {{start: number, end: number}} Object containing start and end + * positions + */ + seekTo(start, end) { + if (!this.buffer) { + return; + } + + this.scheduledPause = null; + + if (start == null) { + start = this.getCurrentTime(); + if (start >= this.getDuration()) { + start = 0; + } + } + if (end == null) { + end = this.getDuration(); + } + + this.startPosition = start; + this.lastPlay = this.ac.currentTime; + + if (this.state === this.states[FINISHED]) { + this.setState(PAUSED); + } + + return { + start: start, + end: end + }; + } + + /** + * Get the playback position in seconds + * + * @return {number} The playback position in seconds + */ + getPlayedTime() { + return (this.ac.currentTime - this.lastPlay) * this.playbackRate; + } + + /** + * Plays the loaded audio region. + * + * @param {number} start Start offset in seconds, relative to the beginning + * of a clip. + * @param {number} end When to stop relative to the beginning of a clip. + */ + play(start, end) { + if (!this.buffer) { + return; + } + + // need to re-create source on each playback + this.createSource(); + + const adjustedTime = this.seekTo(start, end); + + start = adjustedTime.start; + end = adjustedTime.end; + + this.scheduledPause = end; + + this.source.start(0, start); + + this.resumeAudioContext(); + + this.setState(PLAYING); + + this.fireEvent('play'); + } + + /** + * Pauses the loaded audio. + */ + pause() { + this.scheduledPause = null; + + this.startPosition += this.getPlayedTime(); + try { + this.source && this.source.stop(0); + } catch (err) { + // Calling stop can throw the following 2 errors: + // - RangeError (The value specified for when is negative.) + // - InvalidStateNode (The node has not been started by calling start().) + // We can safely ignore both errors, because: + // - The range is surely correct + // - The node might not have been started yet, in which case we just want to carry on without causing any trouble. + } + + this.setState(PAUSED); + + this.fireEvent('pause'); + } + + /** + * Returns the current time in seconds relative to the audio-clip's + * duration. + * + * @return {number} The current time in seconds + */ + getCurrentTime() { + return this.state.getCurrentTime.call(this); + } + + /** + * Returns the current playback rate. (0=no playback, 1=normal playback) + * + * @return {number} The current playback rate + */ + getPlaybackRate() { + return this.playbackRate; + } + + /** + * Set the audio source playback rate. + * + * @param {number} value The playback rate to use + */ + setPlaybackRate(value) { + this.playbackRate = value || 1; + this.source && this.source.playbackRate.setValueAtTime( + this.playbackRate, + this.ac.currentTime + ); + } + + /** + * Set a point in seconds for playback to stop at. + * + * @param {number} end Position to end at + * @version 3.3.0 + */ + setPlayEnd(end) { + this.scheduledPause = end; + } } From e7be805a10f5c85e017e7b969d452055edc9f806 Mon Sep 17 00:00:00 2001 From: Sean1572 Date: Wed, 18 Aug 2021 14:38:49 -0700 Subject: [PATCH 02/22] created system to dynamically take in sample rate value from backend --- audino/frontend/src/pages/annotate.js | 4 ++-- .../src/plugin/spectrogram/index.js | 13 +++++++++-- .../src/wavesurfer.js/src/wavesurfer.js | 23 +++++++++++-------- .../src/wavesurfer.js/src/webaudio.js | 13 +++++++---- 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/audino/frontend/src/pages/annotate.js b/audino/frontend/src/pages/annotate.js index e17363b9..d394fd28 100644 --- a/audino/frontend/src/pages/annotate.js +++ b/audino/frontend/src/pages/annotate.js @@ -164,7 +164,7 @@ class Annotate extends React.Component { labels: response[0].data }); - const { is_marked_for_review, segmentations, filename, original_filename } = response[1].data; + const { is_marked_for_review, segmentations, filename, original_filename, sampling_rate } = response[1].data; const regions = segmentations.map(segmentation => { if (boundingBox) { @@ -200,7 +200,7 @@ class Annotate extends React.Component { original_filename }); - wavesurfer.load(`/audios/${filename}`); + wavesurfer.load(`/audios/${filename}`, null, null, null, sampling_rate); const { zoom } = this.state; wavesurfer.zoom(zoom); diff --git a/audino/frontend/src/wavesurfer.js/src/plugin/spectrogram/index.js b/audino/frontend/src/wavesurfer.js/src/plugin/spectrogram/index.js index 48876bef..72df4315 100644 --- a/audino/frontend/src/wavesurfer.js/src/plugin/spectrogram/index.js +++ b/audino/frontend/src/wavesurfer.js/src/plugin/spectrogram/index.js @@ -343,7 +343,9 @@ export default class SpectrogramPlugin { const { buffer } = this; const channelOne = buffer.getChannelData(0); // const bufferLength = buffer.length; - const { sampleRate } = buffer; + let { sampleRate } = buffer; + //sampleRate = 18000 * 2 + console.log(sampleRate) const frequencies = []; if (!buffer) { @@ -414,7 +416,14 @@ export default class SpectrogramPlugin { const getMaxY = frequenciesHeight || 512; const labelIndex = 5 * (getMaxY / 256); const freqStart = 0; - const step = (this.wavesurfer.backend.ac.sampleRate / 2 - freqStart) / labelIndex; + console.log(this.wavesurfer.backend.ac.sampleRate) + let sampleRate = 44100 + if (this.wavesurfer.backend.offlineAc.sampleRate) { + sampleRate = this.wavesurfer.backend.offlineAc.sampleRate + } else if (this.wavesurfer.backend.ac.sampleRate) { + sampleRate = this.wavesurfer.backend.ac.sampleRate + } + const step = (sampleRate / 2 - freqStart) / labelIndex; // prepare canvas element for labels const ctx = this.labelsEl.getContext('2d'); diff --git a/audino/frontend/src/wavesurfer.js/src/wavesurfer.js b/audino/frontend/src/wavesurfer.js/src/wavesurfer.js index 7837db97..e3afd699 100644 --- a/audino/frontend/src/wavesurfer.js/src/wavesurfer.js +++ b/audino/frontend/src/wavesurfer.js/src/wavesurfer.js @@ -1289,12 +1289,14 @@ export default class WaveSurfer extends util.Observer { * @private * @param {ArrayBuffer} arraybuffer Buffer to process */ - loadArrayBuffer(arraybuffer) { + loadArrayBuffer(arraybuffer, sampleRate = null) { + console.log(arraybuffer, sampleRate) this.decodeArrayBuffer(arraybuffer, data => { + console.log(data) if (!this.isDestroyed) { this.loadDecodedBuffer(data); } - }); + }, sampleRate); } /** @@ -1305,6 +1307,7 @@ export default class WaveSurfer extends util.Observer { * @emits WaveSurfer#ready */ loadDecodedBuffer(buffer) { + console.log(buffer) this.backend.load(buffer); this.drawBuffer(); this.isReady = true; @@ -1358,7 +1361,7 @@ export default class WaveSurfer extends util.Observer { * true * ); */ - load(url, peaks, preload, duration) { + load(url, peaks, preload, duration, sampleRate) { if (!url) { throw new Error('url parameter cannot be empty'); } @@ -1395,10 +1398,10 @@ export default class WaveSurfer extends util.Observer { if (this.params.backend === 'WebAudio' && url instanceof HTMLMediaElement) { url = url.src; } - + console.log(sampleRate) switch (this.params.backend) { case 'WebAudio': - return this.loadBuffer(url, peaks, duration); + return this.loadBuffer(url, peaks, duration, sampleRate); case 'MediaElement': case 'MediaElementWebAudio': return this.loadMediaElement(url, peaks, preload, duration); @@ -1415,12 +1418,13 @@ export default class WaveSurfer extends util.Observer { * @param {?number} duration Optional duration of audio file * @returns {void} */ - loadBuffer(url, peaks, duration) { + loadBuffer(url, peaks, duration, sampleRate = null) { + console.log(sampleRate) const load = action => { if (action) { this.tmpEvents.push(this.once('ready', action)); } - return this.getArrayBuffer(url, data => this.loadArrayBuffer(data)); + return this.getArrayBuffer(url, data => this.loadArrayBuffer(data, sampleRate)); }; if (peaks) { @@ -1501,7 +1505,7 @@ export default class WaveSurfer extends util.Observer { * @param {Object} arraybuffer The array buffer to decode * @param {function} callback The function to call on complete */ - decodeArrayBuffer(arraybuffer, callback) { + decodeArrayBuffer(arraybuffer, callback, sampleRate) { this.arraybuffer = arraybuffer; this.backend.decodeArrayBuffer( arraybuffer, @@ -1513,7 +1517,8 @@ export default class WaveSurfer extends util.Observer { this.arraybuffer = null; } }, - () => this.fireEvent('error', 'Error decoding audiobuffer') + () => this.fireEvent('error', 'Error decoding audiobuffer'), + sampleRate ); } diff --git a/audino/frontend/src/wavesurfer.js/src/webaudio.js b/audino/frontend/src/wavesurfer.js/src/webaudio.js index f2e09ce8..f3e58011 100644 --- a/audino/frontend/src/wavesurfer.js/src/webaudio.js +++ b/audino/frontend/src/wavesurfer.js/src/webaudio.js @@ -342,12 +342,15 @@ export default class WebAudio extends util.Observer { * @param {function} callback The function to call on complete. * @param {function} errback The function to call on error. */ - async decodeArrayBuffer(arraybuffer, callback, errback) { + async decodeArrayBuffer(arraybuffer, callback, errback, sampleRate) { + console.log("in decode array buffer", sampleRate, sampleRate ? sampleRate: this.ac && this.ac.sampleRate ? this.ac.sampleRate : 44100) if (!this.offlineAc) { this.offlineAc = this.getOfflineAudioContext( - this.ac && this.ac.sampleRate ? this.ac.sampleRate : 44100 + sampleRate ? sampleRate: this.ac && this.ac.sampleRate ? this.ac.sampleRate : 44100 ); } + + console.log(this.offlineAc) if ('webkitAudioContext' in window) { // Safari: no support for Promise-based decodeAudioData enabled // Enable it in Safari using the Experimental Features > Modern WebAudio API option @@ -363,10 +366,10 @@ export default class WebAudio extends util.Observer { console.log(audiobuffer) callback(audiobuffer)*/ console.log("here") - var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); - await audioCtx.decodeAudioData(arraybuffer, (data) => { + //var audioCtx = new (window.AudioContext || window.webkitAudioContext)(1, 2, sampleRate); + await this.offlineAc.decodeAudioData(arraybuffer, (data) => { callback(data) - console.log("here") + console.log("here", data) }, err => errback(err)) } From dd4257cefdb393ddd6ff1e0d863672787f8561d1 Mon Sep 17 00:00:00 2001 From: Sean1572 Date: Wed, 18 Aug 2021 15:56:36 -0700 Subject: [PATCH 03/22] manual sampling rate changer --- .../components/annotate/sampleRateChanger.js | 32 +++++++++++++++++++ audino/frontend/src/components/sideMenu.js | 2 ++ audino/frontend/src/pages/annotate.js | 8 +++-- .../src/wavesurfer.js/src/webaudio.js | 16 ++++------ 4 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 audino/frontend/src/components/annotate/sampleRateChanger.js diff --git a/audino/frontend/src/components/annotate/sampleRateChanger.js b/audino/frontend/src/components/annotate/sampleRateChanger.js new file mode 100644 index 00000000..65cff760 --- /dev/null +++ b/audino/frontend/src/components/annotate/sampleRateChanger.js @@ -0,0 +1,32 @@ +import React from 'react'; +import { Button } from '../button'; + +const SampleRateChanger = props => { + const {annotate, state} = props + const {wavesurfer} = state + const [text, setText] = React.useState("") + const handleSubmit = () => { + const int = parseInt(text, 10) + console.log(int) + + const newState = annotate.initalState; + newState["sampleRate"] = int || 44100 + annotate.setState(newState, () => { + wavesurfer.destroy(); + annotate.componentDidMount(); + }); + } + + const inputText = e => { + setText(e.target.value) + } + + return ( +
+ inputText(e)}/> +
+ ) +}; + +export default SampleRateChanger; diff --git a/audino/frontend/src/components/sideMenu.js b/audino/frontend/src/components/sideMenu.js index 91336772..4b87f51c 100644 --- a/audino/frontend/src/components/sideMenu.js +++ b/audino/frontend/src/components/sideMenu.js @@ -6,6 +6,7 @@ import { IconButton } from './button'; import SpectroChanger from './annotate/spectroChanger'; import ChangePlayback from './annotate/extraFeatures/changePlayback'; import PreviousAnnotationButton from './annotate/extraFeatures/previousAnnotationButton'; +import SampleRateChanger from './annotate/sampleRateChanger'; const SideMenuTab = props => { const { tab, icon, tabOpen, setTab } = props; @@ -100,6 +101,7 @@ const SideMenu = props => { {toUnsavedClipOn && annotate.UnsavedButton ? annotate.UnsavedButton.render() : null} + ) : null} diff --git a/audino/frontend/src/pages/annotate.js b/audino/frontend/src/pages/annotate.js index d394fd28..d34cacbc 100644 --- a/audino/frontend/src/pages/annotate.js +++ b/audino/frontend/src/pages/annotate.js @@ -165,7 +165,10 @@ class Annotate extends React.Component { }); const { is_marked_for_review, segmentations, filename, original_filename, sampling_rate } = response[1].data; - + let {sampleRate} = this.state + if (!sampleRate) { + sampleRate = sampling_rate + } const regions = segmentations.map(segmentation => { if (boundingBox) { return { @@ -200,7 +203,8 @@ class Annotate extends React.Component { original_filename }); - wavesurfer.load(`/audios/${filename}`, null, null, null, sampling_rate); + console.log("start load", sampleRate) + wavesurfer.load(`/audios/${filename}`, null, null, null, sampleRate); const { zoom } = this.state; wavesurfer.zoom(zoom); diff --git a/audino/frontend/src/wavesurfer.js/src/webaudio.js b/audino/frontend/src/wavesurfer.js/src/webaudio.js index f3e58011..43213a08 100644 --- a/audino/frontend/src/wavesurfer.js/src/webaudio.js +++ b/audino/frontend/src/wavesurfer.js/src/webaudio.js @@ -87,10 +87,8 @@ export default class WebAudio extends util.Observer { * a new one */ getOfflineAudioContext(sampleRate) { - if (!window.WaveSurferOfflineAudioContext) { - window.WaveSurferOfflineAudioContext = new (window.OfflineAudioContext || - window.webkitOfflineAudioContext)(1, 2, sampleRate); - } + window.WaveSurferOfflineAudioContext = new (window.OfflineAudioContext || + window.webkitOfflineAudioContext)(1, 2, sampleRate); return window.WaveSurferOfflineAudioContext; } @@ -344,11 +342,9 @@ export default class WebAudio extends util.Observer { */ async decodeArrayBuffer(arraybuffer, callback, errback, sampleRate) { console.log("in decode array buffer", sampleRate, sampleRate ? sampleRate: this.ac && this.ac.sampleRate ? this.ac.sampleRate : 44100) - if (!this.offlineAc) { - this.offlineAc = this.getOfflineAudioContext( - sampleRate ? sampleRate: this.ac && this.ac.sampleRate ? this.ac.sampleRate : 44100 - ); - } + this.offlineAc = this.getOfflineAudioContext( + sampleRate ? sampleRate: this.ac && this.ac.sampleRate ? this.ac.sampleRate : 44100 + ); console.log(this.offlineAc) if ('webkitAudioContext' in window) { @@ -367,11 +363,13 @@ export default class WebAudio extends util.Observer { callback(audiobuffer)*/ console.log("here") //var audioCtx = new (window.AudioContext || window.webkitAudioContext)(1, 2, sampleRate); + console.log(arraybuffer) await this.offlineAc.decodeAudioData(arraybuffer, (data) => { callback(data) console.log("here", data) }, err => errback(err)) + } } From 46ba477e8e24eb338e77c02c0ec56852d2d17491 Mon Sep 17 00:00:00 2001 From: Sean1572 Date: Mon, 23 Aug 2021 19:00:57 -0700 Subject: [PATCH 04/22] added zoom component but more work is still need debugging --- .../frontend/src/components/annotate/zoom.js | 28 +++++++++++++++++++ audino/frontend/src/components/sideMenu.js | 5 +++- .../frontend/src/components/stickySlider.js | 4 ++- 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 audino/frontend/src/components/annotate/zoom.js diff --git a/audino/frontend/src/components/annotate/zoom.js b/audino/frontend/src/components/annotate/zoom.js new file mode 100644 index 00000000..98ef85e1 --- /dev/null +++ b/audino/frontend/src/components/annotate/zoom.js @@ -0,0 +1,28 @@ +import React from 'react'; +import StickySlider from '../stickySlider'; +const Zoom = props => { + const {annotate} = props + const {state} = annotate; + const {isRendering, wavesurfer} = state + + const handleZoom = value => { + console.log("hello") + wavesurfer.zoom(value); + } + + return ( +
+ handleZoom(value)} + stickyPos={[0, 200]} + threshold={5} + /> +
+ ); +}; + +export default Zoom; diff --git a/audino/frontend/src/components/sideMenu.js b/audino/frontend/src/components/sideMenu.js index 25653d77..4b467805 100644 --- a/audino/frontend/src/components/sideMenu.js +++ b/audino/frontend/src/components/sideMenu.js @@ -6,7 +6,7 @@ import { Button, IconButton } from './button'; import SpectroChanger from './annotate/spectroChanger'; import ChangePlayback from './annotate/extraFeatures/changePlayback'; import PreviousAnnotationButton from './annotate/extraFeatures/previousAnnotationButton'; - +import Zoom from './annotate/zoom'; const SideMenuTab = props => { const { tab, icon, tabOpen, setTab } = props; const swapTabs = tab => { @@ -101,6 +101,9 @@ const SideMenu = props => { {toUnsavedClipOn && annotate.UnsavedButton ? annotate.UnsavedButton.render() : null} + + +