kopia lustrzana https://github.com/jameshball/osci-render
Add support for recording oscilloscope visualiser
rodzic
925f2a7b80
commit
f30ac1823e
|
@ -2,467 +2,514 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
font-family: Sans-Serif;
|
||||
font-size: 14px;
|
||||
-webkit-user-select: none; /* Safari */
|
||||
-ms-user-select: none; /* IE 10 and IE 11 */
|
||||
user-select: none; /* Standard syntax */
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
canvas {
|
||||
width: min(100vw, 100vh);
|
||||
height: min(100vw, 100vh);
|
||||
position: absolute;
|
||||
top: calc(calc(100vh - min(100vw, 100vh)) / 2);
|
||||
left: calc(calc(100vw - min(100vw, 100vh)) / 2);
|
||||
display: block;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
#overlay {
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
position: absolute;
|
||||
display: none;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: default;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
table {
|
||||
border-spacing:0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
#buttonRow {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
display: none;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
#buttonRow button {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background-color: transparent;
|
||||
background-repeat: no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
outline: none;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
#buttonRow button:hover {
|
||||
filter: brightness(70%);
|
||||
}
|
||||
|
||||
#buttonRow button:active {
|
||||
filter: brightness(50%);
|
||||
}
|
||||
|
||||
#fullscreen {
|
||||
background: url(fullscreen.svg) no-repeat;
|
||||
}
|
||||
|
||||
#popout {
|
||||
background: url(open_in_new.svg) no-repeat;
|
||||
}
|
||||
|
||||
#settings {
|
||||
background: url(cog.svg) no-repeat;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
font-family: Sans-Serif;
|
||||
font-size: 14px;
|
||||
-webkit-user-select: none; /* Safari */
|
||||
-ms-user-select: none; /* IE 10 and IE 11 */
|
||||
user-select: none; /* Standard syntax */
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
canvas {
|
||||
width: min(100vw, 100vh);
|
||||
height: min(100vw, 100vh);
|
||||
position: absolute;
|
||||
top: calc(calc(100vh - min(100vw, 100vh)) / 2);
|
||||
left: calc(calc(100vw - min(100vw, 100vh)) / 2);
|
||||
display: block;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
#overlay {
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
position: absolute;
|
||||
display: none;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: default;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
table {
|
||||
border-spacing:0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
#buttonRow {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
display: none;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
#buttonRow button {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background-color: transparent;
|
||||
background-repeat: no-repeat;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
outline: none;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
#buttonRow button:hover {
|
||||
filter: brightness(70%);
|
||||
}
|
||||
|
||||
#buttonRow button:active {
|
||||
filter: brightness(50%);
|
||||
}
|
||||
|
||||
#download {
|
||||
background: url(download.svg) no-repeat;
|
||||
}
|
||||
|
||||
#fullscreen {
|
||||
background: url(fullscreen.svg) no-repeat;
|
||||
}
|
||||
|
||||
#popout {
|
||||
background: url(open_in_new.svg) no-repeat;
|
||||
}
|
||||
|
||||
#settings {
|
||||
background: url(cog.svg) no-repeat;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body bgcolor="black" text="white" autocomplete="off" style="margin: 0px;">
|
||||
|
||||
<div id="buttonRow">
|
||||
<button id="fullscreen"/>
|
||||
<button id="popout"/>
|
||||
<button id="settings"/>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var controls=
|
||||
{
|
||||
swapXY : false,
|
||||
sweepOn : false,
|
||||
sweepMsDiv : 1,
|
||||
sweepTriggerValue : 0,
|
||||
mainGain : 0.0,
|
||||
brightness : 0.0,
|
||||
intensity: 0.02,
|
||||
saturation: 1.0,
|
||||
focus: 0.01,
|
||||
hue : 125,
|
||||
invertXY : false,
|
||||
grid : true,
|
||||
noise : true,
|
||||
persistence : 0,
|
||||
disableFilter : false,
|
||||
}
|
||||
|
||||
let timeout;
|
||||
document.addEventListener("mousemove", function() {
|
||||
const buttons = document.getElementById('buttonRow');
|
||||
buttons.style.display = "block";
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
<div id="buttonRow">
|
||||
<button onClick="toggleRecording()" id="download"/>
|
||||
<button id="fullscreen"/>
|
||||
<button id="popout"/>
|
||||
<button id="settings"/>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var controls=
|
||||
{
|
||||
swapXY : false,
|
||||
sweepOn : false,
|
||||
sweepMsDiv : 1,
|
||||
sweepTriggerValue : 0,
|
||||
mainGain : 0.0,
|
||||
brightness : 0.0,
|
||||
intensity: 0.02,
|
||||
saturation: 1.0,
|
||||
focus: 0.01,
|
||||
hue : 125,
|
||||
invertXY : false,
|
||||
grid : true,
|
||||
noise : true,
|
||||
persistence : 0,
|
||||
disableFilter : false,
|
||||
}
|
||||
timeout = setTimeout(function() {
|
||||
buttons.style.display = "none";
|
||||
}, 1000)
|
||||
});
|
||||
|
||||
let timeout;
|
||||
document.addEventListener("mousemove", function() {
|
||||
const buttons = document.getElementById('buttonRow');
|
||||
buttons.style.display = "block";
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
timeout = setTimeout(function() {
|
||||
buttons.style.display = "none";
|
||||
}, 1000)
|
||||
});
|
||||
|
||||
let isDebug = true;
|
||||
let paused = false;
|
||||
let openInAnotherWindow = false;
|
||||
let externalSampleRate = 96000;
|
||||
let externalBufferSize = 1920;
|
||||
let recording = false;
|
||||
let mediaRecorder = undefined;
|
||||
let downloadCallback = undefined;
|
||||
|
||||
const toggleRecording = () => {
|
||||
recording = !recording;
|
||||
if (recording) {
|
||||
const canvas = document.getElementById("crtCanvas");
|
||||
const data = [];
|
||||
const stream = canvas.captureStream(60);
|
||||
mediaRecorder = new MediaRecorder(stream);
|
||||
mediaRecorder.ondataavailable = (e) => data.push(e.data);
|
||||
mediaRecorder.onstop = (e) => {
|
||||
const div = document.getElementById("buttonRow");
|
||||
var a = document.createElement("a");
|
||||
const video = new Blob(data, { type: "video/webm;codecs=h264" });
|
||||
var reader = new FileReader();
|
||||
reader.readAsDataURL(video);
|
||||
reader.onloadend = function() {
|
||||
var dataUrl = reader.result;
|
||||
var base64 = dataUrl.split(',')[1];
|
||||
downloadCallback(base64);
|
||||
}
|
||||
};
|
||||
mediaRecorder.start();
|
||||
} else {
|
||||
mediaRecorder.stop();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
let isDebug = true;
|
||||
let paused = false;
|
||||
let openInAnotherWindow = false;
|
||||
let externalSampleRate = 96000;
|
||||
let externalBufferSize = 1920;
|
||||
|
||||
</script>
|
||||
|
||||
<script type="module">
|
||||
import * as Juce from "./index.js";
|
||||
|
||||
const fullscreen = document.getElementById('fullscreen');
|
||||
const toggleFullscreen = Juce.getNativeFunction("toggleFullscreen");
|
||||
fullscreen.onclick = toggleFullscreen;
|
||||
|
||||
const popout = document.getElementById('popout');
|
||||
const popoutFn = Juce.getNativeFunction("popout");
|
||||
popout.onclick = popoutFn;
|
||||
|
||||
const settings = document.getElementById('settings');
|
||||
const settingsFn = Juce.getNativeFunction("settings");
|
||||
settings.onclick = settingsFn;
|
||||
|
||||
const mainScreen = document.getElementById('mainScreen');
|
||||
const overlay = document.getElementById('overlay');
|
||||
const pauseFn = Juce.getNativeFunction("pause");
|
||||
mainScreen.onclick = function() {
|
||||
if (!openInAnotherWindow) {
|
||||
pauseFn();
|
||||
paused = !paused;
|
||||
if (paused) {
|
||||
<script type="module">
|
||||
import * as Juce from "./index.js";
|
||||
|
||||
const fullscreen = document.getElementById('fullscreen');
|
||||
const toggleFullscreen = Juce.getNativeFunction("toggleFullscreen");
|
||||
fullscreen.onclick = toggleFullscreen;
|
||||
|
||||
const popout = document.getElementById('popout');
|
||||
const popoutFn = Juce.getNativeFunction("popout");
|
||||
popout.onclick = popoutFn;
|
||||
|
||||
const settings = document.getElementById('settings');
|
||||
const settingsFn = Juce.getNativeFunction("settings");
|
||||
settings.onclick = settingsFn;
|
||||
|
||||
const mainScreen = document.getElementById('mainScreen');
|
||||
const overlay = document.getElementById('overlay');
|
||||
const pauseFn = Juce.getNativeFunction("pause");
|
||||
mainScreen.onclick = function() {
|
||||
if (!openInAnotherWindow) {
|
||||
pauseFn();
|
||||
paused = !paused;
|
||||
if (paused) {
|
||||
overlay.style.display = "flex";
|
||||
} else {
|
||||
overlay.style.display = "none";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const isDebugFn = Juce.getNativeFunction("isDebug");
|
||||
|
||||
isDebugFn().then(debug => {
|
||||
isDebug = debug;
|
||||
if (!debug) {
|
||||
document.addEventListener('contextmenu', event => event.preventDefault());
|
||||
}
|
||||
});
|
||||
|
||||
const isOverlayFn = Juce.getNativeFunction("isOverlay");
|
||||
isOverlayFn().then(overlay => {
|
||||
if (overlay) {
|
||||
popout.remove();
|
||||
fullscreen.remove();
|
||||
}
|
||||
});
|
||||
|
||||
Juce.getNativeFunction("isVisualiserOnly")().then(visualiserOnly => {
|
||||
if (visualiserOnly) {
|
||||
popout.remove();
|
||||
fullscreen.remove();
|
||||
settings.remove();
|
||||
}
|
||||
});
|
||||
|
||||
window.__JUCE__.backend.addEventListener("childPresent", hasChild => {
|
||||
openInAnotherWindow = hasChild;
|
||||
if (hasChild) {
|
||||
overlay.style.display = "flex";
|
||||
overlay.innerText = "Open in separate window";
|
||||
} else {
|
||||
overlay.style.display = "none";
|
||||
overlay.innerText = "Paused";
|
||||
}
|
||||
});
|
||||
|
||||
window.__JUCE__.backend.addEventListener("toggleRecording", hasChild => {
|
||||
toggleRecording();
|
||||
});
|
||||
|
||||
document.addEventListener("dblclick", function() {
|
||||
toggleFullscreen();
|
||||
});
|
||||
|
||||
downloadCallback = (base64) => {
|
||||
Juce.getNativeFunction("downloadVideo")(base64);
|
||||
};
|
||||
</script>
|
||||
|
||||
<div id="mainScreen">
|
||||
<div id="overlay">Paused</div>
|
||||
<canvas id="crtCanvas" width="800" height="800"></canvas>
|
||||
</div>
|
||||
|
||||
<script id="vertex" type="x-shader">
|
||||
attribute vec2 vertexPosition;
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(vertexPosition, 0.0, 1.0);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
const isDebugFn = Juce.getNativeFunction("isDebug");
|
||||
|
||||
isDebugFn().then(debug => {
|
||||
isDebug = debug;
|
||||
if (!debug) {
|
||||
document.addEventListener('contextmenu', event => event.preventDefault());
|
||||
<script id="fragment" type="x-shader">
|
||||
precision highp float;
|
||||
uniform vec4 colour;
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = colour;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
const isOverlayFn = Juce.getNativeFunction("isOverlay");
|
||||
isOverlayFn().then(overlay => {
|
||||
if (overlay) {
|
||||
popout.remove();
|
||||
fullscreen.remove();
|
||||
<!-- The Gaussian line-drawing code, the next two shaders, is adapted
|
||||
from woscope by e1ml : https://github.com/m1el/woscope -->
|
||||
|
||||
<script id="gaussianVertex" type="x-shader">
|
||||
#define EPS 1E-6
|
||||
uniform float uInvert;
|
||||
uniform float uSize;
|
||||
uniform float uNEdges;
|
||||
uniform float uFadeAmount;
|
||||
uniform float uIntensity;
|
||||
uniform float uGain;
|
||||
attribute vec3 aStart, aEnd;
|
||||
attribute float aIdx;
|
||||
varying vec4 uvl;
|
||||
varying vec2 vTexCoord;
|
||||
varying float vLen;
|
||||
varying float vSize;
|
||||
void main () {
|
||||
float tang;
|
||||
vec2 current;
|
||||
// All points in quad contain the same data:
|
||||
// segment start point and segment end point.
|
||||
// We determine point position using its index.
|
||||
float idx = mod(aIdx,4.0);
|
||||
|
||||
vec2 aStartPos = aStart.xy;
|
||||
vec2 aEndPos = aEnd.xy;
|
||||
float aStartBrightness = aStart.z;
|
||||
float aEndBrightness = aEnd.z;
|
||||
|
||||
// `dir` vector is storing the normalized difference
|
||||
// between end and start
|
||||
vec2 dir = (aEndPos-aStartPos)*uGain;
|
||||
uvl.z = length(dir);
|
||||
|
||||
if (uvl.z > EPS) {
|
||||
dir = dir / uvl.z;
|
||||
} else {
|
||||
// If the segment is too short, just draw a square
|
||||
dir = vec2(1.0, 0.0);
|
||||
}
|
||||
|
||||
vSize = uSize;
|
||||
float intensity = 0.015 * uIntensity / uSize;
|
||||
vec2 norm = vec2(-dir.y, dir.x);
|
||||
|
||||
if (idx >= 2.0) {
|
||||
current = aEndPos*uGain;
|
||||
tang = 1.0;
|
||||
uvl.x = -vSize;
|
||||
uvl.w = aEndBrightness;
|
||||
} else {
|
||||
current = aStartPos*uGain;
|
||||
tang = -1.0;
|
||||
uvl.x = uvl.z + vSize;
|
||||
uvl.w = aStartBrightness;
|
||||
}
|
||||
// `side` corresponds to shift to the "right" or "left"
|
||||
float side = (mod(idx, 2.0)-0.5)*2.0;
|
||||
uvl.y = side * vSize;
|
||||
|
||||
uvl.w *= intensity * mix(1.0-uFadeAmount, 1.0, floor(aIdx / 4.0 + 0.5)/uNEdges);
|
||||
|
||||
vec4 pos = vec4((current+(tang*dir+norm*side)*vSize)*uInvert,0.0,1.0);
|
||||
gl_Position = pos;
|
||||
vTexCoord = 0.5*pos.xy+0.5;
|
||||
//float seed = floor(aIdx/4.0);
|
||||
//seed = mod(sin(seed*seed), 7.0);
|
||||
//if (mod(seed/2.0, 1.0)<0.5) gl_Position = vec4(10.0);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="gaussianFragment" type="x-shader">
|
||||
#define EPS 1E-6
|
||||
#define TAU 6.283185307179586
|
||||
#define TAUR 2.5066282746310002
|
||||
#define SQRT2 1.4142135623730951
|
||||
precision highp float;
|
||||
uniform float uSize;
|
||||
uniform float uIntensity;
|
||||
uniform sampler2D uScreen;
|
||||
varying float vSize;
|
||||
varying vec4 uvl;
|
||||
varying vec2 vTexCoord;
|
||||
|
||||
// A standard gaussian function, used for weighting samples
|
||||
float gaussian(float x, float sigma)
|
||||
{
|
||||
return exp(-(x * x) / (2.0 * sigma * sigma)) / (TAUR * sigma);
|
||||
}
|
||||
|
||||
// This approximates the error function, needed for the gaussian integral
|
||||
float erf(float x)
|
||||
{
|
||||
float s = sign(x), a = abs(x);
|
||||
x = 1.0 + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a;
|
||||
x *= x;
|
||||
return s - s / (x * x);
|
||||
}
|
||||
|
||||
void main (void)
|
||||
{
|
||||
float len = uvl.z;
|
||||
vec2 xy = uvl.xy;
|
||||
float brightness;
|
||||
|
||||
float sigma = vSize/5.0;
|
||||
if (len < EPS)
|
||||
{
|
||||
// If the beam segment is too short, just calculate intensity at the position.
|
||||
brightness = gaussian(length(xy), sigma);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, use analytical integral for accumulated intensity.
|
||||
brightness = erf(xy.x/SQRT2/sigma) - erf((xy.x-len)/SQRT2/sigma);
|
||||
brightness *= exp(-xy.y*xy.y/(2.0*sigma*sigma))/2.0/len;
|
||||
}
|
||||
|
||||
brightness *= uvl.w;
|
||||
gl_FragColor = 2.0 * texture2D(uScreen, vTexCoord) * brightness;
|
||||
gl_FragColor.a = 1.0;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="texturedVertex" type="x-shader">
|
||||
precision highp float;
|
||||
attribute vec2 aPos;
|
||||
varying vec2 vTexCoord;
|
||||
void main (void)
|
||||
{
|
||||
gl_Position = vec4(aPos, 0.0, 1.0);
|
||||
vTexCoord = (0.5*aPos+0.5);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
Juce.getNativeFunction("isVisualiserOnly")().then(visualiserOnly => {
|
||||
if (visualiserOnly) {
|
||||
popout.remove();
|
||||
fullscreen.remove();
|
||||
settings.remove();
|
||||
<script id="texturedVertexWithResize" type="x-shader">
|
||||
precision highp float;
|
||||
attribute vec2 aPos;
|
||||
varying vec2 vTexCoord;
|
||||
uniform float uResizeForCanvas;
|
||||
void main (void)
|
||||
{
|
||||
gl_Position = vec4(aPos, 0.0, 1.0);
|
||||
vTexCoord = (0.5*aPos+0.5)*uResizeForCanvas;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
window.__JUCE__.backend.addEventListener("childPresent", hasChild => {
|
||||
openInAnotherWindow = hasChild;
|
||||
if (hasChild) {
|
||||
overlay.style.display = "flex";
|
||||
overlay.innerText = "Open in separate window";
|
||||
} else {
|
||||
overlay.style.display = "none";
|
||||
overlay.innerText = "Paused";
|
||||
<script id="texturedFragment" type="x-shader">
|
||||
precision highp float;
|
||||
uniform sampler2D uTexture0;
|
||||
varying vec2 vTexCoord;
|
||||
void main (void)
|
||||
{
|
||||
gl_FragColor = texture2D(uTexture0, vTexCoord);
|
||||
gl_FragColor.a= 1.0;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
document.addEventListener("dblclick", function() {
|
||||
toggleFullscreen();
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="mainScreen">
|
||||
<div id="overlay">Paused</div>
|
||||
<canvas id="crtCanvas" width="800" height="800"></canvas>
|
||||
</div>
|
||||
|
||||
<script id="vertex" type="x-shader">
|
||||
attribute vec2 vertexPosition;
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(vertexPosition, 0.0, 1.0);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="fragment" type="x-shader">
|
||||
precision highp float;
|
||||
uniform vec4 colour;
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = colour;
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- The Gaussian line-drawing code, the next two shaders, is adapted
|
||||
from woscope by e1ml : https://github.com/m1el/woscope -->
|
||||
|
||||
<script id="gaussianVertex" type="x-shader">
|
||||
#define EPS 1E-6
|
||||
uniform float uInvert;
|
||||
uniform float uSize;
|
||||
uniform float uNEdges;
|
||||
uniform float uFadeAmount;
|
||||
uniform float uIntensity;
|
||||
uniform float uGain;
|
||||
attribute vec3 aStart, aEnd;
|
||||
attribute float aIdx;
|
||||
varying vec4 uvl;
|
||||
varying vec2 vTexCoord;
|
||||
varying float vLen;
|
||||
varying float vSize;
|
||||
void main () {
|
||||
float tang;
|
||||
vec2 current;
|
||||
// All points in quad contain the same data:
|
||||
// segment start point and segment end point.
|
||||
// We determine point position using its index.
|
||||
float idx = mod(aIdx,4.0);
|
||||
|
||||
vec2 aStartPos = aStart.xy;
|
||||
vec2 aEndPos = aEnd.xy;
|
||||
float aStartBrightness = aStart.z;
|
||||
float aEndBrightness = aEnd.z;
|
||||
|
||||
// `dir` vector is storing the normalized difference
|
||||
// between end and start
|
||||
vec2 dir = (aEndPos-aStartPos)*uGain;
|
||||
uvl.z = length(dir);
|
||||
|
||||
if (uvl.z > EPS) {
|
||||
dir = dir / uvl.z;
|
||||
} else {
|
||||
// If the segment is too short, just draw a square
|
||||
dir = vec2(1.0, 0.0);
|
||||
<script id="blurFragment" type="x-shader">
|
||||
precision highp float;
|
||||
uniform sampler2D uTexture0;
|
||||
uniform vec2 uOffset;
|
||||
varying vec2 vTexCoord;
|
||||
void main (void)
|
||||
{
|
||||
vec4 sum = vec4(0.0);
|
||||
sum += texture2D(uTexture0, vTexCoord - uOffset*8.0) * 0.000078;
|
||||
sum += texture2D(uTexture0, vTexCoord - uOffset*7.0) * 0.000489;
|
||||
sum += texture2D(uTexture0, vTexCoord - uOffset*6.0) * 0.002403;
|
||||
sum += texture2D(uTexture0, vTexCoord - uOffset*5.0) * 0.009245;
|
||||
sum += texture2D(uTexture0, vTexCoord - uOffset*4.0) * 0.027835;
|
||||
sum += texture2D(uTexture0, vTexCoord - uOffset*3.0) * 0.065592;
|
||||
sum += texture2D(uTexture0, vTexCoord - uOffset*2.0) * 0.12098;
|
||||
sum += texture2D(uTexture0, vTexCoord - uOffset*1.0) * 0.17467;
|
||||
sum += texture2D(uTexture0, vTexCoord + uOffset*0.0) * 0.19742;
|
||||
sum += texture2D(uTexture0, vTexCoord + uOffset*1.0) * 0.17467;
|
||||
sum += texture2D(uTexture0, vTexCoord + uOffset*2.0) * 0.12098;
|
||||
sum += texture2D(uTexture0, vTexCoord + uOffset*3.0) * 0.065592;
|
||||
sum += texture2D(uTexture0, vTexCoord + uOffset*4.0) * 0.027835;
|
||||
sum += texture2D(uTexture0, vTexCoord + uOffset*5.0) * 0.009245;
|
||||
sum += texture2D(uTexture0, vTexCoord + uOffset*6.0) * 0.002403;
|
||||
sum += texture2D(uTexture0, vTexCoord + uOffset*7.0) * 0.000489;
|
||||
sum += texture2D(uTexture0, vTexCoord + uOffset*8.0) * 0.000078;
|
||||
gl_FragColor = sum;
|
||||
}
|
||||
|
||||
vSize = uSize;
|
||||
float intensity = 0.015 * uIntensity / uSize;
|
||||
vec2 norm = vec2(-dir.y, dir.x);
|
||||
|
||||
if (idx >= 2.0) {
|
||||
current = aEndPos*uGain;
|
||||
tang = 1.0;
|
||||
uvl.x = -vSize;
|
||||
uvl.w = aEndBrightness;
|
||||
} else {
|
||||
current = aStartPos*uGain;
|
||||
tang = -1.0;
|
||||
uvl.x = uvl.z + vSize;
|
||||
uvl.w = aStartBrightness;
|
||||
</script>
|
||||
|
||||
<script id="outputVertex" type="x-shader">
|
||||
precision highp float;
|
||||
attribute vec2 aPos;
|
||||
varying vec2 vTexCoord;
|
||||
varying vec2 vTexCoordCanvas;
|
||||
uniform float uResizeForCanvas;
|
||||
void main (void)
|
||||
{
|
||||
gl_Position = vec4(aPos, 0.0, 1.0);
|
||||
vTexCoord = (0.5*aPos+0.5);
|
||||
vTexCoordCanvas = vTexCoord*uResizeForCanvas;
|
||||
}
|
||||
// `side` corresponds to shift to the "right" or "left"
|
||||
float side = (mod(idx, 2.0)-0.5)*2.0;
|
||||
uvl.y = side * vSize;
|
||||
|
||||
uvl.w *= intensity * mix(1.0-uFadeAmount, 1.0, floor(aIdx / 4.0 + 0.5)/uNEdges);
|
||||
|
||||
vec4 pos = vec4((current+(tang*dir+norm*side)*vSize)*uInvert,0.0,1.0);
|
||||
gl_Position = pos;
|
||||
vTexCoord = 0.5*pos.xy+0.5;
|
||||
//float seed = floor(aIdx/4.0);
|
||||
//seed = mod(sin(seed*seed), 7.0);
|
||||
//if (mod(seed/2.0, 1.0)<0.5) gl_Position = vec4(10.0);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="gaussianFragment" type="x-shader">
|
||||
#define EPS 1E-6
|
||||
#define TAU 6.283185307179586
|
||||
#define TAUR 2.5066282746310002
|
||||
#define SQRT2 1.4142135623730951
|
||||
precision highp float;
|
||||
uniform float uSize;
|
||||
uniform float uIntensity;
|
||||
uniform sampler2D uScreen;
|
||||
varying float vSize;
|
||||
varying vec4 uvl;
|
||||
varying vec2 vTexCoord;
|
||||
|
||||
// A standard gaussian function, used for weighting samples
|
||||
float gaussian(float x, float sigma)
|
||||
{
|
||||
return exp(-(x * x) / (2.0 * sigma * sigma)) / (TAUR * sigma);
|
||||
}
|
||||
|
||||
// This approximates the error function, needed for the gaussian integral
|
||||
float erf(float x)
|
||||
{
|
||||
float s = sign(x), a = abs(x);
|
||||
x = 1.0 + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a;
|
||||
x *= x;
|
||||
return s - s / (x * x);
|
||||
}
|
||||
|
||||
void main (void)
|
||||
{
|
||||
float len = uvl.z;
|
||||
vec2 xy = uvl.xy;
|
||||
float brightness;
|
||||
|
||||
float sigma = vSize/5.0;
|
||||
if (len < EPS)
|
||||
{
|
||||
// If the beam segment is too short, just calculate intensity at the position.
|
||||
brightness = gaussian(length(xy), sigma);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, use analytical integral for accumulated intensity.
|
||||
brightness = erf(xy.x/SQRT2/sigma) - erf((xy.x-len)/SQRT2/sigma);
|
||||
brightness *= exp(-xy.y*xy.y/(2.0*sigma*sigma))/2.0/len;
|
||||
}
|
||||
|
||||
brightness *= uvl.w;
|
||||
gl_FragColor = 2.0 * texture2D(uScreen, vTexCoord) * brightness;
|
||||
gl_FragColor.a = 1.0;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="texturedVertex" type="x-shader">
|
||||
precision highp float;
|
||||
attribute vec2 aPos;
|
||||
varying vec2 vTexCoord;
|
||||
void main (void)
|
||||
{
|
||||
gl_Position = vec4(aPos, 0.0, 1.0);
|
||||
vTexCoord = (0.5*aPos+0.5);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="texturedVertexWithResize" type="x-shader">
|
||||
precision highp float;
|
||||
attribute vec2 aPos;
|
||||
varying vec2 vTexCoord;
|
||||
uniform float uResizeForCanvas;
|
||||
void main (void)
|
||||
{
|
||||
gl_Position = vec4(aPos, 0.0, 1.0);
|
||||
vTexCoord = (0.5*aPos+0.5)*uResizeForCanvas;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="texturedFragment" type="x-shader">
|
||||
precision highp float;
|
||||
uniform sampler2D uTexture0;
|
||||
varying vec2 vTexCoord;
|
||||
void main (void)
|
||||
{
|
||||
gl_FragColor = texture2D(uTexture0, vTexCoord);
|
||||
gl_FragColor.a= 1.0;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="blurFragment" type="x-shader">
|
||||
precision highp float;
|
||||
uniform sampler2D uTexture0;
|
||||
uniform vec2 uOffset;
|
||||
varying vec2 vTexCoord;
|
||||
void main (void)
|
||||
{
|
||||
vec4 sum = vec4(0.0);
|
||||
sum += texture2D(uTexture0, vTexCoord - uOffset*8.0) * 0.000078;
|
||||
sum += texture2D(uTexture0, vTexCoord - uOffset*7.0) * 0.000489;
|
||||
sum += texture2D(uTexture0, vTexCoord - uOffset*6.0) * 0.002403;
|
||||
sum += texture2D(uTexture0, vTexCoord - uOffset*5.0) * 0.009245;
|
||||
sum += texture2D(uTexture0, vTexCoord - uOffset*4.0) * 0.027835;
|
||||
sum += texture2D(uTexture0, vTexCoord - uOffset*3.0) * 0.065592;
|
||||
sum += texture2D(uTexture0, vTexCoord - uOffset*2.0) * 0.12098;
|
||||
sum += texture2D(uTexture0, vTexCoord - uOffset*1.0) * 0.17467;
|
||||
sum += texture2D(uTexture0, vTexCoord + uOffset*0.0) * 0.19742;
|
||||
sum += texture2D(uTexture0, vTexCoord + uOffset*1.0) * 0.17467;
|
||||
sum += texture2D(uTexture0, vTexCoord + uOffset*2.0) * 0.12098;
|
||||
sum += texture2D(uTexture0, vTexCoord + uOffset*3.0) * 0.065592;
|
||||
sum += texture2D(uTexture0, vTexCoord + uOffset*4.0) * 0.027835;
|
||||
sum += texture2D(uTexture0, vTexCoord + uOffset*5.0) * 0.009245;
|
||||
sum += texture2D(uTexture0, vTexCoord + uOffset*6.0) * 0.002403;
|
||||
sum += texture2D(uTexture0, vTexCoord + uOffset*7.0) * 0.000489;
|
||||
sum += texture2D(uTexture0, vTexCoord + uOffset*8.0) * 0.000078;
|
||||
gl_FragColor = sum;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="outputVertex" type="x-shader">
|
||||
precision highp float;
|
||||
attribute vec2 aPos;
|
||||
varying vec2 vTexCoord;
|
||||
varying vec2 vTexCoordCanvas;
|
||||
uniform float uResizeForCanvas;
|
||||
void main (void)
|
||||
{
|
||||
gl_Position = vec4(aPos, 0.0, 1.0);
|
||||
vTexCoord = (0.5*aPos+0.5);
|
||||
vTexCoordCanvas = vTexCoord*uResizeForCanvas;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="outputFragment" type="x-shader">
|
||||
precision highp float;
|
||||
uniform sampler2D uTexture0; //line
|
||||
uniform sampler2D uTexture1; //tight glow
|
||||
uniform sampler2D uTexture2; //big glow
|
||||
uniform sampler2D uTexture3; //screen
|
||||
uniform float uExposure;
|
||||
uniform float uSaturation;
|
||||
uniform vec3 uColour;
|
||||
varying vec2 vTexCoord;
|
||||
varying vec2 vTexCoordCanvas;
|
||||
</script>
|
||||
|
||||
vec3 desaturate(vec3 color, float factor) {
|
||||
vec3 lum = vec3(0.299, 0.587, 0.114);
|
||||
vec3 gray = vec3(dot(lum, color));
|
||||
return vec3(mix(color, gray, factor));
|
||||
}
|
||||
<script id="outputFragment" type="x-shader">
|
||||
precision highp float;
|
||||
uniform sampler2D uTexture0; //line
|
||||
uniform sampler2D uTexture1; //tight glow
|
||||
uniform sampler2D uTexture2; //big glow
|
||||
uniform sampler2D uTexture3; //screen
|
||||
uniform float uExposure;
|
||||
uniform float uSaturation;
|
||||
uniform vec3 uColour;
|
||||
varying vec2 vTexCoord;
|
||||
varying vec2 vTexCoordCanvas;
|
||||
|
||||
vec3 desaturate(vec3 color, float factor) {
|
||||
vec3 lum = vec3(0.299, 0.587, 0.114);
|
||||
vec3 gray = vec3(dot(lum, color));
|
||||
return vec3(mix(color, gray, factor));
|
||||
}
|
||||
|
||||
/* Gradient noise from Jorge Jimenez's presentation: */
|
||||
/* http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare */
|
||||
float gradientNoise(in vec2 uv) {
|
||||
return fract(52.9829189 * fract(dot(uv, vec2(0.06711056, 0.00583715))));
|
||||
}
|
||||
|
||||
void main (void) {
|
||||
vec4 line = texture2D(uTexture0, vTexCoordCanvas);
|
||||
// r components have grid; g components do not.
|
||||
vec4 screen = texture2D(uTexture3, vTexCoord);
|
||||
vec4 tightGlow = texture2D(uTexture1, vTexCoord);
|
||||
vec4 scatter = texture2D(uTexture2, vTexCoord)+0.35;
|
||||
float light = line.r + 1.5*screen.g*screen.g*tightGlow.r;
|
||||
light += 0.4*scatter.g * (2.0+1.0*screen.g + 0.5*screen.r);
|
||||
float tlight = 1.0-pow(2.0, -uExposure*light);
|
||||
float tlight2 = tlight*tlight*tlight;
|
||||
gl_FragColor.rgb = mix(uColour, vec3(1.0), 0.3+tlight2*tlight2*0.5)*tlight;
|
||||
gl_FragColor.rgb = desaturate(gl_FragColor.rgb, 1.0 - uSaturation);
|
||||
gl_FragColor.rgb += (1.0 / 255.0) * gradientNoise(gl_FragCoord.xy) - (0.5 / 255.0);
|
||||
gl_FragColor.a = 1.0;
|
||||
}
|
||||
</script>
|
||||
|
||||
void main (void)
|
||||
{
|
||||
vec4 line = texture2D(uTexture0, vTexCoordCanvas);
|
||||
// r components have grid; g components do not.
|
||||
vec4 screen = texture2D(uTexture3, vTexCoord);
|
||||
vec4 tightGlow = texture2D(uTexture1, vTexCoord);
|
||||
vec4 scatter = texture2D(uTexture2, vTexCoord)+0.35;
|
||||
float light = line.r + 1.5*screen.g*screen.g*tightGlow.r;
|
||||
light += 0.4*scatter.g * (2.0+1.0*screen.g + 0.5*screen.r);
|
||||
float tlight = 1.0-pow(2.0, -uExposure*light);
|
||||
float tlight2 = tlight*tlight*tlight;
|
||||
gl_FragColor.rgb = mix(uColour, vec3(1.0), 0.3+tlight2*tlight2*0.5)*tlight;
|
||||
gl_FragColor.rgb = desaturate(gl_FragColor.rgb, 1.0 - uSaturation);
|
||||
gl_FragColor.a = 1.0;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script src="oscilloscope.js" type="module"></script>
|
||||
<script src="oscilloscope.js" type="module"></script>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M0,12a12,12 0 1,0 24,0a12,12 0 1,0 -24,0Z" /></svg>
|
Po Szerokość: | Wysokość: | Rozmiar: 120 B |
|
@ -39,6 +39,12 @@ SosciPluginEditor::SosciPluginEditor(SosciAudioProcessor& p)
|
|||
openVisualiserSettings();
|
||||
};
|
||||
|
||||
addAndMakeVisible(record);
|
||||
record.setPulseAnimation(true);
|
||||
record.onClick = [this] {
|
||||
visualiser.toggleRecording();
|
||||
};
|
||||
|
||||
addAndMakeVisible(visualiser);
|
||||
|
||||
visualiser.openSettings = [this] {
|
||||
|
@ -48,6 +54,10 @@ SosciPluginEditor::SosciPluginEditor(SosciAudioProcessor& p)
|
|||
visualiser.closeSettings = [this] {
|
||||
visualiserSettingsWindow.setVisible(false);
|
||||
};
|
||||
|
||||
visualiser.recordingHalted = [this] {
|
||||
record.setToggleState(false, juce::NotificationType::dontSendNotification);
|
||||
};
|
||||
|
||||
visualiserSettingsWindow.setResizable(false, false);
|
||||
#if JUCE_WINDOWS
|
||||
|
@ -80,6 +90,7 @@ void SosciPluginEditor::resized() {
|
|||
|
||||
auto topBar = area.removeFromTop(25);
|
||||
settings.setBounds(topBar.removeFromRight(25));
|
||||
record.setBounds(topBar.removeFromRight(25));
|
||||
menuBar.setBounds(topBar);
|
||||
|
||||
visualiser.setBounds(area);
|
||||
|
|
|
@ -39,6 +39,7 @@ public:
|
|||
|
||||
juce::TooltipWindow tooltipWindow{nullptr, 0};
|
||||
|
||||
SvgButton record{"Record", BinaryData::record_2_svg, juce::Colours::red, juce::Colours::red.withAlpha(0.01f)};
|
||||
SvgButton settings{"Settings", BinaryData::cog_svg, juce::Colours::white, juce::Colours::white};
|
||||
|
||||
bool usingNativeMenuBar = false;
|
||||
|
|
|
@ -24,6 +24,8 @@ class SvgButton : public juce::DrawableButton, public juce::AudioProcessorParame
|
|||
downImageOn = juce::Drawable::createFromSVG(*doc);
|
||||
changeSvgColour(doc.get(), colourOn.withBrightness(0.3f));
|
||||
disabledImageOn = juce::Drawable::createFromSVG(*doc);
|
||||
|
||||
path = normalImage->getOutlineAsPath();
|
||||
|
||||
getLookAndFeel().setColour(juce::DrawableButton::backgroundOnColourId, juce::Colours::transparentWhite);
|
||||
|
||||
|
@ -37,6 +39,8 @@ class SvgButton : public juce::DrawableButton, public juce::AudioProcessorParame
|
|||
setToggleState(toggle->getBoolValue(), juce::NotificationType::dontSendNotification);
|
||||
setTooltip(toggle->getDescription());
|
||||
}
|
||||
|
||||
updater.addAnimator(pulse);
|
||||
}
|
||||
|
||||
SvgButton(juce::String name, juce::String svg, juce::Colour colour) : SvgButton(name, svg, colour, colour) {}
|
||||
|
@ -69,6 +73,30 @@ class SvgButton : public juce::DrawableButton, public juce::AudioProcessorParame
|
|||
juce::DrawableButton::mouseExit(e);
|
||||
setMouseCursor(juce::MouseCursor::NormalCursor);
|
||||
}
|
||||
|
||||
void setPulseAnimation(bool pulseUsed) {
|
||||
this->pulseUsed = pulseUsed;
|
||||
}
|
||||
|
||||
void paintOverChildren(juce::Graphics& g) override {
|
||||
if (pulseUsed && getToggleState()) {
|
||||
g.setColour(juce::Colours::black.withAlpha(colourFade / 1.5f));
|
||||
g.fillPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
void buttonStateChanged() override {
|
||||
juce::DrawableButton::buttonStateChanged();
|
||||
if (pulseUsed && getToggleState() != prevToggleState) {
|
||||
if (getToggleState()) {
|
||||
pulse.start();
|
||||
} else {
|
||||
pulse.complete();
|
||||
colourFade = 1.0;
|
||||
}
|
||||
prevToggleState = getToggleState();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<juce::Drawable> normalImage;
|
||||
|
@ -82,6 +110,21 @@ private:
|
|||
std::unique_ptr<juce::Drawable> disabledImageOn;
|
||||
|
||||
BooleanParameter* toggle;
|
||||
|
||||
juce::VBlankAnimatorUpdater updater{this};
|
||||
float colourFade = 0.0;
|
||||
bool pulseUsed = false;
|
||||
bool prevToggleState = false;
|
||||
juce::Path path;
|
||||
juce::Animator pulse = juce::ValueAnimatorBuilder {}
|
||||
.withEasing([] (float t) { return std::sin(3.14159 * t) / 2 + 0.5; })
|
||||
.withDurationMs(500)
|
||||
.runningInfinitely()
|
||||
.withValueChangedCallback([this] (auto value) {
|
||||
colourFade = value;
|
||||
repaint();
|
||||
})
|
||||
.build();
|
||||
|
||||
void changeSvgColour(juce::XmlElement* xml, juce::Colour colour) {
|
||||
forEachXmlChildElement(*xml, xmlnode) {
|
||||
|
|
|
@ -270,6 +270,9 @@ void VisualiserComponent::paintXY(juce::Graphics& g, juce::Rectangle<float> area
|
|||
}
|
||||
|
||||
void VisualiserComponent::initialiseBrowser() {
|
||||
if (recordingHalted != nullptr) {
|
||||
recordingHalted();
|
||||
}
|
||||
oldBrowser = std::move(browser);
|
||||
if (oldBrowser != nullptr) {
|
||||
removeChildComponent(oldBrowser.get());
|
||||
|
@ -323,6 +326,21 @@ void VisualiserComponent::initialiseBrowser() {
|
|||
.withNativeFunction("isVisualiserOnly", [this](auto& var, auto complete) {
|
||||
complete(visualiserOnly);
|
||||
})
|
||||
.withNativeFunction("downloadVideo", [this](const juce::Array<juce::var>& args, auto complete) {
|
||||
juce::String base64 = args[0].toString();
|
||||
chooser = std::make_unique<juce::FileChooser>("Save video", juce::File::getSpecialLocation(juce::File::SpecialLocationType::userDesktopDirectory).getChildFile("osci-render.webm"), "*.webm");
|
||||
chooser->launchAsync(juce::FileBrowserComponent::saveMode,
|
||||
[base64](const juce::FileChooser& chooser) {
|
||||
juce::File result = chooser.getResult();
|
||||
if (result.getFullPathName().isNotEmpty()) {
|
||||
juce::FileOutputStream stream(result);
|
||||
stream.setPosition(0);
|
||||
stream.truncate();
|
||||
juce::Base64::convertFromBase64(stream, base64);
|
||||
stream.flush();
|
||||
}
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
addAndMakeVisible(*browser);
|
||||
|
@ -366,6 +384,13 @@ void VisualiserComponent::handleAsyncUpdate() {
|
|||
}
|
||||
}
|
||||
|
||||
void VisualiserComponent::toggleRecording() {
|
||||
if (oldVisualiser) {
|
||||
return;
|
||||
}
|
||||
browser->emitEventIfBrowserIsVisible("toggleRecording", juce::var());
|
||||
}
|
||||
|
||||
void VisualiserComponent::resized() {
|
||||
if (!oldVisualiser) {
|
||||
browser->setBounds(getLocalBounds());
|
||||
|
@ -390,10 +415,14 @@ void VisualiserComponent::childChanged() {
|
|||
}
|
||||
|
||||
void VisualiserComponent::popoutWindow() {
|
||||
if (recordingHalted != nullptr) {
|
||||
recordingHalted();
|
||||
}
|
||||
auto visualiser = new VisualiserComponent(sampleRateManager, consumerManager, settings, this, oldVisualiser);
|
||||
visualiser->settings.setLookAndFeel(&getLookAndFeel());
|
||||
visualiser->openSettings = openSettings;
|
||||
visualiser->closeSettings = closeSettings;
|
||||
visualiser->recordingHalted = recordingHalted;
|
||||
child = visualiser;
|
||||
childChanged();
|
||||
popOutButton.setVisible(false);
|
||||
|
|
|
@ -42,12 +42,15 @@ public:
|
|||
void setFullScreen(bool fullScreen);
|
||||
void setVisualiserType(bool oldVisualiser);
|
||||
void handleAsyncUpdate() override;
|
||||
void toggleRecording();
|
||||
|
||||
VisualiserComponent* parent = nullptr;
|
||||
VisualiserComponent* child = nullptr;
|
||||
std::unique_ptr<VisualiserWindow> popout = nullptr;
|
||||
|
||||
std::atomic<bool> active = true;
|
||||
|
||||
std::function<void()> recordingHalted;
|
||||
|
||||
private:
|
||||
// 60fps
|
||||
|
@ -120,6 +123,8 @@ private:
|
|||
// keeping this around for memory management reasons
|
||||
std::unique_ptr<juce::WebBrowserComponent> oldBrowser = nullptr;
|
||||
|
||||
std::unique_ptr<juce::FileChooser> chooser;
|
||||
|
||||
void initialiseBrowser();
|
||||
void resetBuffer();
|
||||
void popoutWindow();
|
||||
|
|
|
@ -658,6 +658,7 @@
|
|||
<MODULEPATH id="juce_gui_extra" path="../../../JUCE/modules"/>
|
||||
<MODULEPATH id="juce_opengl" path="../../../JUCE/modules"/>
|
||||
<MODULEPATH id="juce_dsp" path="../../JUCE/modules"/>
|
||||
<MODULEPATH id="juce_animation" path="../JUCE/modules"/>
|
||||
</MODULEPATHS>
|
||||
</LINUX_MAKE>
|
||||
<VS2022 targetFolder="Builds/VisualStudio2022" smallIcon="pSc1mq" bigIcon="pSc1mq">
|
||||
|
@ -681,6 +682,7 @@
|
|||
<MODULEPATH id="juce_gui_extra" path="../../../JUCE/modules"/>
|
||||
<MODULEPATH id="juce_opengl" path="../../../JUCE/modules"/>
|
||||
<MODULEPATH id="juce_dsp" path="../../JUCE/modules"/>
|
||||
<MODULEPATH id="juce_animation" path="../JUCE/modules"/>
|
||||
</MODULEPATHS>
|
||||
</VS2022>
|
||||
<XCODE_MAC targetFolder="Builds/MacOSX" extraLinkerFlags="-Wl,-weak_reference_mismatches,weak"
|
||||
|
@ -705,10 +707,12 @@
|
|||
<MODULEPATH id="juce_gui_extra" path="../../../JUCE/modules"/>
|
||||
<MODULEPATH id="juce_opengl" path="../../../JUCE/modules"/>
|
||||
<MODULEPATH id="juce_dsp" path="../../JUCE/modules"/>
|
||||
<MODULEPATH id="juce_animation" path="../JUCE/modules"/>
|
||||
</MODULEPATHS>
|
||||
</XCODE_MAC>
|
||||
</EXPORTFORMATS>
|
||||
<MODULES>
|
||||
<MODULE id="juce_animation" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
<MODULE id="juce_audio_basics" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
<MODULE id="juce_audio_devices" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
<MODULE id="juce_audio_formats" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
<FILE id="PFc2q2" name="random.svg" compile="0" resource="1" file="Resources/svg/random.svg"/>
|
||||
<FILE id="CE6di2" name="range.svg" compile="0" resource="1" file="Resources/svg/range.svg"/>
|
||||
<FILE id="n79IAy" name="record.svg" compile="0" resource="1" file="Resources/svg/record.svg"/>
|
||||
<FILE id="TWt5MY" name="record_2.svg" compile="0" resource="1" file="Resources/svg/record_2.svg"/>
|
||||
<FILE id="OaqZb1" name="right_arrow.svg" compile="0" resource="1" file="Resources/svg/right_arrow.svg"/>
|
||||
<FILE id="rXjNlx" name="threshold.svg" compile="0" resource="1" file="Resources/svg/threshold.svg"/>
|
||||
<FILE id="rFYmV8" name="timer.svg" compile="0" resource="1" file="Resources/svg/timer.svg"/>
|
||||
|
@ -139,6 +140,7 @@
|
|||
<MODULEPATH id="juce_gui_extra" path="../../../JUCE/modules"/>
|
||||
<MODULEPATH id="juce_opengl" path="../../../JUCE/modules"/>
|
||||
<MODULEPATH id="juce_dsp" path="../../JUCE/modules"/>
|
||||
<MODULEPATH id="juce_animation" path="../../../JUCE/modules"/>
|
||||
</MODULEPATHS>
|
||||
</LINUX_MAKE>
|
||||
<VS2022 targetFolder="Builds/sosci/VisualStudio2022" smallIcon="pSc1mq"
|
||||
|
@ -163,6 +165,7 @@
|
|||
<MODULEPATH id="juce_gui_extra" path="../../../JUCE/modules"/>
|
||||
<MODULEPATH id="juce_opengl" path="../../../JUCE/modules"/>
|
||||
<MODULEPATH id="juce_dsp" path="../../JUCE/modules"/>
|
||||
<MODULEPATH id="juce_animation" path="../../../JUCE/modules"/>
|
||||
</MODULEPATHS>
|
||||
</VS2022>
|
||||
<XCODE_MAC targetFolder="Builds/sosci/MacOSX" extraLinkerFlags="-Wl,-weak_reference_mismatches,weak"
|
||||
|
@ -187,10 +190,12 @@
|
|||
<MODULEPATH id="juce_gui_extra" path="../../../JUCE/modules"/>
|
||||
<MODULEPATH id="juce_opengl" path="../../../JUCE/modules"/>
|
||||
<MODULEPATH id="juce_dsp" path="../../JUCE/modules"/>
|
||||
<MODULEPATH id="juce_animation" path="../../../JUCE/modules"/>
|
||||
</MODULEPATHS>
|
||||
</XCODE_MAC>
|
||||
</EXPORTFORMATS>
|
||||
<MODULES>
|
||||
<MODULE id="juce_animation" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
<MODULE id="juce_audio_basics" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
<MODULE id="juce_audio_devices" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
<MODULE id="juce_audio_formats" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
|
|
Ładowanie…
Reference in New Issue