如何将音频频谱扩展到网格中
How to spread the audio spectrum into a grid
我正在尝试使用处理来获取音频输入并创建分成多行并均匀适合草图宽度的音频频谱。
我希望椭圆像时尚一样散布在网格中,同时也代表光谱的不同部分。
import ddf.minim.analysis.*;
import ddf.minim.*;
Minim minim;
FFT fft;
AudioInput mic;
void setup()
{
size(512, 512, P3D);
minim = new Minim(this);
mic = minim.getLineIn();
fft = new FFT(mic.bufferSize(), mic.sampleRate());
}
void draw()
{
background(0);
stroke(255);
fft.forward(mic.mix);
for(int i = 0; i < fft.specSize(); i++)
{
float size = fft.getBand(i);
float x = map(i, 0, fft.specSize(), 0, height);
float y = i;
ellipse(x, y, size, size );
}
}
fft 数据是一维信号,您希望将数据可视化为二维网格。
如果您知道您希望网格有多少行和列,您可以使用算术根据索引计算 x 和 y 网格位置。
假设您有 100 个元素,并且您希望将它们显示在 10x10 的网格中:
使用一维数组计数器对列数取模 (%) 计算二维 x 索引,用 (/) 除以列数计算二维 y 索引:
for(int i = 0 ; i < 100; i++){
println(i,i % 10, i / 10);
}
这是一个更长的注释示例:
// fft data placeholder
float[] values = new float[100];
// fill with 100 random values
for(int i = 0 ; i < values.length; i++){
values[i] = random(0.0,1.0);
}
// how many rows/cols
int rows = 10;
int cols = 10;
// how large will a grid element be (including spacing)
float widthPerSquare = (width / cols);
// grid elements offset from top left
float offsetX = widthPerSquare * 0.5;
float offsetY = widthPerSquare * 0.5;
noStroke();
smooth();
println("i,gridX,gridY,value");
// traverse data
for(int i = 0; i < 100; i++){
// calculate x,y indices
int gridX = i % rows;
int gridY = i / rows;
println(i+","+gridX+","+gridY+","+values[i]);
// calculate on screen x,y position based on grid element size
float x = offsetX + (gridX * widthPerSquare);
float y = offsetY + (gridY * widthPerSquare);
// set the size to only be 75% of the grid element (to leave some spacing)
float size = values[i] * widthPerSquare * 0.75;
//fill(values[i] * 255);
ellipse(x,y,size,size);
}
在你的例子中,假设 fft.specSize() 是 512 左右,你想画一个正方形网格,你可以这样做:
import ddf.minim.analysis.*;
import ddf.minim.*;
Minim minim;
FFT fft;
AudioInput mic;
int rows;
int cols;
float xSpacing;
float ySpacing;
void setup()
{
size(512, 512, P3D);
noStroke();
minim = new Minim(this);
mic = minim.getLineIn();
fft = new FFT(mic.bufferSize(), mic.sampleRate());
// define your own grid size or use an estimation based on square root of your FFT data
rows = cols = (int)sqrt(fft.specSize());
println(rows,rows * rows);
xSpacing = width / cols;
ySpacing = height / rows;
}
void draw()
{
background(0);
fft.forward(mic.mix);
for(int i = 0; i < fft.specSize(); i++)
{
float size = fft.getBand(i) * 90;
float x = (i % rows) * xSpacing;
float y = (i / rows) * ySpacing;
ellipse(x, y, size, size );
}
}
请注意,该示例未应用偏移量,网格为 22 x 22 (484 != 512),
但希望它能给你一些想法。
要记住的另一件事是 FFT 数组的内容。
您可能希望以对数方式缩放以考虑 how we perceive 声音。
查看 Processing > Examples > Contributed Libraries > Minim > Analysis > SoundSpectrum 并查看 logAverages()
。播放 minBandwidth
和 bandsPerOctave
可能会帮助您获得更好的视觉效果。
如果您想更深入地了解可视化,请查看这个 wakjah 的优秀答案 here and if you have time, go through Dan Ellis' amazing Music Signal Computing 课程
我正在尝试使用处理来获取音频输入并创建分成多行并均匀适合草图宽度的音频频谱。 我希望椭圆像时尚一样散布在网格中,同时也代表光谱的不同部分。
import ddf.minim.analysis.*;
import ddf.minim.*;
Minim minim;
FFT fft;
AudioInput mic;
void setup()
{
size(512, 512, P3D);
minim = new Minim(this);
mic = minim.getLineIn();
fft = new FFT(mic.bufferSize(), mic.sampleRate());
}
void draw()
{
background(0);
stroke(255);
fft.forward(mic.mix);
for(int i = 0; i < fft.specSize(); i++)
{
float size = fft.getBand(i);
float x = map(i, 0, fft.specSize(), 0, height);
float y = i;
ellipse(x, y, size, size );
}
}
fft 数据是一维信号,您希望将数据可视化为二维网格。
如果您知道您希望网格有多少行和列,您可以使用算术根据索引计算 x 和 y 网格位置。
假设您有 100 个元素,并且您希望将它们显示在 10x10 的网格中:
使用一维数组计数器对列数取模 (%) 计算二维 x 索引,用 (/) 除以列数计算二维 y 索引:
for(int i = 0 ; i < 100; i++){
println(i,i % 10, i / 10);
}
这是一个更长的注释示例:
// fft data placeholder
float[] values = new float[100];
// fill with 100 random values
for(int i = 0 ; i < values.length; i++){
values[i] = random(0.0,1.0);
}
// how many rows/cols
int rows = 10;
int cols = 10;
// how large will a grid element be (including spacing)
float widthPerSquare = (width / cols);
// grid elements offset from top left
float offsetX = widthPerSquare * 0.5;
float offsetY = widthPerSquare * 0.5;
noStroke();
smooth();
println("i,gridX,gridY,value");
// traverse data
for(int i = 0; i < 100; i++){
// calculate x,y indices
int gridX = i % rows;
int gridY = i / rows;
println(i+","+gridX+","+gridY+","+values[i]);
// calculate on screen x,y position based on grid element size
float x = offsetX + (gridX * widthPerSquare);
float y = offsetY + (gridY * widthPerSquare);
// set the size to only be 75% of the grid element (to leave some spacing)
float size = values[i] * widthPerSquare * 0.75;
//fill(values[i] * 255);
ellipse(x,y,size,size);
}
在你的例子中,假设 fft.specSize() 是 512 左右,你想画一个正方形网格,你可以这样做:
import ddf.minim.analysis.*;
import ddf.minim.*;
Minim minim;
FFT fft;
AudioInput mic;
int rows;
int cols;
float xSpacing;
float ySpacing;
void setup()
{
size(512, 512, P3D);
noStroke();
minim = new Minim(this);
mic = minim.getLineIn();
fft = new FFT(mic.bufferSize(), mic.sampleRate());
// define your own grid size or use an estimation based on square root of your FFT data
rows = cols = (int)sqrt(fft.specSize());
println(rows,rows * rows);
xSpacing = width / cols;
ySpacing = height / rows;
}
void draw()
{
background(0);
fft.forward(mic.mix);
for(int i = 0; i < fft.specSize(); i++)
{
float size = fft.getBand(i) * 90;
float x = (i % rows) * xSpacing;
float y = (i / rows) * ySpacing;
ellipse(x, y, size, size );
}
}
请注意,该示例未应用偏移量,网格为 22 x 22 (484 != 512), 但希望它能给你一些想法。
要记住的另一件事是 FFT 数组的内容。
您可能希望以对数方式缩放以考虑 how we perceive 声音。
查看 Processing > Examples > Contributed Libraries > Minim > Analysis > SoundSpectrum 并查看 logAverages()
。播放 minBandwidth
和 bandsPerOctave
可能会帮助您获得更好的视觉效果。
如果您想更深入地了解可视化,请查看这个 wakjah 的优秀答案 here and if you have time, go through Dan Ellis' amazing Music Signal Computing 课程