webgl+canvas浏览器中自动生成音乐可视化效果代码
代码语言:html
所属分类:多媒体
代码描述:webgl+canvas浏览器中自动生成音乐可视化效果代码,使用webkitAudioContext来弹奏生成播放音乐。
代码标签: webgl canvas 浏览器 自动 生成 音乐 可视化
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> :root { --clr-fg: #fff7; --clr-active-fg: #fff9; } html, body { margin: 0; padding: 0; } canvas { position: fixed; z-index: -2; width: 100%; height: auto; inset: 0; user-select: none; } .control { display: grid; place-content: center; position: absolute; width: 200px; height: 200px; inset: 0; margin: auto; } .control_label { opacity: 0; display: grid; place-content: center; transition: opacity 1200ms cubic-bezier(0.075, 0.82, 0.165, 1); } .control.initial .control_label { opacity: 1; } .control:hover .control_label { opacity: 1; } .control_display, .control_input { grid-row: 1/-1; grid-column: 1/-1; position: relative; cursor: pointer; } .control_display { display: grid; place-content: center; font-size: 0.825em; font-weight: 500; } .control_display svg { --duration: 50ms; display: inline-block; stroke-linejoin: round; stroke-width: 2px; fill: var(--clr-fg); transition: var(--duration); transform: scale(1.1); } .control_display svg .speaker-vol { stroke-linecap: round; } .control_display svg .speaker-on { fill: none; stroke: none; opacity: 0; transition: opacity var(--duration); } .control_label:has([type="checkbox"]:checked) svg { fill: var(--clr-active-fg); } .control_label:has([type="checkbox"]:checked) svg .speaker-on { opacity: 1; fill: var(--clr-active-fg); } input[type="checkbox"] { -webkit-appearance: none; appearance: none; background-color: transparent; position: relative; margin: 0; width: 6em; height: 6em; transform: scale(1); font: inherit; color: currentColor; border-width: 0.15rem; border-style: solid; border-radius: 50%; border-color: var(--clr-fg); display: grid; place-content: center; background: #11111199; box-shadow: 0px 0px 12px 0 #a5a5a5; } input[type="checkbox"]:hover { transform: scale(1.1); transition: 300ms cubic-bezier(0.075, 0.82, 0.165, 1); } input[type="checkbox"]:is(:checked, :active), input[type="checkbox"]:is(:checked, :active) + .control_display svg { transform: scale(1); } input[type="checkbox"]::after { content: ""; position: absolute; inset: 0; border-radius: inherit; box-shadow: 0 2px 5px 2px #fff9, 0 2px 10px 10px #fff7, 0 2px 20px 20px #fff5; opacity: 0; transform: scale(0.95); transition: 400ms; } input[type="checkbox"]:hover::after { transform: scale(1.05); opacity: 1; } </style> </head> <body translate="no"> <canvas id="canvas"></canvas> <div class="control initial"> <label class="control_label"> <input type="checkbox" class="control_input" name="vol" id="play"> <div class="control_display"> <svg viewBox="0 0 60 60" width="60" height="60"> <path class="speaker-cone" d=" M5 25 Q10 25 30 5 L30 55 Q10 35 5 35 Z "></path> <path class="speaker-vol" d=" M35 25 A 5 5 0 0 1 35 35 "></path> <path class="speaker-vol speaker-on" d=" M35 15 A 5 5 0 0 1 35 45 "></path> </svg> </div> </label> </div> <script > const choose = a => a[Math.floor(Math.random() * a.length)]; const speeds = [.3, .45]; const resont = [.25, .5]; const volmns = [.8, .9, 1]; const options = { volume: choose(volmns), resonance: choose(resont), speed: choose(speeds), rand: 1 }; let nextSpeed = options.speed; let nextVolume = .2; const Composer = () => { /****************************** * Original Author: Yota Morimoto * Web Site: https://yota.tehis.net/asg/ */ let context, main, verb, bus, compressor; const trigger = Object.freeze({ trig: function () { let prev = 0; let t = false; return function (val) { t = prev < 0 && val >= 0; prev = val; return t; }; }, change: function () { let prev = 0; let t = false; return function (val) { t = prev != val; prev = val; return t; }; }, pulse: function (threshold) { let prev = 0; let t = false; return function (b) { if (b) prev++; if (prev == threshold) { t = true; prev = 0; } else {t = false;} return t; }; } }); const roots = [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]; const melodicminor = [0, 2, 3, 5, 7, 9, 11]; const locrian = [0, 1, 3, 5, 6, 8, 10]; const phrygian = [0, 1, 3, 5, 7, 8, 10]; const aeolian = [0, 2, 3, 5, 7, 8, 10]; const dorian = [0, 2, 3, 5, 7, 9, 10]; const ionian = [0, 2, 4, 5, 7, 9, 11]; const mixolydian = [0, 2, 4, 5, 7, 9, 10]; const lydian = [0, 2, 4, 6, 7, 9, 11]; const mode = [melodicminor, locrian, phrygian, aeolian, dorian, ionian, mixolydian, lydian]; const lowTrig = trigger.trig(); const highTrig = trigger.trig(); const lowChanged = trigger.change(); const highChanged = trigger.change(); const pulseTrig = trigger.trig(); const pulsed = trigger.pulse(20); let b = Float32Array.from({ length: 3 }, () => Math.random() * 2 - 1); let m = pickItem(b[0], 0, 20, mode); let root = pickItem(b[1], 0, 20, roots); let then = 0, speedAnimStart = 0, volAnimStart = 0, volAnimStarted = false, speedAnimStarted = false, animationDuration = 5000; options.rand = lerp(b[2], -1, 1, 0.05, 1); function loop(now) { if (now - then > expInterp(nextSpeed, 0, 1, 800, 80)) { compose(); then = now; } if (Math.abs(options.speed - nextSpeed) > .001) { if (!speedAnimStarted) { speedAnimStart = now; speedAnimStarted = true; } const elapsed = now - speedAnimStart; const fraction = elapsed / animationDuration; if (fraction < 1) { const val = fractInterp(nextSpeed, options.speed, fraction); nextSpeed = round(1e3 * val) * 1e-3; } else { speedAnimStarted = false; } } if (Math.abs(options.volume - nextVolume) > .001) { if (!volAnimStarted) { volAnimStart = now; volAnimStarted = true; } const elapsed = now - volAnimStart; const fraction = elapsed / (animationDuration * 20); if (fraction < 1) { const val = fractInterp(nextVolume, options.volume, fraction); nextVolume = round(1e3 * val) * 1e-3; main.gain.value = dbamp(lerp(nextVolume, 0, 1, -60, 3)); } else { volAnimStarted = false; } } requestAnimationFrame(loop); } function compose() { b = Float32Array.from({ length: 24 }, () => Math.random() * 2 - 1); if (pulsed(pulseTrig(b[0]))) { m = pickItem(b[0], 0, 20, mode); root = pickItem(b[1], 0, 20, roots); options.speed = choose(speeds); console.table(options); } if (lowTrig(b[10])) { const note = pickNote(b[11], 15, 35); if (lowChanged(note)) { sine( midicps(note), pickVolume(b[12], -24, -9), b[13]); } } if (highTrig(b[20])) { const note = pickNote(b[21], 20, 40); if (highChanged(note)) { sine( midicps(note), pickVolume(b[22], -24, -9), b[23]); } } } function pickItem(v, a, b, array) { return array[round(lerp(v, -1, 1, a, b)) % (array.length - 1)]; .........完整代码请登录后点击上方下载按钮下载查看
网友评论0