Как изменить параметр CSS с помощью Web Audio API в Javascript? - PullRequest
0 голосов
/ 02 мая 2020

Я работаю над проектом визуализатора c.

На моей странице HTML у меня есть div, который был стилизован в желтый круг с помощью CSS.

С JAVASCRIPT я хотел бы собрать данные о частоте аудиофайла, и с этими данными изменить цвет круга на розовый, когда частота достигает определенного c числа - числа это будет представлять переходные процессы в аудио. В основном, желтый круг, который меняется на розовый после ритма песни.

HTML:

<!DOCTYPE html>

<html>
  <head>
    <meta charset="utf-8">
    <title>CSS Flower</title>
    <style>
      /* centering */
      body {
        margin: 0;
        height: 100vh;
        display: flex;
        align-items: center;
        justify-content: center;
      }

      /* proportion and perspective */
      #scene {
        width: 200px;
        height: 200px;
        perspective: 600px;
        perspective-origin: center top;
      }

      .flower {
        width: 100%;
        height: 100%;
        position: relative;
        transform-style: preserve-3d;
      }

      #center {
        position: absolute;
        width: 100px;
        height: 100px;
        border-radius: 50px;
        background: yellow;  // THIS IS YELLOW CIRCLE, AND PARAMETER I WANT TO CHANGE
        transform: rotateX(180deg) translateX(50px) translateZ(-140px);
      }

    </style>
  </head>

  <body>
    <input type="file" id="file-input" accept="audio/*,video/*,image/*" />
    <canvas id="canvas"></canvas>
    <div id="scene">
      <div class="flower">
        <div class="center" id="center"></div>
      </div>
    </div>
    <audio id="audio" controls></audio>
    <script src="audio.js"></script>
  </body>
</html>

Код JS, который у меня сейчас есть:

window.onload = function() {

  const file = document.getElementById("file-input");
  const canvas = document.getElementById("canvas");
  const audio = document.getElementById("audio");

  file.onchange = function() {

    const files = this.files; 
    console.log('FILES[0]: ', files[0])
    audio.src = URL.createObjectURL(files[0]); 

    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    const ctx = canvas.getContext("2d");
    const flower = document.getElementById('center');



    const context = new AudioContext(); 
    let src = context.createMediaElementSource(audio); 
    const analyser = context.createAnalyser(); 

    src.connect(analyser); 
    analyser.connect(context.destination); 

    analyser.fftSize = 1024;

    const bufferLength = analyser.frequencyBinCount; 

    const dataArray = new Uint8Array(bufferLength); 

    const WIDTH = canvas.width;
    const HEIGHT = canvas.height;

    function renderFrame() {
      requestAnimationFrame(renderFrame); // Takes callback function to invoke before rendering


      analyser.getByteFrequencyData(dataArray); // Copies the frequency data into dataArray
      // Results in a normalized array of values between 0 and 255
      // Before this step, dataArray's values are all zeros (but with length of 8192)

      for (let i = 0; i < bufferLength; i++) {
        console.log("data array: ", dataArray)

//from here I can see the different frequencies collected in the array, but I don't know how to proceed
      }

    audio.play();
    renderFrame();
  };
};
};

Я не могу понять, как сформулировать FOR l oop, а затем как связать эту информацию с параметром CSS.

Любая помощь будет чрезвычайно признательна! Я пытался понять это в течение нескольких дней, но безуспешно. Как вы, вероятно, можете сказать по моему коду, я начинающий!

Всего наилучшего,

Джейд

1 Ответ

1 голос
/ 02 мая 2020

Просто делайте средние частоты. Вот рабочий пример:

const file = document.getElementById("file-input");
const canvas = document.getElementById("canvas");
const audio = document.getElementById("audio");

var threshold = 230;  //Point where turn the "flower" pink
var frequencies = 10; //Number of records to count (You want to look for lower frequencies)

file.onchange = function() {

    const files = this.files;
    //console.log('FILES[0]: ', files[0])
    audio.src = URL.createObjectURL(files[0]);

    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    const ctx = canvas.getContext("2d");
    const flower = document.getElementById('center');



    const context = new AudioContext();
    let src = context.createMediaElementSource(audio);
    const analyser = context.createAnalyser();

    src.connect(analyser);
    analyser.connect(context.destination);

    analyser.fftSize = 1024;

    const bufferLength = analyser.frequencyBinCount;

    const dataArray = new Uint8Array(bufferLength);

    const WIDTH = canvas.width;
    const HEIGHT = canvas.height;

    function renderFrame() {
        requestAnimationFrame(renderFrame); // Takes callback function to invoke before rendering


        analyser.getByteFrequencyData(dataArray); // Copies the frequency data into dataArray
        // Results in a normalized array of values between 0 and 255
        // Before this step, dataArray's values are all zeros (but with length of 8192)

        let sum = 0;

        for(let i = 0; i < bufferLength; i++) {
            if(i < frequencies) sum += dataArray[i];

            //Do some other stuff
        }

        //Change CSS according to threshold
        let avg = sum / frequencies;
        flower.style.backgroundColor = avg > threshold ? "pink" : "yellow";
        flower.style.transform = `scale(${avg / 255})`;
        flower.innerText = ~~avg;

    };

    //!!This functions have to be called outside of the rendering function (renderFrame)!!
    audio.play();
    renderFrame();
};


/* Sliders */
const sliderF = document.querySelector(".slider.f");
const sliderFvalue = document.querySelector(".slider-value.f");
const sliderT = document.querySelector(".slider.t");
const sliderTvalue = document.querySelector(".slider-value.t");

sliderF.oninput = function() {
  sliderFvalue.innerText = this.value;
  frequencies = +this.value;
}

sliderT.oninput = function() {
  sliderTvalue.innerText = this.value;
  threshold = +this.value;
}
/* centering */
body {
  margin: 0;
}

canvas {
  position: absolute;
  pointer-events: none;
}

#audio {
  width: 100vw;
}

#center {
  width: 100px;
  height: 100px;
  border-radius: 50px;
  background-color: yellow;
  text-align: center;
  line-height: 100px;
}
      
.slider-value {
  display: inline-block;
  width: 25px;
}

.slider {
  width: 90vw;
}
<input type="file" id="file-input" accept="audio/*,video/*,image/*" /><br>
<canvas id="canvas"></canvas>
<audio id="audio" controls></audio>
<div class="center" id="center"></div>

<!-- Frequences Slider --->
<input type="range" min="0" max="500" value="10" step="1" class="slider f">
<span class="slider-value f">10</span>

<!-- Threshold Slider --->
<input type="range" min="0" max="255" value="230" step="1" class="slider t">
<span class="slider-value t">230</span>

Вам просто нужно отрегулировать ползунки, чтобы сделать его идеальным, но, возможно, было бы лучше использовать некоторые низкочастотные эквалайзеры, чтобы получить еще более близкие результаты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...