kopia lustrzana https://github.com/backface/turtlestitch
SciSnap2 extension update (FFT), thanks, Eckart!
rodzic
e9a0e6f402
commit
ce63da9cef
|
@ -5,12 +5,16 @@
|
||||||
* **New Features:**
|
* **New Features:**
|
||||||
* variadic commutative infix reporters
|
* variadic commutative infix reporters
|
||||||
* **Notable Changes:**
|
* **Notable Changes:**
|
||||||
* removed now redundant variadic reporters from the variadic reporters library
|
* SciSnap2 extension update (FFT), thanks, Eckart!
|
||||||
|
* removed now redundant variadic reporters from the variadic reporters library
|
||||||
* **Notable Fixes:**
|
* **Notable Fixes:**
|
||||||
* **Documentation Updates:**
|
* **Documentation Updates:**
|
||||||
* **Translation Updates:**
|
* **Translation Updates:**
|
||||||
* German
|
* German
|
||||||
|
|
||||||
|
### 2022-03-03
|
||||||
|
* SciSnap2 extension update (FFT), thanks, Eckart!
|
||||||
|
|
||||||
### 2022-03-02
|
### 2022-03-02
|
||||||
* gui: never close a dev-warning
|
* gui: never close a dev-warning
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -3253,28 +3253,27 @@ SnapExtensions.primitives.set(
|
||||||
|
|
||||||
SnapExtensions.primitives.set(
|
SnapExtensions.primitives.set(
|
||||||
'SciS_drawGraph(amatrix,vlist,cAttributes,vAttributes,lAttributes,oldCostume)',
|
'SciS_drawGraph(amatrix,vlist,cAttributes,vAttributes,lAttributes,oldCostume)',
|
||||||
function (amatrix, vlist, cAttributes, vAttributes, lAttributes,oldCostume) {
|
function (amatrix, vlist, cAttributes, vAttributes, lAttributes, oldCostume) {
|
||||||
var costume = new Costume(), ctx = costume.contents.getContext('2d'), c, row, anz,
|
var costume = new Costume(), ctx = costume.contents.getContext('2d'), c, row, anz,
|
||||||
w = Number(cAttributes.at(1)), h = Number(cAttributes.at(2)), v1, v2, x1, y1, x2, y2, n = amatrix.length(), label, textheight,
|
w = Number(cAttributes.at(1)), h = Number(cAttributes.at(2)), v1, v2, x1, y1, x2, y2, n = amatrix.length(), label, textheight,
|
||||||
weight, directed, marked, showWeights, xp, yp, alpha, l, dx, dy, dl, size, minsize = Number(vAttributes.at(2)), growing = vAttributes.at(3);
|
weight, directed, marked, showWeights, xp, yp, alpha, l, dx, dy, dl, size, minsize = Number(vAttributes.at(2)), growing = vAttributes.at(3);
|
||||||
//create new costume or take old one
|
//create new costume or take old one
|
||||||
//create new costume or take old one
|
//create new costume or take old one
|
||||||
if(oldCostume==="null"){
|
if (oldCostume === "null") {
|
||||||
costume.contents.width = w;
|
costume.contents.width = w;
|
||||||
costume.contents.height = h;
|
costume.contents.height = h;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.fillStyle = new Color(cAttributes.at(3), cAttributes.at(4), cAttributes.at(5)).toString();
|
ctx.fillStyle = new Color(cAttributes.at(3), cAttributes.at(4), cAttributes.at(5)).toString();
|
||||||
ctx.strokeStyle = new Color(0, 0, 0).toString();
|
ctx.strokeStyle = new Color(0, 0, 0).toString();
|
||||||
ctx.fillRect(0, 0, w, h);
|
ctx.fillRect(0, 0, w, h);
|
||||||
ctx.strokeRect(0, 0, w, h);
|
ctx.strokeRect(0, 0, w, h);
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
costume.rotationCenter = new Point(w / 2, h / 2);
|
costume.rotationCenter = new Point(w / 2, h / 2);
|
||||||
}
|
} else {
|
||||||
else{
|
costume = oldCostume;
|
||||||
costume = oldCostume;
|
ctx = costume.contents.getContext('2d');
|
||||||
ctx = costume.contents.getContext('2d');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//count edges per vertex an set size per vertex
|
//count edges per vertex an set size per vertex
|
||||||
|
@ -4317,6 +4316,150 @@ SnapExtensions.primitives.set(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
SnapExtensions.primitives.set(
|
||||||
|
'SciS_FFTops(data,freq,choice)',
|
||||||
|
function (data, freq, choice) {
|
||||||
|
function newComplex(re, im) {
|
||||||
|
return [re, im];
|
||||||
|
}
|
||||||
|
function addComplex(c1, c2) {
|
||||||
|
return newComplex(c1[0] + c2[0], c1[1] + c2[1]);
|
||||||
|
}
|
||||||
|
function subComplex(c1, c2) {
|
||||||
|
return newComplex(c1[0] - c2[0], c1[1] - c2[1]);
|
||||||
|
}
|
||||||
|
function mulComplex(c1, c2) {
|
||||||
|
return newComplex(c1[0] * c2[0] - c1[1] * c2[1], c1[0] * c2[1] + c1[1] * c2[0]);
|
||||||
|
}
|
||||||
|
function absComplex(c) {
|
||||||
|
return Math.sqrt(c[0] * c[0] + c[1] * c[1]);
|
||||||
|
}
|
||||||
|
function complexToPolar(c) {
|
||||||
|
return newComplex(absComplex(c), Math.atan(c[1] / c[0]));
|
||||||
|
}
|
||||||
|
function polarToComplex(c) {
|
||||||
|
return newComplex(c[0] * Math.cos(c[1]), c[0] * Math.sin(c[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
function FFT(d) {
|
||||||
|
var n = d.length, nDIV2 = n / 2, even = [], odd = [], result = [], evenPart, oddPart;
|
||||||
|
if (n <= 1)
|
||||||
|
return d;
|
||||||
|
for (var i = 0; i < n; i++) {
|
||||||
|
result.push(0);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < nDIV2; i++) {
|
||||||
|
even.push(d[2 * i]);
|
||||||
|
odd.push(d[2 * i + 1]);
|
||||||
|
}
|
||||||
|
evenPart = FFT(even);
|
||||||
|
oddPart = FFT(odd);
|
||||||
|
f = -2 * Math.PI / n;
|
||||||
|
for (var k = 0; k < nDIV2; k++) {
|
||||||
|
g = mulComplex(newComplex(Math.cos(f * k), Math.sin(f * k)), oddPart[k]);
|
||||||
|
result[k] = addComplex(evenPart[k], g);
|
||||||
|
result[k + nDIV2] = subComplex(evenPart[k], g);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rData = [], cData = [], N = 0, result, maxLength = data.length(), n;
|
||||||
|
|
||||||
|
if (choice === "frequency_spectrum") {
|
||||||
|
rData = data.asArray();
|
||||||
|
//complete data up to length 2^N
|
||||||
|
while (Math.pow(2, N) < rData.length) {
|
||||||
|
N++;
|
||||||
|
}
|
||||||
|
while (rData.length < Math.pow(2, N)) {
|
||||||
|
rData.push(0);
|
||||||
|
}
|
||||||
|
//convert to complex numbers
|
||||||
|
for (var i = 0; i < rData.length; i++) {
|
||||||
|
cData.push([Number(rData[i]), Number(0)]);
|
||||||
|
}
|
||||||
|
//calculate FFT
|
||||||
|
result = FFT(cData);
|
||||||
|
//shorten to length of original data
|
||||||
|
while (result.length > maxLength) {
|
||||||
|
result.pop();
|
||||||
|
}
|
||||||
|
//calculate normalized FFT data
|
||||||
|
n = cData.length;
|
||||||
|
for (var i = 0; i < result.length; i++) {
|
||||||
|
result[i] = [1.0 * i / n * freq, 2 * absComplex(result[i]) / maxLength];
|
||||||
|
}
|
||||||
|
result[0][1] = result[0][1] / 2;
|
||||||
|
//convert to List
|
||||||
|
for (var i = 0; i < result.length; i++) {
|
||||||
|
result[i] = new List(result[i]);
|
||||||
|
}
|
||||||
|
return new List(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (choice === 'complex_FFTdata') {
|
||||||
|
rData = data.asArray();
|
||||||
|
//complete data up to length 2^N
|
||||||
|
while (Math.pow(2, N) < rData.length) {
|
||||||
|
N++;
|
||||||
|
}
|
||||||
|
while (rData.length < Math.pow(2, N)) {
|
||||||
|
rData.push(0);
|
||||||
|
}
|
||||||
|
//convert to complex numbers
|
||||||
|
for (var i = 0; i < rData.length; i++) {
|
||||||
|
cData.push([Number(rData[i]), Number(0)]);
|
||||||
|
}
|
||||||
|
//calculate FFT
|
||||||
|
result = FFT(cData);
|
||||||
|
//use SciSnap! format for complex numbers
|
||||||
|
for (var i = 0; i < result.length; i++) {
|
||||||
|
result[i] = ["complexNumberCartesianStyle", result[i][0], result[i][1]];
|
||||||
|
}
|
||||||
|
//shorten to length of original data
|
||||||
|
while (result.length > maxLength) {
|
||||||
|
result.pop();
|
||||||
|
}
|
||||||
|
//convert to List
|
||||||
|
for (var i = 0; i < result.length; i++) {
|
||||||
|
result[i] = new List(result[i]);
|
||||||
|
}
|
||||||
|
return new List(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (choice === 'iFFT_of_FFTdata') {
|
||||||
|
//convert data to conjugate complex array
|
||||||
|
for (var i = 1; i <= data.length(); i++) {
|
||||||
|
rData.push([data.at(i).at(1), -data.at(i).at(2)]);
|
||||||
|
}
|
||||||
|
//complete data up to length 2^N
|
||||||
|
while (Math.pow(2, N) < rData.length) {
|
||||||
|
N++;
|
||||||
|
}
|
||||||
|
while (rData.length < Math.pow(2, N)) {
|
||||||
|
rData.push([0, 0]);
|
||||||
|
}
|
||||||
|
//calculate FFT
|
||||||
|
result = FFT(rData);
|
||||||
|
n = result.length;
|
||||||
|
for (var i = 0; i < n; i++) {
|
||||||
|
result[i] = result[i][0] / n;
|
||||||
|
}
|
||||||
|
//shorten to length of original data
|
||||||
|
while (result.length > maxLength) {
|
||||||
|
result.pop();
|
||||||
|
}
|
||||||
|
//convert to List
|
||||||
|
return new List(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "ERROR: incorrect selection!";
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -4338,4 +4481,15 @@ SnapExtensions.primitives.set(
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3413,6 +3413,48 @@ Process.prototype.decodeSound = function (sound, callback) {
|
||||||
this.pushContext();
|
this.pushContext();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Process.prototype.decodeSpectrum = function (sound, callback) {
|
||||||
|
// private - callback is optional and invoked with sound as argument
|
||||||
|
var base64, binaryString, len, bytes, i, arrayBuffer, audioCtx, analyzer;
|
||||||
|
|
||||||
|
if (sound.audioBuffer) {
|
||||||
|
return (callback || nop)(sound);
|
||||||
|
}
|
||||||
|
if (!sound.isDecoding) {
|
||||||
|
base64 = sound.audio.src.split(',')[1];
|
||||||
|
binaryString = window.atob(base64);
|
||||||
|
len = binaryString.length;
|
||||||
|
bytes = new Uint8Array(len);
|
||||||
|
for (i = 0; i < len; i += 1) {
|
||||||
|
bytes[i] = binaryString.charCodeAt(i);
|
||||||
|
}
|
||||||
|
arrayBuffer = bytes.buffer;
|
||||||
|
audioCtx = Note.prototype.getAudioContext();
|
||||||
|
sound.isDecoding = true;
|
||||||
|
|
||||||
|
analyser = audioCtx.createAnalyser(); // +++
|
||||||
|
analyser.fftSize = 256;
|
||||||
|
var bufferLength = analyser.frequencyBinCount;
|
||||||
|
var dataArray = new Uint8Array(bufferLength);
|
||||||
|
analyser.getByteFrequencyData(dataArray);
|
||||||
|
|
||||||
|
|
||||||
|
audioCtx.decodeAudioData(
|
||||||
|
arrayBuffer,
|
||||||
|
buffer => {
|
||||||
|
sound.audioBuffer = buffer;
|
||||||
|
sound.isDecoding = false;
|
||||||
|
},
|
||||||
|
err => {
|
||||||
|
sound.isDecoding = false;
|
||||||
|
this.handleError(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.pushContext('doYield');
|
||||||
|
this.pushContext();
|
||||||
|
};
|
||||||
|
|
||||||
Process.prototype.encodeSound = function (samples, rate) {
|
Process.prototype.encodeSound = function (samples, rate) {
|
||||||
// private
|
// private
|
||||||
var rcvr = this.blockReceiver(),
|
var rcvr = this.blockReceiver(),
|
||||||
|
|
Ładowanie…
Reference in New Issue