例如,如果每个像素有200个样本(垂直线),我应该从200个样本的那部分中绘制最低和最高样本吗?或者我应该绘制低和高样本的平均值?也许两者都有不同的颜色?
答案 0 :(得分:7)
这将帮助您使用C#...
中的nAudio从音频文件生成波形using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string strPath = Server.MapPath("audio/060.mp3");
string SongID = "2";
byte[] bytes = File.ReadAllBytes(strPath);
WriteToFile(SongID,strPath, bytes);
Response.Redirect("Main.aspx");
}
private void WriteToFile(string SongID, string strPath, byte[] Buffer)
{
try
{
int samplesPerPixel = 128;
long startPosition = 0;
//FileStream newFile = new FileStream(GeneralUtils.Get_SongFilePath() + "/" + strPath, FileMode.Create);
float[] data = FloatArrayFromByteArray(Buffer);
Bitmap bmp = new Bitmap(1170, 200);
int BORDER_WIDTH = 5;
int width = bmp.Width - (2 * BORDER_WIDTH);
int height = bmp.Height - (2 * BORDER_WIDTH);
NAudio.Wave.Mp3FileReader reader = new NAudio.Wave.Mp3FileReader(strPath, wf => new NAudio.FileFormats.Mp3.DmoMp3FrameDecompressor(wf));
NAudio.Wave.WaveChannel32 channelStream = new NAudio.Wave.WaveChannel32(reader);
int bytesPerSample = (reader.WaveFormat.BitsPerSample / 8) * channelStream.WaveFormat.Channels;
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.White);
Pen pen1 = new Pen(Color.Gray);
int size = data.Length;
string hexValue1 = "#009adf";
Color colour1 = System.Drawing.ColorTranslator.FromHtml(hexValue1);
pen1.Color = colour1;
Stream wavestream = new NAudio.Wave.Mp3FileReader(strPath, wf => new NAudio.FileFormats.Mp3.DmoMp3FrameDecompressor(wf));
wavestream.Position = 0;
int bytesRead1;
byte[] waveData1 = new byte[samplesPerPixel * bytesPerSample];
wavestream.Position = startPosition + (width * bytesPerSample * samplesPerPixel);
for (float x = 0; x < width; x++)
{
short low = 0;
short high = 0;
bytesRead1 = wavestream.Read(waveData1, 0, samplesPerPixel * bytesPerSample);
if (bytesRead1 == 0)
break;
for (int n = 0; n < bytesRead1; n += 2)
{
short sample = BitConverter.ToInt16(waveData1, n);
if (sample < low) low = sample;
if (sample > high) high = sample;
}
float lowPercent = ((((float)low) - short.MinValue) / ushort.MaxValue);
float highPercent = ((((float)high) - short.MinValue) / ushort.MaxValue);
float lowValue = height * lowPercent;
float highValue = height * highPercent;
g.DrawLine(pen1, x, lowValue, x, highValue);
}
}
string filename = Server.MapPath("image/060.png");
bmp.Save(filename);
bmp.Dispose();
}
catch (Exception e)
{
}
}
public float[] FloatArrayFromStream(System.IO.MemoryStream stream)
{
return FloatArrayFromByteArray(stream.GetBuffer());
}
public float[] FloatArrayFromByteArray(byte[] input)
{
float[] output = new float[input.Length / 4];
for (int i = 0; i < output.Length; i++)
{
output[i] = BitConverter.ToSingle(input, i * 4);
}
return output;
}
}
答案 1 :(得分:6)
尝试使用dsp.stackexchange.com
每像素200个样本,您可以尝试几种方法。无论你做什么,通常最好画出0和0以上的每条垂直线,即。单独处理正负样本值。可能最简单的是计算RMS。在如此低的分辨率下,峰值可能会给出误导性的波形表示。
答案 2 :(得分:1)
答案 3 :(得分:0)
任何人都会遇到这个问题:
您可以将每个像素的样本视为缩放级别,在更高级别(缩小更多)时,您可能希望根据性能原因对其进行子采样。
您很可能需要一个适合屏幕的固定宽度来绘制和使用虚拟滚动(因此您可能不会有数百万像素的绘制区域)。
您可以通过迭代音频数据来计算每个像素的值:skip(滚动位置*每个像素的样本数)+(像素*每个像素的样本数)每个像素采样。 这允许高性能无限缩放和滚动,因为您只读取并绘制最小量以填充视图。 使用每像素的音频数据长度/样本计算滚动宽度。
音频样本通常以两种方式之一显示,即样本范围的峰值或rms值。有效值的计算方法是,对样本范围内所有值的平方求和,除以样本长度得到总和,如果是平方根则有效值(rms将略高于平均值,是感知响度的一个很好的度量)
您可以通过多种方式提高性能,例如增加子采样(导致细节丢失),限制滚动并使绘制请求可取消,以便在渲染之前进行新的滚动触发。
答案 4 :(得分:0)
如果要使音频文件填充输出图像的宽度,则仅记录它
samplesPerPixel = (reader.Length / bytesPerSample) / width ;