我正在尝试使用Azure网站上的ASP.net绘制波形(没有安装ACM或DMO编解码器),所以我不得不使用NLayer来读取mp3文件。我下面的代码与常规的DmoMp3FrameDecompressor完美配合,但是当我使用NLayer解压缩器时,它没有。
NLayer解压缩器的格式可能是32位浮点数而不是16位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;
}
}
答案 0 :(得分:2)
终于明白了。感谢@MarkHeath的意见和建议(以及构建令人惊叹的NAudio / NLayer库)!
关键是WaveFloatTo16Provider
没有Length
属性,因此您无法计算每个像素的样本数,因此您需要有两个循环。一个顺序读取所有单个样本然后另一个然后对每个像素分组样本,并计算最大幅度。最后一个循环然后将值映射到像素位置并将它们绘制到图像。如果您不需要AutoFit
代码,则可以合并第二个和第三个循环。
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;