@tonejs/ui
Advanced tools
| import { LitElement, html } from '@polymer/lit-element' | ||
| import '../viz/waveform' | ||
| class ToneDemo extends LitElement { | ||
| static get properties(){ | ||
| return { | ||
| autoplay : { type : Boolean }, | ||
| } | ||
| } | ||
| firstUpdated(){ | ||
| super.firstUpdated() | ||
| this.shadowRoot.querySelector('tone-waveform').bind(Tone.Master) | ||
| } | ||
| render(){ | ||
| return html` | ||
| <style> | ||
| :host, #container, tone-waveform { | ||
| width: 100%; | ||
| height: 100%; | ||
| position: absolute; | ||
| top: 0px; | ||
| left: 0px; | ||
| } | ||
| tone-waveform { | ||
| z-index: 0; | ||
| } | ||
| #content { | ||
| position: relative; | ||
| width: 80%; | ||
| min-width: 200px; | ||
| max-width: 400px; | ||
| margin: 40px auto 0px; | ||
| z-index: 1; | ||
| } | ||
| tone-unmute { | ||
| z-index: 10; | ||
| } | ||
| ::slotted(tone-trigger), ::slotted(tone-button), ::slotted(tone-play-toggle), ::slotted(tone-slider){ | ||
| width: 100%; | ||
| display: block; | ||
| margin-bottom: 10px; | ||
| } | ||
| ::slotted(*){ | ||
| font-family: var(--title-font-family); | ||
| font-size: var(--title-font-size); | ||
| } | ||
| </style> | ||
| <div id="container"> | ||
| <tone-waveform></tone-waveform> | ||
| ${this.autoplay ? html`<tone-unmute novolume></tone-unmute>` : html``} | ||
| <div id="content"> | ||
| <slot></slot> | ||
| </div> | ||
| </div> | ||
| ` | ||
| } | ||
| } | ||
| customElements.define('tone-demo', ToneDemo) |
| import { LitElement, html } from '@polymer/lit-element' | ||
| import { Waveforms } from './waveforms' | ||
| class ToneWaveform extends LitElement { | ||
| constructor(){ | ||
| super() | ||
| this._waveform = Waveforms(512).random | ||
| /** | ||
| * The waveform analysis of the incoming signal | ||
| * @type {Tone.Waveform} | ||
| */ | ||
| this._analyser = new Tone.Waveform(512) | ||
| /** | ||
| * A signal to make the analyser rest | ||
| * at 0 when nothing is connected | ||
| * @private | ||
| */ | ||
| this._signal = new Tone.Zero().connect(this._analyser) | ||
| /** | ||
| * the value below which it is considered silent | ||
| */ | ||
| this._silentThresh = 0.001 | ||
| /** | ||
| * The current RMS of the incoming signal | ||
| */ | ||
| this._rms = 0 | ||
| } | ||
| firstUpdated(){ | ||
| super.firstUpdated() | ||
| //kick off the loop | ||
| this._loop() | ||
| } | ||
| bind(source){ | ||
| source.connect(this._analyser) | ||
| } | ||
| _loop(){ | ||
| requestAnimationFrame(this._loop.bind(this)) | ||
| const canvas = this.shadowRoot.querySelector('canvas') | ||
| const conatiner = this.shadowRoot.querySelector('#container') | ||
| const context = canvas.getContext('2d') | ||
| canvas.width = conatiner.clientWidth * 2 | ||
| canvas.height = conatiner.clientHeight * 2 | ||
| //if it's silent, draw a canned waveform when the mouse is over | ||
| const analysis = this._analyser.getValue() | ||
| if (this._isSilent(analysis)){ | ||
| this._drawAnalysis(this._waveform, true, context) | ||
| } else { //if it's not silent, draw the waveform | ||
| this._drawAnalysis(analysis, false, context) | ||
| } | ||
| } | ||
| _isSilent(analysis){ | ||
| //if the average is close to 128 | ||
| let total = 0 | ||
| for (let i = 0; i < analysis.length; i++){ | ||
| total += Math.pow(analysis[i], 2) | ||
| } | ||
| const rms = Math.sqrt(total / analysis.length) | ||
| this._rms = Math.max(rms, this._rms * 0.9) | ||
| return this._rms < this._silentThresh | ||
| } | ||
| _drawAnalysis(analysis, silent, context){ | ||
| const { width, height } = context.canvas | ||
| let margin = height * 0.2 | ||
| if (silent){ | ||
| margin = Math.scale(this._rms, 0, this._silentThresh, height * 0.2, height * 0.5) | ||
| } | ||
| context.clearRect(0, 0, width, height) | ||
| context.beginPath() | ||
| let firstValue | ||
| for (let i = 0, len = analysis.length; i < len; i++){ | ||
| const x = Math.scale(i, 0, len - 1, 0, width) | ||
| const y = Math.scale(analysis[i], -1, 1, height - margin, margin) | ||
| if (i === 0){ | ||
| firstValue = y | ||
| context.moveTo(x, y) | ||
| } else { | ||
| context.lineTo(x, y) | ||
| } | ||
| } | ||
| context.lineTo(width, height) | ||
| context.lineTo(0, height) | ||
| context.lineTo(0, firstValue) | ||
| context.lineCap = 'round' | ||
| // context.stroke(); | ||
| context.fillStyle = '#22DBC0' | ||
| context.fill() | ||
| } | ||
| render(){ | ||
| return html` | ||
| <style> | ||
| :host, #container, canvas { | ||
| width: 100%; | ||
| height: 100%; | ||
| position: absolute; | ||
| top: 0px; | ||
| left: 0px; | ||
| } | ||
| #container { | ||
| background-color: var(--color-magenta); | ||
| } | ||
| </style> | ||
| <div id="container"> | ||
| <canvas></canvas> | ||
| </div> | ||
| ` | ||
| } | ||
| } | ||
| customElements.define('tone-waveform', ToneWaveform) |
| export function Waveforms(bufferLength){ | ||
| const sine = new Array(bufferLength) | ||
| const square = new Array(bufferLength) | ||
| const sawtooth = new Array(bufferLength) | ||
| const triangle = new Array(bufferLength) | ||
| const choices = [sine, sawtooth, triangle, square] | ||
| for (let i = 0; i < bufferLength; i++){ | ||
| sine[i] = Math.sin(Math.PI * 2 * i / bufferLength) | ||
| } | ||
| for (let i = 0; i < bufferLength; i++){ | ||
| sawtooth[i] = (((i + bufferLength/2) % bufferLength) / bufferLength) * 2 - 1 | ||
| } | ||
| for (let i = 0; i < bufferLength; i++){ | ||
| if (i < bufferLength/3){ | ||
| triangle[i] = i/(bufferLength/3) * 2 - 1 | ||
| } else if (i < bufferLength * 2/3){ | ||
| triangle[i] = (1 - (i - bufferLength/3)/(bufferLength/3)) * 2 - 1 | ||
| } else { | ||
| triangle[i] = (i - bufferLength * 2/3)/(bufferLength/3) * 2 - 1 | ||
| } | ||
| } | ||
| for (let i = 0; i < bufferLength; i++){ | ||
| var margin = bufferLength/16 | ||
| if (i < margin){ | ||
| square[i] = -1 | ||
| } else if (i < bufferLength/2){ | ||
| square[i] = 1 | ||
| } else if (i < (bufferLength - margin)){ | ||
| square[i] = -1 | ||
| } else { | ||
| square[i] = 1 | ||
| } | ||
| } | ||
| const random = choices[Math.floor(Math.random()*choices.length)] | ||
| return { | ||
| sawtooth : sawtooth, | ||
| sine : sine, | ||
| triangle : triangle, | ||
| square : square, | ||
| random : random | ||
| } | ||
| } |
+1
-1
| { | ||
| "name": "@tonejs/ui", | ||
| "version": "0.0.6", | ||
| "version": "0.0.7", | ||
| "description": "Web Component interfaces for Tone.js", | ||
@@ -5,0 +5,0 @@ "main": "build/tonejs-ui.js", |
@@ -51,3 +51,3 @@ import { LitElement, html } from '@polymer/lit-element' | ||
| <tone-slider | ||
| label="Predealy" | ||
| label="Predelay" | ||
| attribute="preDelay" | ||
@@ -54,0 +54,0 @@ min="0.001" |
+1
-0
@@ -49,2 +49,3 @@ /** | ||
| import './page/example' | ||
| import './page/demo' | ||
@@ -51,0 +52,0 @@ import './viz/oscilloscope' |
+12
-9
@@ -19,2 +19,3 @@ import { LitElement, html } from '@polymer/lit-element' | ||
| focused : { type : Boolean }, | ||
| novolume : { type : Boolean } | ||
| } | ||
@@ -38,3 +39,3 @@ } | ||
| const volume = this.shadowRoot.querySelector('#volume') | ||
| if (!this.muted && volume.min == volume.value){ | ||
| if (!this.novolume && !this.muted && volume.min == volume.value){ | ||
| volume.value = 0 | ||
@@ -85,3 +86,3 @@ } | ||
| #container:hover, #container[focused] { | ||
| #container:hover:not([novolume]), #container[focused]:not([novolume]) { | ||
| width: 144px; | ||
@@ -124,3 +125,3 @@ } | ||
| </style> | ||
| <div id="container" ?focused=${this.focused}> | ||
| <div id="container" ?focused=${this.focused} ?novolume=${this.novolume}> | ||
| <button | ||
@@ -134,8 +135,10 @@ @blur=${e => this.focused = false} | ||
| <tone-slider | ||
| @blur=${e => this.focused = false} | ||
| @focus=${e => this.focused = true} | ||
| id="volume" | ||
| @change=${this._adjustVolume.bind(this)} | ||
| bare min="-60" max="0" value="0"></tone-slider> | ||
| ${!this.novolume ? html` | ||
| <tone-slider | ||
| @blur=${e => this.focused = false} | ||
| @focus=${e => this.focused = true} | ||
| id="volume" | ||
| @change=${this._adjustVolume.bind(this)} | ||
| bare min="-60" max="0" value="0"></tone-slider>` : html``} | ||
| </div> | ||
@@ -142,0 +145,0 @@ ` |
Sorry, the diff of this file is too big to display
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
1585070
0.56%199
1.53%10722
2.6%