2016-09-08 4 views
0

Я пытаюсь извлечь волну с использованием ASP.net на веб-сайте Azure (на котором не установлены кодеки ACM или DMO), поэтому мне пришлось используйте NLayer для чтения mp3-файла. Код, который у меня ниже, отлично работает с обычным DmoMp3FrameDecompressor, но когда я использую декомпрессор NLayer, это не так.C# NAudio, отображающий форму волны ASP.net без DMO или ACM

Возможно, формат декомпрессора NLayer - это 32-битный Float, а не 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; 
    } 
} 

ответ

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; 
+0

Благодаря @Illaya для основных строительных блоков этого кода! http://stackoverflow.com/questions/11451707/how-to-render-audio-waveform/20190230#20190230 – Shiroy