首页 > 解决方案 > 如何使 PGraphics 充满点(白色等级基于幅度)和不断变化的弧线的纹理?

问题描述

我正在研究一个基本上应该是圆形频谱图的音频可视化。我有一个图表已经显示了频率和一个弧线,它根据经过的时间而演变。现在我想根据每个频率的幅度用白点填充弧线,就像这里一样: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);
  }
}

标签: audioprocessingvisualization

解决方案


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

  1. 如果您计划在pgPGraphics 实例中渲染弧线,请使用符号访问 pg并在/调用.之间调用绘图函数。目前 pg 中没有渲染任何内容,并且 pg 没有在任何地方使用. 有关更多详细信息,请参阅createGraphics()参考,运行示例代码/调整它/破坏它/修复它/理解它beginDraw()endDraw()image()
  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 转换教程,并牢记转换的顺序很重要。或者,有一个版本使用极坐标(角度/半径)到笛卡尔(x,y)坐标系转换公式来代替。

垂直绘制 FFT 线图,留下顺时针旋转的灰度轨迹作为径向频谱图

PS 我还想知道如何根据 FFT 数据获得漂亮的视觉效果,并且通过一些过滤技巧,结果可能会很好。我建议还在这里查看wakjah 的答案


推荐阅读