C#NAudio在没有DMO或ACM的情况下渲染波形ASP.net [英] C# NAudio rendering a waveform ASP.net without DMO or ACM
问题描述
我试图在Azure网站(未安装ACM或DMO编解码器)上使用ASP.net绘制波形,因此我不得不使用NLayer读取mp3文件.我下面的代码与常规DmoMp3FrameDecompressor完美搭配,但是当我使用NLayer解压缩器时却不能.
I'm trying to draw out a waveform using ASP.net on an Azure Website (which doesn't have the ACM or DMO codecs installed), so I had to use NLayer to read the mp3 file. The code I have below works perfectly with the regular DmoMp3FrameDecompressor, but when I use the NLayer decompressor it doesn't.
也许NLayer解压缩器的格式是32位Float,而不是16位PCM.
Maybe the format of the NLayer decompressor is 32bit Float and not 16bit PCM.
byte[] data = new WebClient().DownloadData(URL);
int maxAmplitude = 0;
short[,] dataArray = new short[Width, 2];
//using (Mp3FileReader wavestream = new Mp3FileReader(new MemoryStream(data), wf => new DmoMp3FrameDecompressor(wf)))
using (Mp3FileReader wavestream = new Mp3FileReader(new MemoryStream(data), new Mp3FileReader.FrameDecompressorBuilder(waveFormat => new NLayer.NAudioSupport.Mp3FrameDecompressor(waveFormat))))
{
WaveChannel32 channelStream = new WaveChannel32(wavestream);
int bytesPerSample = (wavestream.WaveFormat.BitsPerSample / 8) * channelStream.WaveFormat.Channels;
wavestream.Position = 0;
long lenSamples = wavestream.Length / bytesPerSample;
int samplesPerPixel = (int)(lenSamples / Width);
int bytesRead1;
byte[] waveData1 = new byte[samplesPerPixel * bytesPerSample];
// First get all the data
for (int 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;
}
if (-low > maxAmplitude) maxAmplitude = -low;
if (high > maxAmplitude) maxAmplitude = high;
dataArray[x, 0] = low;
dataArray[x, 1] = high;
}
}
推荐答案
最后弄清楚了.感谢@MarkHeath提出您的意见和建议(以及构建了令人惊叹的NAudio/NLayer库)!
Finally figured it out. Thanks @MarkHeath for your comments and suggestions (and for building the amazing NAudio / NLayer libraries)!
关键是WaveFloatTo16Provider
没有Length
属性,因此您无法计算每个像素的样本数,因此需要两个循环.一个依次读取所有单个样本,然后另一个按每个像素对样本进行分组,并计算最大振幅.然后,最后的循环将这些值映射到像素位置,并将它们绘制到图像上.如果不需要AutoFit
代码,则可以合并第二个和第三个循环.
The key is that the WaveFloatTo16Provider
doesn't have a Length
attribute, so you can't compute the number of samples per pixel, so you need to have two loops. One which sequentially reads all the individual samples and then another which then groups the samples per pixel, and calculates the max amplitude. The final loop then maps the values to pixel positions and draws them to an image. If you don't need the AutoFit
code, then you can merge the second and third loops.
Bitmap bmp = new Bitmap(Width, Height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.White);
Pen pen1 = new Pen(Color.Gray);
string hexValue = "#" + sColor;
Color colour1 = System.Drawing.ColorTranslator.FromHtml(hexValue);
pen1.Color = colour1;
int maxAmplitude = 0;
short[,] dataArray = new short[Width, 2];
using (Mp3FileReader wavestreamFloat = new Mp3FileReader(
new MemoryStream(new WebClient().DownloadData(URL)),
new Mp3FileReader.FrameDecompressorBuilder(
waveFormat => new NLayer.NAudioSupport.Mp3FrameDecompressorwaveFormat))))
{
IWaveProvider stream16 = new WaveFloatTo16Provider(wavestreamFloat);
int bytesPerSample = (stream16.WaveFormat.BitsPerSample / 8) * stream16.WaveFormat.Channels;
int bytesRead = 0;
byte[] buffer = new byte[8192];
List<short> rawDataArray = new List<short>();
do
{
bytesRead = stream16.Read(buffer, 0, buffer.Length);
for (int n = 0; n < bytesRead; n += bytesPerSample)
{
short sample = BitConverter.ToInt16(buffer, n);
rawDataArray.Add(sample);
}
} while (bytesRead != 0);
// Now that we have all the samples
long lenSamples = rawDataArray.Count;
int samplesPerPixel = (int)(lenSamples / Width);
int nCounter = 0;
for (int x = 0; x < Width; x++)
{
short low = 0;
short high = 0;
for (int n = 0; n < samplesPerPixel; n++)
{
short sample = rawDataArray[nCounter++];
if (sample < low) low = sample;
if (sample > high) high = sample;
}
if (-low > maxAmplitude) maxAmplitude = -low;
if (high > maxAmplitude) maxAmplitude = high;
dataArray[x, 0] = low;
dataArray[x, 1] = high;
}
// Now lay it out on the image. This is where we resize it to AutoFit.
for (int x = 0; x < Width; x++)
{
short low = dataArray[x, 0];
short high = dataArray[x, 1];
if (AutoFit)
{
low = (short)((int)low * (int)short.MaxValue / (int)maxAmplitude);
high = (short)((int)high * (int)short.MaxValue / (int)maxAmplitude);
}
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);
}
g.Flush();
}
}
return bmp;
这篇关于C#NAudio在没有DMO或ACM的情况下渲染波形ASP.net的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!