2016-09-08 4 views
0

J'essaye de dessiner une forme d'onde en utilisant ASP.net sur un site web Azure (qui n'a pas les codecs ACM ou DMO installés), donc j'ai dû utilisez NLayer pour lire le fichier mp3. Le code que j'ai ci-dessous fonctionne parfaitement avec le DmoMp3FrameDecompressor habituel, mais quand j'utilise le décompresseur NLayer, ce n'est pas le cas.C# NAudio rendu d'une forme d'onde ASP.net sans DMO ou ACM

Peut-être que le format du décompresseur NLayer est 32 bits Float et non 16 bits 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; 
    } 
} 

Répondre

2

Enfin compris. Merci @MarkHeath pour vos commentaires et suggestions (et pour la construction des incroyables bibliothèques NAudio/NLayer)! La clé est que le WaveFloatTo16Provider n'a pas d'attribut Length, donc vous ne pouvez pas calculer le nombre d'échantillons par pixel, vous devez donc avoir deux boucles. Une qui lit séquentiellement tous les échantillons individuels puis une autre qui regroupe ensuite les échantillons par pixel et calcule l'amplitude maximale. La boucle finale mappe alors les valeurs aux positions de pixel et les dessine à une image. Si vous n'avez pas besoin du code AutoFit, vous pouvez fusionner les deuxième et troisième boucles.

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

Merci à @Illaya pour les blocs de construction de base de ce code! http://stackoverflow.com/questions/11451707/how-to-render-audio-waveform/20190230#20190230 – Shiroy