简体   繁体   English

分析wav并绘制图表

[英]Analyzing wav and drawing a graph

I'm trying to print out an wave from a wav file, but I'm kinda lost on how the length I should take for an sample. 我正在尝试从wav文件中打印出一个wave,但我对于我应该为样本采取的长度感到很遗憾。

this is what I would love to archieve (without the colors): 这就是我喜欢的(没有颜色): 音乐wav

so for reading in my data I use the following code: 因此,为了读取我的数据,我使用以下代码:

// first we need to read our wav file, so we can get our info:
byte[] wav = File.ReadAllBytes(filename);

// then we are going to get our file's info
info.NumChannnels = wav[22];
info.SampleRate = bytesToInt(wav[24], wav[25]);

// nr of samples is the length - the 44 bytes that where needed for the offset
int samples = (wav.Length - 44) / 2;

// if there are 2 channels, we need to devide the nr of sample in 2
if (info.NumChannnels == 2) samples /= 2;

// create the array
leftChannel = new List<float>();
if (info.NumChannnels == 2) rightChannel = new List<float>();
else rightChannel = null;

int pos = 44; // start of data chunk
for (int i = 0; i < samples; i++) {
    leftChannel.Add(bytesToFloat(wav[pos], wav[pos + 1]));
    pos += 2;
    if (info.NumChannnels == 2) {
        rightChannel.Add(bytesToFloat(wav[pos], wav[pos + 1]));
        pos += 2;
    }
}

BytesToFloat = Converts 2 bytes to an float between -1 and 1 BytesToFloat =将2个字节转换为介于-1和1之间的浮点数

So now I have 2 lists of data, but now how do I how many numbers I should take for creating 1 line? 所以现在我有2个数据列表,但现在我应该如何创建1行数?

what confuses me the most: when you play a song, you can see in most music players the following data, this is in my eyes the representation of 1 sample. 最让我困惑的是:当你播放一首歌时,你可以在大多数音乐播放器中看到以下数据,这在我眼中是1个样本的表示。 在此输入图像描述

but how do you know the value of each of those bars, and how many bars there are in a sample 但是你怎么知道每个条的值,以及样本中有多少条

Your question is about two different visualisations of audio. 您的问题是关于音频的两种不同的可视化。 To draw the waveform, the code you posted is close to being ready to draw from, but you are adding a single entry per sample to your list. 要绘制波形,您发布的代码即将准备好绘制,但您要为每个样本添加一个条目到列表中。 Since audio is often 44100 samples per second, the waveform for a 3 minute song would require almost 8 million pixels across. 由于音频通常是每秒44100个样本,因此3分钟歌曲的波形将需要近800万像素。 So what you do is batch them up. 所以你要做的就是批量处理它们。 For every say 4410 pixels (ie 100ms), find the one with the highest and lowest values, and then use that to draw the line. 对于每个说4410像素(即100ms),找到具有最高和最低值的那个,然后使用它来绘制线。 in fact, you can usually get away with just finding the max Abs value, and drawing a symetrical waveform. 实际上,通常只需找到最大Abs值并绘制对称波形即可。

Here is some code to draw a basic WaveForm of an audio file in WPF, using NAudio for easier access to the sample values (it can do WAV or MP3 files). 下面是一些在WPF中绘制音频文件的基本WaveForm的代码,使用NAudio可以更方便地访问样本值(它可以执行WAV或MP3文件)。 I haven't included any splitting out of left and right channels, but that should be fairly easy to add: 我没有包括任何拆分左右声道,但这应该相当容易添加:

var window = new Window();
var canvas = new Canvas();
using(var reader = new AudioFileReader(file))
{
    var samples = reader.Length / (reader.WaveFormat.Channels * reader.WaveFormat.BitsPerSample / 8);
    var f = 0.0f;
    var max = 0.0f;
    // waveform will be a maximum of 4000 pixels wide:
    var batch = (int)Math.Max(40, samples / 4000);
    var mid = 100;
    var yScale = 100;
    float[] buffer = new float[batch];
    int read;
    var xPos = 0;
    while((read = reader.Read(buffer,0,batch)) == batch)
    {
        for(int n = 0; n < read; n++)
        {
            max = Math.Max(Math.Abs(buffer[n]), max);
        }
        var line = new Line();
        line.X1 = xPos;
        line.X2 = xPos;
        line.Y1 = mid + (max * yScale); 
        line.Y2 = mid - (max * yScale);
        line.StrokeThickness = 1;
        line.Stroke = Brushes.DarkGray;
        canvas.Children.Add(line);
        max = 0;    
        xPos++;
    }
    canvas.Width = xPos;
    canvas.Height = mid * 2;
}
window.Height = 260;
var scrollViewer = new ScrollViewer();
scrollViewer.Content = canvas;
scrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
window.Content = scrollViewer;
window.ShowDialog();

The second visualisation is sometimes called a spectogram or a spectrum analyser. 第二种可视化有时被称为谱图或频谱分析仪。 It does not represent 1 sample, but represents the frequencies present in a block of samples. 它不代表1个样本,而是表示样本块中存在的频率。 To get at this information you need to pass your samples through a Fast Fourier Transform (FFT). 要获得此信息,您需要通过快速傅里叶变换(FFT)传递样本。 Usually you pass through blocks of 1024 samples (it should be a power of 2). 通常你会通过1024个样本的块(它应该是2的幂)。 Unforunately FFTs can be tricky to work with if you are new to DSP, as there are several things you need to learn how to do: 不幸的是,如果您不熟悉DSP,FFT可能很难处理,因为您需要学习如何做以下几件事:

  • apply a windowing function 应用窗口函数
  • get your audio into the right input format (many FFTs expect input as complex numbers) 将您的音频转换为正确的输入格式(许多FFT期望输入为复数)
  • work out which bin numbers correspond to which frequency, 找出哪个bin编号对应哪个频率,
  • find the magnitude of each bin and convert it to a decibel scale. 找到每个bin的大小并将其转换为分贝标度。

You should be able to find further information on each of those topics here on StackOverflow. 您应该能够在StackOverflow上找到有关这些主题的更多信息。 I've written a bit about how you can use FFT in C# in this article . 我在本文中写了一些关于如何在C#中使用FFT的文章

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM