Upload visual.ts
Browse files
visual.ts
ADDED
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* @license
|
3 |
+
* SPDX-License-Identifier: Apache-2.0
|
4 |
+
*/
|
5 |
+
/* tslint:disable */
|
6 |
+
|
7 |
+
import {LitElement, css, html} from 'lit';
|
8 |
+
import {customElement, property} from 'lit/decorators.js';
|
9 |
+
import {Analyser} from './analyser';
|
10 |
+
|
11 |
+
@customElement('gdm-live-audio-visuals')
|
12 |
+
export class GdmLiveAudioVisuals extends LitElement {
|
13 |
+
private inputAnalyser: Analyser;
|
14 |
+
private outputAnalyser: Analyser;
|
15 |
+
|
16 |
+
private _outputNode: AudioNode;
|
17 |
+
|
18 |
+
@property()
|
19 |
+
set outputNode(node: AudioNode) {
|
20 |
+
this._outputNode = node;
|
21 |
+
this.outputAnalyser = new Analyser(this._outputNode);
|
22 |
+
}
|
23 |
+
|
24 |
+
get outputNode() {
|
25 |
+
return this._outputNode;
|
26 |
+
}
|
27 |
+
|
28 |
+
private _inputNode: AudioNode;
|
29 |
+
|
30 |
+
@property()
|
31 |
+
set inputNode(node: AudioNode) {
|
32 |
+
this._inputNode = node;
|
33 |
+
this.inputAnalyser = new Analyser(this._inputNode);
|
34 |
+
}
|
35 |
+
|
36 |
+
get inputNode() {
|
37 |
+
return this._inputNode;
|
38 |
+
}
|
39 |
+
|
40 |
+
private canvas: HTMLCanvasElement;
|
41 |
+
private canvasCtx: CanvasRenderingContext2D;
|
42 |
+
|
43 |
+
static styles = css`
|
44 |
+
canvas {
|
45 |
+
width: 400px;
|
46 |
+
aspect-ratio: 1 / 1;
|
47 |
+
}
|
48 |
+
`;
|
49 |
+
|
50 |
+
connectedCallback() {
|
51 |
+
super.connectedCallback();
|
52 |
+
this.visualize();
|
53 |
+
}
|
54 |
+
|
55 |
+
private visualize() {
|
56 |
+
if (this.canvas && this.outputAnalyser) {
|
57 |
+
const canvas = this.canvas;
|
58 |
+
const canvasCtx = this.canvasCtx;
|
59 |
+
|
60 |
+
const WIDTH = canvas.width;
|
61 |
+
const HEIGHT = canvas.height;
|
62 |
+
|
63 |
+
canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);
|
64 |
+
canvasCtx.fillStyle = '#1f2937';
|
65 |
+
canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);
|
66 |
+
|
67 |
+
const barWidth = WIDTH / this.outputAnalyser.data.length;
|
68 |
+
let x = 0;
|
69 |
+
|
70 |
+
const inputGradient = canvasCtx.createLinearGradient(0, 0, 0, HEIGHT);
|
71 |
+
inputGradient.addColorStop(1, '#D16BA5');
|
72 |
+
inputGradient.addColorStop(0.5, '#E78686');
|
73 |
+
inputGradient.addColorStop(0, '#FB5F5F');
|
74 |
+
canvasCtx.fillStyle = inputGradient;
|
75 |
+
|
76 |
+
this.inputAnalyser.update();
|
77 |
+
|
78 |
+
for (let i = 0; i < this.inputAnalyser.data.length; i++) {
|
79 |
+
const barHeight = this.inputAnalyser.data[i] * (HEIGHT / 255);
|
80 |
+
canvasCtx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight);
|
81 |
+
x += barWidth;
|
82 |
+
}
|
83 |
+
|
84 |
+
canvasCtx.globalCompositeOperation = 'lighter';
|
85 |
+
|
86 |
+
const outputGradient = canvasCtx.createLinearGradient(0, 0, 0, HEIGHT);
|
87 |
+
outputGradient.addColorStop(1, '#3b82f6');
|
88 |
+
outputGradient.addColorStop(0.5, '#10b981');
|
89 |
+
outputGradient.addColorStop(0, '#ef4444');
|
90 |
+
canvasCtx.fillStyle = outputGradient;
|
91 |
+
|
92 |
+
x = 0;
|
93 |
+
this.outputAnalyser.update();
|
94 |
+
|
95 |
+
for (let i = 0; i < this.outputAnalyser.data.length; i++) {
|
96 |
+
const barHeight = this.outputAnalyser.data[i] * (HEIGHT / 255);
|
97 |
+
canvasCtx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight);
|
98 |
+
x += barWidth;
|
99 |
+
}
|
100 |
+
}
|
101 |
+
requestAnimationFrame(() => this.visualize());
|
102 |
+
}
|
103 |
+
|
104 |
+
private firstUpdated() {
|
105 |
+
this.canvas = this.shadowRoot!.querySelector('canvas');
|
106 |
+
this.canvas.width = 400;
|
107 |
+
this.canvas.height = 400;
|
108 |
+
this.canvasCtx = this.canvas.getContext('2d');
|
109 |
+
}
|
110 |
+
|
111 |
+
private render() {
|
112 |
+
return html`<canvas></canvas>`;
|
113 |
+
}
|
114 |
+
}
|
115 |
+
|
116 |
+
declare global {
|
117 |
+
interface HTMLElementTagNameMap {
|
118 |
+
'gdm-live-audio-visuals': GdmLiveAudioVisuals;
|
119 |
+
}
|
120 |
+
}
|