首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >根据tone.js react项目中振荡器波的形状绘制可视化/颜色变化?

根据tone.js react项目中振荡器波的形状绘制可视化/颜色变化?
EN

Stack Overflow用户
提问于 2021-05-14 23:59:18
回答 1查看 127关注 0票数 1

我想基于振荡器波的当前部分设置动画/更改颜色,以创建与波匹配的脉冲颜色效果?波形可以是任何类型,例如正弦、三角形等,因此这将根据波形类型创建不同的脉冲,并且振荡器的频率也可以改变(然后我希望也改变脉冲定时)。

假设我需要得到振幅和波长(这些是我所需要的正确的术语吗?)从振荡器对象,并使用它与绘图对象相关,同时使用一些css动画,但我有点卡住了,从哪里开始?特别是关于tone.js部分,我将如何获得所需的值,以及如何随着时间的推移从A颜色到B颜色再转换回来等等。我需要包含像p5这样的外部库吗?或者我可以通过tone.js单独使用draw来完成这项工作吗?

干杯大卫

编辑- @paulwheeler非常感谢你的所有评论,这是一个很大的帮助。为了更清楚,并回答您的问题,这是我所拥有的和需要的,如果您有更多的输入-

i)我有两个从Tone.js连续播放的振荡器。他们用A和B的频率“演奏”,创造出双耳的声音。这两者之间的差异,我称之为值域。例如,Osc1可能是100 4hz,osc2可能是104 4hz,范围是4 4hz。这些振荡器可以是tone.js允许的任何类型(锯齿、正弦、三角形..)

ii)当声音播放时,我想获取范围频率,并将其附加到两种颜色上。因此,在频率的峰值,颜色A将显示为背景色,而在频率的低谷,颜色B将显示。在这两个时间之间,颜色将在两者之间变形,即在任何时间t,颜色将是波上Y位置的表示,这反映了从0开始的距离。这将使它看起来颜色正在变化,以匹配波浪的形状。有点像这里的css (但在这个例子中只使用了关键帧,只是给出了一个我在视觉上的意思的例子)

https://jsfiddle.net/CF3Np/4/

代码语言:javascript
运行
复制
@keyframes animation {
0%     {background-color:red;}
50.0%  {background-color:green;}
100.0%  {background-color:red;}
}
EN

回答 1

Stack Overflow用户

发布于 2021-05-16 10:23:04

粗略地扫描一下tone.js documentation,它似乎具备了您想要合成和分析声音的所有功能。然而,它似乎没有任何用于图形的工具。就绘制图形而言,p5.js无疑是一种选择。然而,这里引用"css动画“有点不合时宜,因为像p5.js这样的库在设计时并没有真正考虑到css样式。相反,您将通过调用每个帧的绘制函数来自己完成所有动画。

当涉及到分析声音以便将其处理为数据并可能将其可视化时,您需要的是Fast Fourier Transform。这是一种算法,它将声波样本分解为单独的正弦波分量,您可以使用这些正弦波的振幅来测量声音的分量频率。p5.js (通过p5.sound插件)和tone.js都有快速傅立叶变换类。如果您已经在使用tone.js,那么您可能希望继续使用它来分析声音,但是您当然可以使用p5.js为它们创建可视化效果。仅作为概念性示例,下面是一个纯p5.js示例:

代码语言:javascript
运行
复制
const notes = [{
    name: 'c',
    freq: 261.6
  },
  {
    name: 'c#',
    freq: 277.2,
    sharp: true
  },
  {
    name: 'd',
    freq: 293.7
  },
  {
    name: 'd#',
    freq: 311.1,
    sharp: true
  },
  {
    name: 'e',
    freq: 329.6
  },
  {
    name: 'f',
    freq: 349.2
  },
  {
    name: 'f#',
    freq: 370.0,
    sharp: true
  },
  {
    name: 'g',
    freq: 392.0
  },
  {
    name: 'g#',
    freq: 415.3,
    sharp: true
  },
  {
    name: 'a',
    freq: 440.0
  },
  {
    name: 'a#',
    freq: 466.2,
    sharp: true
  },
  {
    name: 'b',
    freq: 493.9
  },
];

let playing = {};
let fft;
let bg;

function setup() {
  createCanvas(windowWidth, windowHeight);
  colorMode(HSB);
  bg = color('lightgray');

  for (let note of notes) {
    note.osc = new p5.Oscillator();
    note.osc.freq(note.freq);
    note.osc.amp(0);
  }

  fft = new p5.FFT();
}

function toggleNote(name) {
  let note = notes.filter(n => n.name === name)[0];
  if (playing[name] === undefined) {
    // First play
    note.osc.start();
  }
  if (playing[name] = !playing[name]) {
    // fade in a little
    note.osc.amp(0.2, 0.2);
  } else {
    // fade out a little
    note.osc.amp(0, 0.4);
  }
}

function playNote(name) {
  let note = notes.filter(n => n.name === name)[0];
  if (playing[name] === undefined) {
    // First play
    note.osc.start();
  }
  playing[name] = true;
  note.osc.amp(0.2, 0.2);
}

function releaseNote(name) {
  let note = notes.filter(n => n.name === name)[0];
  playing[name] = false;
  note.osc.amp(0, 0.4);
}

function draw() {
  background(bg);
  let w = width / 3;
  let h = min(height, w * 0.8);
  drawSpectrumGraph(w, 0, w, h);
  drawWaveformGraph(w * 2, 0, w, h);
  drawKeyboard();
  bg = color((fft.getCentroid() * 1.379) % 360, 30, 50);
}

function drawSpectrumGraph(left, top, w, h) {
  let spectrum = fft.analyze();

  stroke('limegreen');
  fill('darkgreen');
  strokeWeight(1);

  beginShape();
  vertex(left, top + h);

  for (let i = 0; i < spectrum.length; i++) {
    vertex(
      left + map(log(i), 0, log(spectrum.length), 0, w),
      top + map(spectrum[i], 0, 255, h, 0)
    );
  }

  vertex(left + w, top + h);
  endShape(CLOSE);
}

function drawWaveformGraph(left, top, w, h) {
  let waveform = fft.waveform();

  stroke('limegreen');
  noFill();
  strokeWeight(1);

  beginShape();

  for (let i = 0; i < waveform.length; i++) {
    let x = map(i * 5, 0, waveform.length, 0, w);
    let y = map(waveform[i], -1, 2, h / 10 * 8, 0);
    vertex(left + x, top + y);
  }

  endShape();
}

function drawKeyboard() {
  let w = width / 3;
  let h = min(height, w * 0.8);
  let x = 1;
  let keyWidth = (w - 8) / 7;
  let sharpWidth = keyWidth * 0.8;
  noStroke();
  let sharpKeys = [];
  for (let note of notes) {
    fill(playing[note.name] ? 'beige' : 'ivory');
    if (note.sharp) {
      sharpKeys.push({
        fill: playing[note.name] ? 'black' : 'dimgray',
        rect: [x - sharpWidth / 2, 0, sharpWidth, h / 2, 0, 0, 4, 4]
      });
    } else {
      rect(x, 0, keyWidth, h - 1, 0, 0, 4, 4);
      x += keyWidth + 1;
    }
  }
  for (let key of sharpKeys) {
    fill(key.fill);
    rect(...key.rect);
  }
}

let keymap = {
  'z': 'c',
  's': 'c#',
  'x': 'd',
  'd': 'd#',
  'c': 'e',
  'v': 'f',
  'g': 'f#',
  'b': 'g',
  'h': 'g#',
  'n': 'a',
  'j': 'a#',
  'm': 'b',
}

function keyPressed(e) {
  let note = keymap[e.key];
  if (note) {
    playNote(note);
  }
}

function keyReleased(e) {
  let note = keymap[e.key];
  if (note) {
    releaseNote(note);
  }
}

function mouseClicked() {
  if (mouseX < width / 3) {
    let w = width / 3;
    let h = w * 0.8;
    let x = 1;
    let keyWidth = (w - 8) / 7;
    let sharpWidth = keyWidth * 0.8;
    let naturalKeys = [];
    let sharpKeys = [];
    for (let note of notes) {
      if (note.sharp) {
        sharpKeys.push({
          name: note.name,
          bounds: {
            left: x - sharpWidth / 2,
            top: 0,
            right: x - sharpWidth / 2 + sharpWidth,
            bottom: h / 2
          }
        });
      } else {
        naturalKeys.push({
          name: note.name,
          bounds: {
            left: x,
            top: 0,
            right: x + keyWidth,
            bottom: h - 1
          }
        });
        x += keyWidth + 1;
      }
    }

    for (let {
        bounds,
        name
      } of sharpKeys.concat(naturalKeys)) {
      if (mouseX > bounds.left && mouseX < bounds.right &&
        mouseY > bounds.top && mouseY < bounds.bottom) {
        toggleNote(name);
        break;
      }
    }
  }
}
代码语言:javascript
运行
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/addons/p5.sound.min.js"></script>

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67537305

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档