这次我们来尝试一下真正的答案。 :-)
这个问题太复杂了,无法用这个空间中的所有代码给出完整的解决方案,但我将使用伪代码并假设您有一些库可以对样本块进行窗口化并计算 FFT。
这类似于构建波形显示。当您构建波形显示时,您可以确定在当前缩放级别下“适合”单个水平像素的样本数量(给定 X 滚动位置),计算该段的最小和最大样本值,并为您提供该波形像素的最小/最大 Y 位置。 (这实际上有点简化,我当时已经编写了波形渲染代码,但这是一个很好的近似值。)
要使用频率对波进行着色,您需要使用具有较小箱的短时 FFT 来预处理波数据,并为每个箱确定主要频率是什么,然后将其映射到光谱上从红色到紫色的颜色。
假设您的音频样本位于名为samples
,这是伪代码。
// sample rate
float fS = 44100;
// size of frame for analysis, you may want to play with this
float frameMsec = 10;
// samples in a frame
int frameSamples = (int)(fS / (frameMsec * 1000));
// how much overlap each frame, you may want to play with this one too
int overlapSamples = (frameSamples / 2);
// number of samples in the sound file
int numSamples = ...;
// input array of samples
float inSamples[] = ...;
// color to use for each frame
RGB outColors[] = new float[(numSamples / frameOverlap) + 1];
// scratch buffers
float tmpWindow[frameSamples];
float tmpFFT[frameSamples];
// helper function to apply a windowing function to a frame of samples
void calcWindow(float* dst, const float* src, int size);
// helper function to compute FFT
void fft(float* dst, const float* src, int size);
// find the index of array element with the highest absolute value
// probably want to take some kind of moving average of buf[i]^2
// and return the maximum found
int maxFreqIndex(const float* buf, int size);
// map a frequency to a color, red = lower freq -> violet = high freq
RGB freqToColor(int i);
for (int i = 0, outptr = 0; i < numSamples; i += frameOverlap, outptr++)
{
// window another frame for FFT
calcWindow(tmpWindow, &inSamples[i], frameSamples);
// compute the FFT on the next frame
fft(tmpFFT, tmpWindow, frameSamples);
// which frequency is the highest?
int freqIndex = maxFreqIndex(tmpFFT, frameSamples);
// map to color
outColor[outptr] = freqToColor(freqIndex);
}
这将为您提供一个 RGB 数组,您可以在放大和缩小波形显示时放大和缩小该数组。当您缩放时,您可能希望对相邻帧的 RGB 值进行平均,以便为您提供整体视图。
我希望这有帮助。