(prodigy) tslade@RTI-107301 ~/projects/teacherprints/prodigy 13:16:57 .18783 (prodigy-annotation) $ PRODIGY_LOGGING=verbose prodigy post-sad-multiclass -d eNY-2step -s
../data/training_inputs/audio/chunked -t round2 -l FEM,MAL,CHI\(1\),CHI\(2P\) -F ./post-sad-multiclass.py
13:17:02: INIT: Setting all logging levels to 10
email-validator not installed, email fields will be treated as str.
To install, run: pip install email-validator
13:17:07: RECIPE: Loading recipe from file ./post-sad-multiclass.py
13:17:07: RECIPE: Calling recipe 'post-sad-multiclass'
Using 4 label(s): FEM, MAL, CHI(1), CHI(2P)
13:17:07: Defining blocks
13:17:07: Instantiating stream
13:17:07: VALIDATE: Validating components returned by recipe
13:17:07: CONTROLLER: Initialising from recipe
{'before_db': None, 'config': {'blocks': [{'view_id': 'html', 'html_template': '\n \n\n'}, {'view_id': 'audio_manual'}], 'javascript': 'console.log("Loading component libraries...");\n/* http://wavesurfer-js.org/example/stretcher/soundtouch.js\n * SoundTouch JS audio processing library\n * Copyright (c) Olli Parviainen\n * Copyright (c) Ryan Berdeen\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n * Lesser General License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n */\nconsole.log("Loading soundtouch.js");\n(function(window) {\n /**\n * Giving this value for the sequence length sets automatic parameter value\n * according to tempo setting (recommended)\n */\n var USE_AUTO_SEQUENCE_LEN = 0;\n\n /**\n * Default length of a single processing sequence, in milliseconds. This determines to how\n * long sequences the original sound is chopped in the time-stretch algorithm.\n *\n * The larger this value is, the lesser sequences are used in processing. In principle\n * a bigger value sounds better when slowing down tempo, but worse when increasing tempo\n * and vice versa.\n *\n * Increasing this value reduces computational burden and vice versa.\n */\n //var DEFAULT_SEQUENCE_MS = 130\n var DEFAULT_SEQUENCE_MS = USE_AUTO_SEQUENCE_LEN;\n\n /**\n * Giving this value for the seek window length sets automatic parameter value\n * according to tempo setting (recommended)\n */\n var USE_AUTO_SEEKWINDOW_LEN = 0;\n\n /**\n * Seeking window default length in milliseconds for algorithm that finds the best possible\n * overlapping location. This determines from how wide window the algorithm may look for an\n * optimal joining location when mixing the sound sequences back together.\n *\n * The bigger this window setting is, the higher the possibility to find a better mixing\n * position will become, but at the same time large values may cause a "drifting" artifact\n * because consequent sequences will be taken at more uneven intervals.\n *\n * If there\'s a disturbing artifact that sounds as if a constant frequency was drifting\n * around, try reducing this setting.\n *\n * Increasing this value increases computational burden and vice versa.\n */\n //var DEFAULT_SEEKWINDOW_MS = 25;\n var DEFAULT_SEEKWINDOW_MS = USE_AUTO_SEEKWINDOW_LEN;\n\n /**\n * Overlap length in milliseconds. When the chopped sound sequences are mixed back together,\n * to form a continuous sound stream, this parameter defines over how long period the two\n * consecutive sequences are let to overlap each other.\n *\n * This shouldn\'t be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting\n * by a large amount, you might wish to try a smaller value on this.\n *\n * Increasing this value increases computational burden and vice versa.\n */\n var DEFAULT_OVERLAP_MS = 8;\n\n // Table for the hierarchical mixing position seeking algorithm\n var _SCAN_OFFSETS = [\n [\n 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806, 868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0\n ],\n [\n -100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n ],\n [\n -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n ],\n [\n -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n ]\n ];\n\n // Adjust tempo param according to tempo, so that variating processing sequence length is used\n // at varius tempo settings, between the given low...top limits\n var AUTOSEQ_TEMPO_LOW = 0.5; // auto setting low tempo range (-50%)\n var AUTOSEQ_TEMPO_TOP = 2.0; // auto setting top tempo range (+100%)\n\n // sequence-ms setting values at above low & top tempo\n var AUTOSEQ_AT_MIN = 125.0;\n var AUTOSEQ_AT_MAX = 50.0;\n var AUTOSEQ_K =\n (AUTOSEQ_AT_MAX - AUTOSEQ_AT_MIN) /\n (AUTOSEQ_TEMPO_TOP - AUTOSEQ_TEMPO_LOW);\n var AUTOSEQ_C = AUTOSEQ_AT_MIN - AUTOSEQ_K * AUTOSEQ_TEMPO_LOW;\n\n // seek-window-ms setting values at above low & top tempo\n var AUTOSEEK_AT_MIN = 25.0;\n var AUTOSEEK_AT_MAX = 15.0;\n var AUTOSEEK_K =\n (AUTOSEEK_AT_MAX - AUTOSEEK_AT_MIN) /\n (AUTOSEQ_TEMPO_TOP - AUTOSEQ_TEMPO_LOW);\n var AUTOSEEK_C = AUTOSEEK_AT_MIN - AUTOSEEK_K * AUTOSEQ_TEMPO_LOW;\n\n function extend(a, b) {\n for (var i in b) {\n var g = b.__lookupGetter__(i),\n s = b.__lookupSetter__(i);\n if (g || s) {\n if (g) {\n a.__defineGetter__(i, g);\n }\n if (s) {\n a.__defineSetter__(i, s);\n }\n } else {\n a[i] = b[i];\n
}\n }\n return a;\n }\n\n function testFloatEqual(a, b) {\n return (a > b ? a - b : b - a) > 1e-10;\n }\n\n function AbstractFifoSamplePipe(createBuffers) {\n if (createBuffers) {\n this.inputBuffer = new FifoSampleBuffer();\n this.outputBuffer = new FifoSampleBuffer();\n } else {\n this.inputBuffer = this.outputBuffer = null;\n }\n }\n AbstractFifoSamplePipe.prototype = {\n get inputBuffer() {\n return this._inputBuffer;\n },\n set inputBuffer(inputBuffer) {\n this._inputBuffer = inputBuffer;\n },\n get outputBuffer() {\n return this._outputBuffer;\n },\n set outputBuffer(outputBuffer) {\n this._outputBuffer = outputBuffer;\n },\n clear: function() {\n this._inputBuffer.clear();\n this._outputBuffer.clear();\n }\n };\n\n function RateTransposer(createBuffers) {\n AbstractFifoSamplePipe.call(this, createBuffers);\n this._reset();\n this.rate = 1;\n }\n extend(RateTransposer.prototype, AbstractFifoSamplePipe.prototype);\n extend(RateTransposer.prototype, {\n set rate(rate) {\n this._rate = rate;\n // TODO aa filter\n },\n _reset: function() {\n this.slopeCount = 0;\n this.prevSampleL = 0;\n this.prevSampleR = 0;\n },\n process: function() {\n // TODO aa filter\n var numFrames = this._inputBuffer.frameCount;\n this._outputBuffer.ensureAdditionalCapacity(\n numFrames / this._rate + 1\n );\n var numFramesOutput = this._transpose(numFrames);\n this._inputBuffer.receive();\n this._outputBuffer.put(numFramesOutput);\n },\n _transpose: function(numFrames) {\n if (numFrames === 0) {\n return 0; // No work.\n }\n\n var src = this._inputBuffer.vector;\n var srcOffset = this._inputBuffer.startIndex;\n\n var dest = this._outputBuffer.vector;\n var destOffset = this._outputBuffer.endIndex;\n\n var used = 0;\n var i = 0;\n\n while (this.slopeCount < 1.0) {\n dest[destOffset + 2 * i] =\n (1.0 - this.slopeCount) * this.prevSampleL +\n this.slopeCount * src[srcOffset];\n dest[destOffset + 2 * i + 1] =\n (1.0 - this.slopeCount) * this.prevSampleR +\n this.slopeCount * src[srcOffset + 1];\n i++;\n this.slopeCount += this._rate;\n }\n\n this.slopeCount -= 1.0;\n\n if (numFrames != 1) {\n // eslint-disable-next-line no-constant-condition\n out: while (true) {\n while (this.slopeCount > 1.0) {\n this.slopeCount -= 1.0;\n used++;\n if (used >= numFrames - 1) {\n break out;\n }\n }\n\n var srcIndex = srcOffset + 2 * used;\n dest[destOffset + 2 * i] =\n (1.0 - this.slopeCount) * src[srcIndex] +\n this.slopeCount * src[srcIndex + 2];\n dest[destOffset + 2 * i + 1] =\n (1.0 - this.slopeCount) * src[srcIndex + 1] +\n this.slopeCount * src[srcIndex + 3];\n\n i++;\n this.slopeCount += this._rate;\n }\n }\n\n this.prevSampleL = src[srcOffset + 2 * numFrames - 2];\n this.prevSampleR = src[srcOffset + 2 * numFrames - 1];\n\n return i;\n }\n });\n\n function FifoSampleBuffer() {\n this._vector = new Float32Array();\n this._position = 0;\n this._frameCount = 0;\n }\n FifoSampleBuffer.prototype = {\n get vector() {\n return this._vector;\n },\n get position() {\n return this._position;\n },\n get startIndex() {\n return this._position * 2;\n },\n get frameCount() {\n
return this._frameCount;\n },\n get endIndex() {\n return (this._position + this._frameCount) * 2;\n },\n clear: function(frameCount) {\n this.receive(frameCount);\n this.rewind();\n },\n put: function(numFrames) {\n this._frameCount += numFrames;\n },\n putSamples: function(samples, position, numFrames) {\n position = position || 0;\n var sourceOffset = position * 2;\n
if (!(numFrames >= 0)) {\n numFrames = (samples.length - sourceOffset) / 2;\n }\n var numSamples = numFrames * 2;\n\n this.ensureCapacity(numFrames + this._frameCount);\n\n var destOffset = this.endIndex;\n this._vector.set(\n samples.subarray(sourceOffset, sourceOffset + numSamples),\n destOffset\n );\n\n this._frameCount += numFrames;\n },\n putBuffer: function(buffer, position, numFrames) {\n position = position || 0;\n if (!(numFrames >= 0)) {\n numFrames = buffer.frameCount - position;\n }\n this.putSamples(\n buffer.vector,\n buffer.position + position,\n numFrames\n );\n },\n receive: function(numFrames) {\n if (!(numFrames >= 0) || numFrames > this._frameCount) {\n numFrames = this._frameCount;\n }\n this._frameCount -= numFrames;\n this._position += numFrames;\n },\n receiveSamples: function(output, numFrames) {\n
var numSamples = numFrames * 2;\n var sourceOffset = this.startIndex;\n output.set(\n this._vector.subarray(sourceOffset, sourceOffset + numSamples)\n );\n this.receive(numFrames);\n },\n extract: function(output, position, numFrames) {\n var sourceOffset = this.startIndex + position * 2;\n var numSamples = numFrames * 2;\n output.set(\n this._vector.subarray(sourceOffset, sourceOffset + numSamples)\n );\n },\n ensureCapacity: function(numFrames) {\n var minLength = numFrames * 2;\n if (this._vector.length < minLength) {\n var newVector = new Float32Array(minLength);\n newVector.set(\n this._vector.subarray(this.startIndex, this.endIndex)\n );\n this._vector = newVector;\n this._position = 0;\n } else {\n this.rewind();\n }\n },\n ensureAdditionalCapacity: function(numFrames) {\n this.ensureCapacity(this.frameCount + numFrames);\n },\n rewind: function() {\n if (this._position > 0) {\n this._vector.set(\n this._vector.subarray(this.startIndex, this.endIndex)\n );\n this._position = 0;\n }\n }\n };\n\n function SimpleFilter(sourceSound, pipe) {\n this._pipe = pipe;\n this.sourceSound = sourceSound;\n this.historyBufferSize = 22050;\n this._sourcePosition = 0;\n this.outputBufferPosition = 0;\n this._position = 0;\n }\n SimpleFilter.prototype = {\n get pipe() {\n return this._pipe;\n },\n get position() {\n return this._position;\n },\n set position(position) {\n if (position > this._position) {\n throw new RangeError(\n
\'New position may not be greater than current position\'\n );\n }\n var newOutputBufferPosition =\n this.outputBufferPosition - (this._position - position);\n if (newOutputBufferPosition < 0) {\n throw new RangeError(\n \'New position falls outside of history buffer\'\n );\n }\n this.outputBufferPosition = newOutputBufferPosition;\n this._position = position;\n },\n get sourcePosition() {\n return this._sourcePosition;\n },\n set sourcePosition(sourcePosition) {\n this.clear();\n this._sourcePosition = sourcePosition;\n },\n get inputBuffer() {\n return this._pipe.inputBuffer;\n },\n get outputBuffer() {\n return this._pipe.outputBuffer;\n },\n fillInputBuffer: function(numFrames) {\n var samples = new Float32Array(numFrames * 2);\n var numFramesExtracted = this.sourceSound.extract(\n samples,\n numFrames,\n this._sourcePosition\n );\n this._sourcePosition += numFramesExtracted;\n this.inputBuffer.putSamples(samples, 0, numFramesExtracted);\n },\n fillOutputBuffer: function(numFrames) {\n while (this.outputBuffer.frameCount < numFrames) {\n // TODO hardcoded buffer size\n var numInputFrames = 8192 * 2 - this.inputBuffer.frameCount;\n\n this.fillInputBuffer(numInputFrames);\n\n if (this.inputBuffer.frameCount < 8192 * 2) {\n break;\n // TODO flush pipe\n }\n this._pipe.process();\n }\n },\n extract: function(target, numFrames) {\n this.fillOutputBuffer(this.outputBufferPosition + numFrames);\n\n var numFramesExtracted = Math.min(\n numFrames,\n this.outputBuffer.frameCount - this.outputBufferPosition\n );\n this.outputBuffer.extract(\n
target,\n this.outputBufferPosition,\n numFramesExtracted\n );\n\n var currentFrames = this.outputBufferPosition + numFramesExtracted;\n this.outputBufferPosition = Math.min(\n this.historyBufferSize,\n currentFrames\n );\n this.outputBuffer.receive(\n Math.max(currentFrames - this.historyBufferSize, 0)\n );\n\n this._position += numFramesExtracted;\n return numFramesExtracted;\n },\n handleSampleData: function(e) {\n this.extract(e.data, 4096);\n },\n clear: function() {\n // TODO yuck\n this._pipe.clear();\n this.outputBufferPosition = 0;\n }\n };\n\n function Stretch(createBuffers, sampleRate) {\n AbstractFifoSamplePipe.call(this, createBuffers);\n this.bQuickSeek = true;\n this.bMidBufferDirty = false;\n\n this.pMidBuffer = null;\n this.overlapLength = 0;\n\n this.bAutoSeqSetting = true;\n this.bAutoSeekSetting = true;\n\n this._tempo = 1;\n this.setParameters(\n sampleRate,\n DEFAULT_SEQUENCE_MS,\n DEFAULT_SEEKWINDOW_MS,\n DEFAULT_OVERLAP_MS\n );\n }\n extend(Stretch.prototype, AbstractFifoSamplePipe.prototype);\n extend(Stretch.prototype, {\n clear: function() {\n AbstractFifoSamplePipe.prototype.clear.call(this);\n this._clearMidBuffer();\n },\n _clearMidBuffer: function() {\n if (this.bMidBufferDirty) {\n this.bMidBufferDirty = false;\n this.pMidBuffer = null;\n }\n },\n\n /**\n * Sets routine control parameters. These control are certain time constants\n * defining how the sound is stretched to the desired duration.\n *\n * \'sampleRate\' = sample rate of the sound\n
* \'sequenceMS\' = one processing sequence length in milliseconds (default = 82 ms)\n * \'seekwindowMS\' = seeking window length for scanning the best overlapping\n * position (default = 28 ms)\n * \'overlapMS\' = overlapping length (default = 12 ms)\n */\n setParameters: function(\n
aSampleRate,\n aSequenceMS,\n aSeekWindowMS,\n aOverlapMS\n ) {\n // accept only positive parameter values - if zero or negative, use old values instead\n if (aSampleRate > 0) {\n this.sampleRate = aSampleRate;\n }\n if (aOverlapMS > 0) {\n this.overlapMs = aOverlapMS;\n }\n\n if (aSequenceMS > 0) {\n this.sequenceMs = aSequenceMS;\n this.bAutoSeqSetting = false;\n } else {\n // zero or below, use automatic setting\n this.bAutoSeqSetting = true;\n }\n\n if (aSeekWindowMS > 0) {\n this.seekWindowMs = aSeekWindowMS;\n this.bAutoSeekSetting = false;\n } else {\n // zero or below, use automatic setting\n this.bAutoSeekSetting = true;\n }\n\n this.calcSeqParameters();\n\n this.calculateOverlapLength(this.overlapMs);\n\n // set tempo to recalculate \'sampleReq\'\n this.tempo = this._tempo;\n },\n\n /**\n * Sets new target tempo. Normal tempo = \'SCALE\', smaller values represent slower\n * tempo, larger faster tempo.\n */\n set tempo(newTempo) {\n var intskip;\n\n this._tempo = newTempo;\n\n // Calculate new sequence duration\n this.calcSeqParameters();\n\n // Calculate ideal skip length (according to tempo value)\n this.nominalSkip =\n this._tempo * (this.seekWindowLength - this.overlapLength);\n this.skipFract = 0;\n intskip = Math.floor(this.nominalSkip + 0.5);\n\n // Calculate how many samples are needed in the \'inputBuffer\' to\n // process another batch of samples\n this.sampleReq =\n Math.max(intskip + this.overlapLength, this.seekWindowLength) +\n this.seekLength;\n },\n get inputChunkSize() {\n return this.sampleReq;\n },\n get outputChunkSize() {\n
return (\n this.overlapLength +\n Math.max(0, this.seekWindowLength - 2 * this.overlapLength)\n );\n },\n\n /**\n * Calculates overlapInMsec period length in samples.\n */\n calculateOverlapLength: function(overlapInMsec) {\n var newOvl;\n\n // TODO assert(overlapInMsec >= 0);\n newOvl = (this.sampleRate * overlapInMsec) / 1000;\n if (newOvl < 16) newOvl = 16;\n\n // must be divisible by 8\n newOvl -= newOvl % 8;\n\n this.overlapLength = newOvl;\n\n this.pRefMidBuffer = new Float32Array(this.overlapLength * 2);\n this.pMidBuffer = new Float32Array(this.overlapLength * 2);\n },\n checkLimits: function(x, mi, ma) {\n return x < mi ? mi : x > ma ? ma : x;\n },\n\n /**\n * Calculates processing sequence length according to tempo setting\n */\n calcSeqParameters: function() {\n var seq;\n var seek;\n\n if (this.bAutoSeqSetting) {\n seq = AUTOSEQ_C + AUTOSEQ_K * this._tempo;\n
seq = this.checkLimits(seq, AUTOSEQ_AT_MAX, AUTOSEQ_AT_MIN);\n this.sequenceMs = Math.floor(seq + 0.5);\n }\n\n if (this.bAutoSeekSetting) {\n seek = AUTOSEEK_C + AUTOSEEK_K * this._tempo;\n seek = this.checkLimits(seek, AUTOSEEK_AT_MAX, AUTOSEEK_AT_MIN);\n
this.seekWindowMs = Math.floor(seek + 0.5);\n }\n\n // Update seek window lengths\n this.seekWindowLength = Math.floor(\n
(this.sampleRate * this.sequenceMs) / 1000\n );\n this.seekLength = Math.floor(\n (this.sampleRate * this.seekWindowMs) / 1000\n );\n },\n\n /**\n * Enables/disables the quick position seeking algorithm.\n */\n set quickSeek(enable) {\n
this.bQuickSeek = enable;\n },\n\n /**\n * Seeks for the optimal overlap-mixing position.\n */\n seekBestOverlapPosition: function() {\n if (this.bQuickSeek) {\n return this.seekBestOverlapPositionStereoQuick();\n } else {\n return this.seekBestOverlapPositionStereo();\n }\n },\n\n /**\n * Seeks for the optimal overlap-mixing position. The \'stereo\' version of the\n * routine\n *\n * The best position is determined as the position where the two overlapped\n * sample sequences are \'most alike\', in terms of the highest cross-correlation\n * value over the overlapping period\n */\n seekBestOverlapPositionStereo: function() {\n var bestOffs, bestCorr, corr, i;\n\n // Slopes the amplitudes of the \'midBuffer\' samples.\n this.precalcCorrReferenceStereo();\n\n bestCorr = Number.MIN_VALUE;\n bestOffs = 0;\n\n // Scans for the best correlation value by testing each possible position\n // over the permitted range.\n for (i = 0; i < this.seekLength; i++) {\n // Calculates correlation value for the mixing position corresponding\n // to \'i\'\n corr = this.calcCrossCorrStereo(2 * i, this.pRefMidBuffer);\n\n // Checks for the highest correlation value.\n if (corr > bestCorr) {\n bestCorr = corr;\n bestOffs = i;\n }\n }\n return bestOffs;\n },\n\n /**\n * Seeks for the optimal overlap-mixing position. The \'stereo\' version of the\n * routine\n *\n * The best position is determined as the position where the two overlapped\n * sample sequences are \'most alike\', in terms of the highest cross-correlation\n * value over the overlapping period\n */\n seekBestOverlapPositionStereoQuick: function() {\n var j, bestOffs, bestCorr, corr, scanCount, corrOffset, tempOffset;\n\n // Slopes the amplitude of the \'midBuffer\' samples\n this.precalcCorrReferenceStereo();\n\n bestCorr = Number.MIN_VALUE;\n bestOffs = 0;\n corrOffset = 0;\n tempOffset = 0;\n\n // Scans for the best correlation value using four-pass hierarchical search.\n
//\n // The look-up table \'scans\' has hierarchical position adjusting steps.\n // In first pass the routine searhes for the highest correlation with\n // relatively coarse steps, then rescans the neighbourhood of the highest\n // correlation with better resolution and so on.\n for (scanCount = 0; scanCount < 4; scanCount++) {\n j = 0;\n while (_SCAN_OFFSETS[scanCount][j]) {\n tempOffset = corrOffset + _SCAN_OFFSETS[scanCount][j];\n if (tempOffset >= this.seekLength) {\n break;\n }\n\n
// Calculates correlation value for the mixing position corresponding\n // to \'tempOffset\'\n corr = this.calcCrossCorrStereo(\n 2 * tempOffset,\n this.pRefMidBuffer\n );\n\n // Checks for the highest correlation value\n if (corr > bestCorr) {\n bestCorr = corr;\n bestOffs = tempOffset;\n }\n j++;\n }\n corrOffset = bestOffs;\n }\n return bestOffs;\n },\n\n /**\n * Slopes the amplitude of the \'midBuffer\' samples so that cross correlation\n * is faster to calculate\n */\n precalcCorrReferenceStereo: function() {\n var i, cnt2, temp;\n\n for (i = 0; i < this.overlapLength; i++) {\n temp = i * (this.overlapLength - i);\n cnt2 = i * 2;\n this.pRefMidBuffer[cnt2] = this.pMidBuffer[cnt2] * temp;\n this.pRefMidBuffer[cnt2 + 1] = this.pMidBuffer[cnt2 + 1] * temp;\n }\n },\n\n calcCrossCorrStereo: function(mixingPos, compare) {\n var mixing = this._inputBuffer.vector;\n mixingPos += this._inputBuffer.startIndex;\n\n var corr, i, mixingOffset;\n corr = 0;\n for (i = 2; i < 2 * this.overlapLength; i += 2) {\n mixingOffset = i + mixingPos;\n corr +=\n mixing[mixingOffset] * compare[i] +\n mixing[mixingOffset + 1] * compare[i + 1];\n }\n return corr;\n },\n\n // TODO inline\n /**\n * Overlaps samples in \'midBuffer\' with the samples in \'pInputBuffer\' at position\n * of \'ovlPos\'.\n */\n overlap: function(ovlPos) {\n this.overlapStereo(2 * ovlPos);\n },\n\n /**\n * Overlaps samples in \'midBuffer\' with the samples in \'pInput\'\n */\n overlapStereo: function(pInputPos) {\n var pInput = this._inputBuffer.vector;\n pInputPos += this._inputBuffer.startIndex;\n\n var pOutput = this._outputBuffer.vector,\n pOutputPos = this._outputBuffer.endIndex,\n i,\n cnt2,\n fTemp,\n fScale,\n fi,\n pInputOffset,\n pOutputOffset;\n\n fScale = 1 / this.overlapLength;\n for (i = 0; i < this.overlapLength; i++) {\n fTemp = (this.overlapLength - i) * fScale;\n fi = i * fScale;\n cnt2 = 2 * i;\n pInputOffset = cnt2 + pInputPos;\n pOutputOffset = cnt2 + pOutputPos;\n pOutput[pOutputOffset + 0] =\n pInput[pInputOffset + 0] * fi +\n this.pMidBuffer[cnt2 + 0] * fTemp;\n pOutput[pOutputOffset + 1] =\n pInput[pInputOffset + 1] * fi +\n this.pMidBuffer[cnt2 + 1] * fTemp;\n }\n },\n process: function() {\n var ovlSkip, offset, temp, i;\n if (this.pMidBuffer === null) {\n // if midBuffer is empty, move the first samples of the input stream\n // into it\n if (this._inputBuffer.frameCount < this.overlapLength) {\n // wait until we\'ve got overlapLength samples\n return;\n }\n this.pMidBuffer = new Float32Array(this.overlapLength * 2);\n this._inputBuffer.receiveSamples(\n this.pMidBuffer,\n this.overlapLength\n );\n }\n\n var output;\n // Process samples as long as there are enough samples in \'inputBuffer\'\n // to form a processing frame.\n while (this._inputBuffer.frameCount >= this.sampleReq) {\n // If tempo differs from the normal (\'SCALE\'), scan for the best overlapping\n // position\n offset = this.seekBestOverlapPosition();\n\n // Mix the samples in the \'inputBuffer\' at position of \'offset\' with the\n // samples in \'midBuffer\' using sliding overlapping\n // ... first partially overlap with the end of the previous sequence\n // (that\'s in \'midBuffer\')\n this._outputBuffer.ensureAdditionalCapacity(this.overlapLength);\n // FIXME unit?\n
//overlap(uint(offset));\n this.overlap(Math.floor(offset));\n this._outputBuffer.put(this.overlapLength);\n\n // ... then copy sequence samples from \'inputBuffer\' to output\n temp = this.seekWindowLength - 2 * this.overlapLength; // & 0xfffffffe;\n if (temp > 0) {\n this._outputBuffer.putBuffer(\n this._inputBuffer,\n offset + this.overlapLength,\n temp\n );\n }\n\n // Copies the end of the current sequence from \'inputBuffer\' to\n // \'midBuffer\' for being mixed with the beginning of the next\n // processing sequence and so on\n //assert(offset + seekWindowLength <= (int)inputBuffer.numSamples());\n var start =\n this.inputBuffer.startIndex +\n 2 * (offset + this.seekWindowLength - this.overlapLength);\n this.pMidBuffer.set(\n this._inputBuffer.vector.subarray(\n start,\n
start + 2 * this.overlapLength\n )\n );\n\n // Remove the processed samples from the input buffer. Update\n
// the difference between integer & nominal skip step to \'skipFract\'\n // in order to prevent the error from accumulating over time.\n
this.skipFract += this.nominalSkip; // real skip size\n ovlSkip = Math.floor(this.skipFract); // rounded to integer skip\n this.skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip\n this._inputBuffer.receive(ovlSkip);\n }\n }\n });\n\n // https://bugs.webkit.org/show_bug.cgi?id=57295\n extend(Stretch.prototype, {\n get tempo() {\n return this._tempo;\n }\n });\n\n function SoundTouch(sampleRate) {\n this.rateTransposer = new RateTransposer(false);\n this.tdStretch = new Stretch(false, sampleRate);\n\n this._inputBuffer = new FifoSampleBuffer();\n this._intermediateBuffer = new FifoSampleBuffer();\n this._outputBuffer = new FifoSampleBuffer();\n\n this._rate = 0;\n this._tempo = 0;\n\n this.virtualPitch = 1.0;\n this.virtualRate = 1.0;\n this.virtualTempo = 1.0;\n\n this._calculateEffectiveRateAndTempo();\n }\n SoundTouch.prototype = {\n clear: function() {\n this.rateTransposer.clear();\n this.tdStretch.clear();\n },\n get rate() {\n return this._rate;\n },\n set rate(rate) {\n this.virtualRate = rate;\n this._calculateEffectiveRateAndTempo();\n },\n set rateChange(rateChange) {\n this.rate = 1.0 + 0.01 * rateChange;\n },\n get tempo() {\n return this._tempo;\n },\n set tempo(tempo) {\n this.virtualTempo = tempo;\n this._calculateEffectiveRateAndTempo();\n },\n set tempoChange(tempoChange) {\n this.tempo = 1.0 + 0.01 * tempoChange;\n },\n set pitch(pitch) {\n this.virtualPitch = pitch;\n this._calculateEffectiveRateAndTempo();\n },\n set pitchOctaves(pitchOctaves) {\n this.pitch = Math.exp(0.69314718056 * pitchOctaves);\n this._calculateEffectiveRateAndTempo();\n },\n set pitchSemitones(pitchSemitones) {\n this.pitchOctaves = pitchSemitones / 12.0;\n },\n get inputBuffer() {\n return this._inputBuffer;\n },\n get outputBuffer() {\n return this._outputBuffer;\n },\n _calculateEffectiveRateAndTempo: function() {\n var previousTempo = this._tempo;\n var previousRate = this._rate;\n\n this._tempo = this.virtualTempo / this.virtualPitch;\n this._rate = this.virtualRate * this.virtualPitch;\n\n if (testFloatEqual(this._tempo, previousTempo)) {\n this.tdStretch.tempo = this._tempo;\n }\n if (testFloatEqual(this._rate, previousRate)) {\n this.rateTransposer.rate = this._rate;\n }\n\n if (this._rate > 1.0) {\n if (this._outputBuffer != this.rateTransposer.outputBuffer) {\n
this.tdStretch.inputBuffer = this._inputBuffer;\n this.tdStretch.outputBuffer = this._intermediateBuffer;\n\n this.rateTransposer.inputBuffer = this._intermediateBuffer;\n this.rateTransposer.outputBuffer = this._outputBuffer;\n }\n } else {\n if (this._outputBuffer != this.tdStretch.outputBuffer) {\n this.rateTransposer.inputBuffer = this._inputBuffer;\n this.rateTransposer.outputBuffer = this._intermediateBuffer;\n\n this.tdStretch.inputBuffer = this._intermediateBuffer;\n this.tdStretch.outputBuffer = this._outputBuffer;\n }\n }\n },\n process: function() {\n if (this._rate > 1.0) {\n this.tdStretch.process();\n this.rateTransposer.process();\n } else {\n this.rateTransposer.process();\n this.tdStretch.process();\n }\n }\n };\n\n function WebAudioBufferSource(buffer) {\n this.buffer = buffer;\n }\n WebAudioBufferSource.prototype = {\n extract: function(target, numFrames, position) {\n var l = this.buffer.getChannelData(0),\n r = this.buffer.getChannelData(1);\n for (var i = 0; i < numFrames; i++) {\n target[i * 2] = l[i + position];\n target[i * 2 + 1] = r[i + position];\n }\n return Math.min(numFrames, l.length - position);\n }\n };\n\n function getWebAudioNode(context, filter) {\n var BUFFER_SIZE = 4096;\n var node = context.createScriptProcessor(BUFFER_SIZE, 2, 2),\n samples = new Float32Array(BUFFER_SIZE * 2);\n node.onaudioprocess = function(e) {\n var l = e.outputBuffer.getChannelData(0),\n r = e.outputBuffer.getChannelData(1);\n var framesExtracted = filter.extract(samples, BUFFER_SIZE);\n if (framesExtracted === 0) {\n node.disconnect(); // Pause.\n }\n for (var i = 0; i < framesExtracted; i++) {\n l[i] = samples[i * 2];\n r[i] = samples[i * 2 + 1];\n }\n };\n return node;\n }\n\n window.soundtouch = {\n RateTransposer: RateTransposer,\n Stretch: Stretch,\n SimpleFilter: SimpleFilter,\n SoundTouch: SoundTouch,\n WebAudioBufferSource: WebAudioBufferSource,\n getWebAudioNode: getWebAudioNode\n };\n})(this);\n\nconsole.log("Loading stretcher.js");\n// http://wavesurfer-js.org/example/stretcher/app.js\n\'use strict\';\n\n// Create an instance\n// var wavesurfer_prod = {};\nconsole.log(\'Pausing to allow DOM loading to complete\');\nsetTimeout(function() {\n// Init & load\n// window.addEventListener(\'DOMContentLoaded\', function() {\n /*\n ** Removed because a wavesurfer object has already been\n ** instantiated by Prodigy\n\n Init wavesurfer\n wavesurfer = WaveSurfer.create({\n container: \'#waveform\',\n waveColor: \'violet\',\n progressColor: \'purple\',\n loaderColor: \'purple\',\n cursorColor: \'navy\'\n });\n wavesurfer.load(\'../../example/media/demo.wav\');\n */\n\n timestretcher = window.wavesurfer;\n // Time stretcher\n /*\n ** If this wavesurfer.on(\'ready\') is enabled the script won\'t work\n\n window.wavesurfer.on(\'ready\', function() {\n \n */\n var st = new window.soundtouch.SoundTouch(\n timestretcher.backend.ac.sampleRate\n );\n\n var buffer = timestretcher.backend.buffer;\n var channels = buffer.numberOfChannels;\n var l = buffer.getChannelData(0);\n var r = channels > 1 ? buffer.getChannelData(1) : l;\n var length = buffer.length;\n var seekingPos = null;\n var seekingDiff = 0;\n\n var source = {\n extract: function(target, numFrames, position) {\n if (seekingPos != null) {\n seekingDiff = seekingPos - position;\n seekingPos = null;\n }\n\n position += seekingDiff;\n\n for (var i = 0; i < numFrames; i++) {\n target[i * 2] = l[i + position];\n target[i * 2 + 1] = r[i + position];\n }\n\n return Math.min(numFrames, length - position);\n }\n };\n\n var soundtouchNode;\n\n timestretcher.on(\'play\', function() {\n // console.log(\'Within the on.play function...\')\n seekingPos = ~~(timestretcher.backend.getPlayedPercents() * length);\n st.tempo = timestretcher.getPlaybackRate();\n\n if (st.tempo === 1) {\n timestretcher.backend.disconnectFilters();\n } else {\n if (!soundtouchNode) {\n var filter = new window.soundtouch.SimpleFilter(source, st);\n soundtouchNode = window.soundtouch.getWebAudioNode(\n timestretcher.backend.ac,\n filter\n );\n }\n timestretcher.backend.setFilter(soundtouchNode);\n }\n });\n\n timestretcher.on(\'pause\', function() {\n // console.log(\'Within the on.pause function...\')\n soundtouchNode && soundtouchNode.disconnect();\n });\n\n timestretcher.on(\'seek\', function() {\n // console.log(\'Within the on.seek function...\')\n seekingPos = ~~(timestretcher.backend.getPlayedPercents() * length);\n });\n // }); // Matches the window.wavesurfer.on(\'ready\')\n// }); // Matches the window.addEventListener\n}, 1000);', 'audio_autoplay': False, 'audio_bar_gap': 0, 'audio_bar_height': 2, 'audio_bar_radius': 1, 'audio_bar_width': 1, 'audio_loop': False, 'audio_max_zoom': 5000, 'audio_rate': 1.0, 'show_audio_cursor': True, 'show_audio_cursor_time': True, 'show_audio_minimap': True, 'show_audio_timeline': True, 'force_stream_order': True, 'labels': ['FEM', 'MAL', 'CHI(1)', 'CHI(2p)'], 'custom_theme': {'labels': {'FEM': '#84E9F3', 'MAL': '#4E6BF3', 'CHI(1)': '#F2B11A', 'CHI(2p)': '#852215'}}, 'dataset': 'round2', 'recipe_name': 'post-sad-multiclass'}, 'dataset': 'round2', 'db': True, 'exclude': None, 'get_session_id': None, 'on_exit': None, 'on_load': None, 'progress': , 'self': , 'stream': , 'update': None, 'validate_answer': None, 'view_id': 'blocks'}
13:17:07: VALIDATE: Creating validator for view ID 'blocks'
13:17:07: VALIDATE: Validating Prodigy and recipe config
13:17:07: DB: Initializing database SQLite
13:17:07: DB: Connecting to database SQLite
13:17:07: DB: Creating dataset '2020-09-26_13-17-07'
{'created': datetime.datetime(2020, 9, 25, 21, 5, 9)}
13:17:07: CONTROLLER: Initialising from recipe
{'batch_size': 10, 'dataset': 'round2', 'db': None, 'exclude': 'task', 'filters': [{'name': 'RelatedSessionsFilter', 'cache_size': 10}], 'max_sessions': 10, 'overlap': True, 'self': , 'stream': , 'validator': , 'view_id': 'blocks'}
13:17:07: CONTROLLER: Validating the first batch for session: None
13:17:07: PREPROCESS: Fetching media if necessary: ['audio']
{'input_keys': ['audio'], 'skip': False, 'stream': .get_stream at 0x000001F6569353C0>}
13:17:07: Instantiating DB connection
13:17:07: Connecting to DB eNY-2step
13:17:07: DB: Loading dataset 'eNY-2step' (6 examples)
13:17:07: CORS: initialized with wildcard "*" CORS origins
✨ Starting the web server at http://localhost:8080 ...
Open the app in your browser and start annotating!
INFO: Started server process [30472]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://localhost:8080 (Press CTRL+C to quit)