如何制作充满点(白色等级基于振幅)和纹理以适应不断变化的弧线的 PGraphics?

How do I make a PGraphics filled with points (grade of white is based on the amplitude) and texture that to the ever evolving arc?

我正在研究基本上应该是圆形频谱图的音频可视化。我有一个显示频率的图表和一个弧,它根据经过的时间演变。现在我想根据每个频率的幅度用白点填充圆弧,就像这里:https://vimeo.com/27135957。显然,我需要制作一个充满点的 PGraphics,这些点根据振幅从白色变为黑色。然后我需要用这个图形对弧线进行纹理处理。有谁知道如何做到这一点?

import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.effects.*;
import ddf.minim.signals.*;
import ddf.minim.spi.*;
import ddf.minim.ugens.*;

Minim minim;
AudioPlayer song;
FFT fft;
PGraphics pg;
PShape arc;

float deg = 90;
float rad = radians(deg);

void setup()
{
  size(1000, 1000);

  minim = new Minim(this);
  song = minim.loadFile("Anthology.mp3");
  song.play();

  fft = new FFT(song.bufferSize(), song.sampleRate());

  pg = createGraphics(width, height);
}

void draw()
{
  background(0);
  fft.forward(song.mix);

  for (int i = 0; i < fft.specSize(); i++)
  {
    pushMatrix();
    stroke(255);
    line(i, height, i, height - fft.getBand(i)*0.5);
    popMatrix();
    println(fft.getBand(i));

    //Map Amplitude to 0 → 255, fill with points and color them
    float brightness = map(fft.getBand(i), -1, 1, 0, 255);
    pg.beginDraw();
    pg.endDraw();

    fill(255, 255, 255,);
    noStroke();
    float evolution = radians(map(song.position(), 0, song.length(), 90, 450));
    //texture(pg);
    arc(height/2, height/2, height-100, height-100, rad, evolution, PIE);
  }
}

根据您的代码,有几个概念不清楚:

  1. 如果您计划在 pg PGraphics 实例中渲染圆弧,请使用 . 符号访问 pg 并在 beginDraw()/endDraw() 调用之间调用绘图函数。目前,pg 中没有渲染任何内容,并且使用 image() 也没有在任何地方渲染 pg。有关详细信息,请参阅 createGraphics() 参考,运行 示例代码/调整它/打破 it/fix it/understand 它
  2. 同样PShape arc创建但未使用
  3. 有评论试图将 pg 用作纹理,但纹理映射不清楚

如果同时使用 PGraphicsPShape 令人困惑,您可以单独使用 PGraphics 实现类似的效果:只需渲染一些较大的灰色点而不是弧形。它不会是完全相同的效果,但它会以更少的努力获得非常相似的外观。

这是基于您的代码的变体:

import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.effects.*;
import ddf.minim.signals.*;
import ddf.minim.spi.*;
import ddf.minim.ugens.*;

Minim minim;
AudioPlayer song;
FFT fft;

PGraphics pg;

void setup()
{
  size(600, 600, P2D);

  minim = new Minim(this);
  song = minim.loadFile("jingle.mp3", 1024);
  song.loop();

  fft = new FFT(song.bufferSize(), song.sampleRate());
  // optional: use logarithmic averages: clover to how we perceive sound
  fft.logAverages( 30, 6 );
  // setup pg graphics layer disable fill, make points stroke thick
  pg = createGraphics(width, height);
  pg.beginDraw();
  pg.strokeWeight(3);
  pg.noFill();
  pg.endDraw();
}

void draw()
{
  background(0);
  image(pg, 0, 0);
  // perform FFT on stereo mix
  fft.forward(song.mix);
  // center coordinates
  float cx = width * 0.5;
  float cy = height * 0.5;
  // count FFT bins
  int fftSpecSize = fft.specSize();
  // calculate the visual size for representing an FFT bin
  float sizePerSpec = (height * 0.5 ) / fftSpecSize;

  stroke(255);
  noFill();

  // start @editing@ the pg layer (once
  pg.beginDraw();

  // start the FFT graph shape
  beginShape();

  // for each FFT bin
  for (int i = 0; i < fftSpecSize; i++)
  {
    // get the vands in reverse order (low frequencies last)
    float fftBand = fft.getBand(fftSpecSize - i - 1);
    // scale FFT bin value to pixel/render size
    float xOffset = fftBand * 10;
    // map FFT bins to 0-255 brightness levels (note 35 may differ 
    float brightness = map(fftBand, 0, 35, 0, 255);

    // draw the line graph vertex
    vertex(cx + xOffset, cy + sizePerSpec * i);
    // map song position (millis played) to 360 degrees in radians (2 * PI)
    // add HALF_PI (90 degrees) because  0 degrees points to the right and drawing should start pointing down (not right)
    //float angle = map(song.position(), 0, song.length(), 0, TWO_PI) + HALF_PI;
    // as a test map it to a lower value
    float angle = (frameCount * 0.0025) + HALF_PI;
    // map radius from FFT index
    float radius = map(i, 0, fftSpecSize - 1, 0, width * 0.5);
    // use mapped brightness as point stroke 
    pg.stroke(brightness);
    // use polar coordinates mapped from the centre
    pg.pushMatrix();
    pg.translate(cx,cy);
    pg.rotate(angle);
    pg.point(radius,0);
    pg.popMatrix();
    // alternatively use polar to cartesian coordinate conversion
    // x = cos(angle) * radius
    // y = sin((angle) * radius
    // cx, cy are added to offset from center
    //pg.point(cx + (cos(angle) * radius),
    //         cy + (sin(angle) * radius));
  }
  // finish FFT graph line
  endShape();
  // fnish pg layer
  pg.endDraw();
}

备注

  • 您可能想将 jingle.mp3 更改为您的音频文件名
  • 为了测试短曲目,我使用了 angle 的任意映射(与代码中的 evolution 相同):有一个注释版本采用曲目持续时间考虑
  • 灰度点位置使用坐标变换渲染。一定要通过 2D Transformations tutorial 并记住转换的顺序很重要。或者,有一个版本使用极坐标 (angle/radius) 到笛卡尔 (x,y) 坐标系转换公式来执行相同的操作。

P.S。我还想知道如何根据 FFT 数据获得漂亮的视觉效果,并通过一些过滤技巧获得不错的结果。我建议还查看 wakjah's answer here.