このプログラムは、音声信号を解析し、周波数領域での音声のパワーをグラフィカルに表現することができます。具体的には、左右のオーディオ入力を取り込み、FFT(高速フーリエ変換)アルゴリズムを使用して各バンドの周波数成分を計算し、グラフィカルに表示しています。グラフは、周波数帯域ごとのバーで構成されており、各バーの高さは周波数成分の強さに対応しています。音声のパワーが高い領域は、バーが高くなるため、グラフの形状は音声のパワースペクトルを反映しています。
import processing.sound.*;
color dCyan = #005678;
color lCyan = #0099aa;
AudioIn audioInL, audioInR;
FFT fftL, fftR;
int samples = 2048;
int numBars = 16;
float[][] barHeights = new float[2][numBars];
float sampleRate = 48000.0;
void setup() {
size(720, 300, P2D);
noStroke();
background(dCyan);
frameRate(90);
audioInL = new AudioIn(this, 0);
audioInR = new AudioIn(this, 1);
audioInL.start();
audioInR.start();
fftL = new FFT(this, samples);
fftR = new FFT(this, samples);
fftL.input(audioInL);
fftR.input(audioInR);
}
void draw() {
background(dCyan);
fftL.analyze();
fftR.analyze();
updateBarHeights(fftL, 0);
updateBarHeights(fftR, 1);
for (int i = 0; i < numBars; i++) {
drawBar(i, barHeights[0][i], width / 4, true);
drawBar(i, barHeights[1][i], 3 * width / 4, false);
}
}
float[] generateOctaveBands(int numBands) {
float minFreq = 31.25;
float maxFreq = sampleRate / 2.0; // ナイキスト周波数を最大周波数に設定
float[] bands = new float[numBands + 1];
float ratio = pow(maxFreq / minFreq, 1.0 / numBands);
for (int i = 0; i <= numBands; i++) {
bands[i] = minFreq * pow(ratio, i);
}
return bands;
}
void updateBarHeights(FFT fft, int channel) {
float[] spectrum = fft.analyze();
int spectrumSize = spectrum.length;
float freqPerBin = sampleRate / 2.0 / spectrumSize;
float[] octaveBands = generateOctaveBands(numBars);
int numOctaveBands = octaveBands.length - 1;
for (int i = 0; i < numOctaveBands; i++) {
float lowFreq = octaveBands[i];
float highFreq = octaveBands[i + 1];
int lowIndex = round(lowFreq / freqPerBin);
int highIndex = min(round(highFreq / freqPerBin), spectrumSize - 1);
int numBins = highIndex - lowIndex;
float sum = 0;
for (int j = lowIndex; j < highIndex; j++) {
sum += spectrum[j];
}
float average = sum / numBins;
float db = max(20 * log(average) / log(10), -100);
barHeights[channel][i] = map(db, -100, 0, 0, height);
}
}
void drawBar(int index, float barHeight, float centerX, boolean flip) {
float barWidth = (width / 2) / float(numBars);
float x;
if (flip) {
x = map(index, 0, numBars, centerX + (width / 4) - barWidth, centerX - (width / 4));
} else {
x = map(index, 0, numBars, centerX - (width / 4), centerX + (width / 4) - barWidth);
}
float y = -barHeight;
fill(lCyan);
noStroke();
rect(x, height/2 -y/2, barWidth, y);
}