C # NAudio displaying ASP.net waveform without DMO or ACM

I am trying to extract a wave using ASP.net on an Azure website (which does not have ACM or DMO codecs installed), so I had to use NLayer to read the mp3 file. The code that I have below works fine with the regular DmoMp3FrameDecompressor, but when I use the NLayer decompressor, it doesn’t.

Perhaps the NLayer decompressor format is a 32-bit Float rather than a 16-bit 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
source share
1 answer

Finally figured it out. Thanks @MarkHeath for your comments and suggestions (and for creating the wonderful NAudio / NLayer libraries)!

The key is that WaveFloatTo16Provider does not have a Length attribute, so you cannot calculate the number of samples per pixel, so you need to have two loops. One that sequentially reads all the individual samples, and then another, which then groups the samples into pixels and calculates the maximum amplitude. The final loop then displays the values ​​at the pixel position and draws them onto the image. If you don't need AutoFit code, you can combine 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; 
+2
source

Source: https://habr.com/ru/post/885842/


All Articles