2016-12-07 2 views
0

J'essaie d'analyser un fichier wav. Je ne suis pas sûr s'il peut y avoir plusieurs morceaux de données dans un fichier wav, mais je supposais initialement qu'il y en avait seulement 1 puisque la description du format de fichier wav que je lisais indiquait seulement 1.Qu'est-ce que je fais de mal lors de l'analyse d'un fichier wav?

Mais j'ai remarqué que le subchunk2size était très petit (comme 26) lorsque le fichier wav analysé était quelque chose comme 36MB et le taux d'échantillonnage était 44100.

Alors j'ai essayé d'analyser en supposant qu'il y avait plusieurs morceaux, mais après le 1er morceau, il n'y avait pas subchunk2id être trouvé.

Pour aller morceau par morceau, j'utilisais le code ci-dessous

int chunkSize = System.BitConverter.ToInt32(strm, 40); 
int widx = 44; //wav data starts at the 44th byte 
//strm is a byte array of the wav file 
while(widx < strm.Length) 
{ 
    widx += chunkSize; 
    if(widx < 1000) 
    { 
     //log "data" or "100 97 116 97" for the subchunkid 
     //This is only getting printed the 1st time though. All prints after that are garbage 
     Debug.Log(strm[widx] + " " + strm[widx+1] + " " + strm[widx+2] + " " + strm[widx+3]); 
    } 
    if(widx + 8 < strm.Length) 
    { 
     widx += 4; 
     chunkSize = System.BitConverter.ToInt32(strm, widx); 
     widx += 4; 
    }else 
    { 
     widx += 8; 
    } 
} 
+0

Il est très vague de le mentionner n'a pas fonctionné/n'a pas fonctionné. S'il vous plaît mentionner vos exceptions si un ou des détails liés à un bug. –

+0

J'ai mentionné ces choses. Je ne vois pas les "données" dans le tampon après le 1er et ma taille de subchunk2 est trop petite. – Thundercleez

+0

pouvez-vous expliquer comment vous vous attendez à ce que les données soient formatées? Du code il ressemble à: en-tête (40): chunksize (4) :(données chunksize long) :(4 octets de quelque chose?) :(nouvelle taille de morceau) :(data chunksize long): etc ... est-ce exact? – meganaut

Répondre

0

Dans la référence que vous avez ajouté que je ne vois aucune mention de la taille de bloc étant répétée pour chaque bloc de données ...

Essayez quelque chose comme ceci:

int chunkSize = System.BitConverter.ToInt32(strm, 40); 
int widx = 44; //wav data starts at the 44th byte 
//strm is a byte array of the wav file 
while(widx < strm.Length) 
{ 
    if(widx < 1000) 
    { 
     //log "data" or "100 97 116 97" for the subchunkid 
     //This is only getting printed the 1st time though. All prints after that are garbage 
     Debug.Log(strm[widx] + " " + strm[widx+1] + " " + strm[widx+2] + " " + strm[widx+3]); 
    }  
    widx += chunkSize; 
} 
+0

Oui, je sais que cela ne mentionne que le 1, mais je ne savais pas s'il pouvait y avoir d'autres morceaux.Cela ne me ressemble pas parce que j'ai simplement essayé de rechercher l'ensemble des données pour un autre identificateur de bloc de "données" et je n'ai pas pu en trouver un. Mais je ne comprends pas pourquoi le subchunk2size est seulement 26 quand le dossier est 36MB. Ça devrait être beaucoup plus grand que ça. Je me demande s'il y a quelque chose qui cloche avec le fichier wav puisque la 1ère taille de bloc est également fausse (j'obtiens 0xffffffff). J'utilise ffmpeg pour faire le fichier wav, donc je pourrais manquer une option ou quelque chose? – Thundercleez

+0

@Thundercleez Il semble que le fichier soit corrompu. Essayez de sortir le ChunkSize (octets 4 - 8). il devrait égaler 36 + SubChunk2Size. – meganaut

+0

Il est dit au bas de ce document, que les fichiers WAV utilisent généralement un format plus ancien. Le lien vers l'ancien format est malheureusement rompu. Je pense que vous devriez jeter un oeil dans le fichier sur les données et vous assurer que tout est là où vous vous attendez. Si ce n'est pas il pourrait être préférable de rechercher le mot "données" (prévu à 36-40) et ensuite travailler à partir de là. – meganaut

1

un fichier .wav a 3 morceaux: Chaque morceau a une taille de 4 octets

Le premier segment est le "RIFF" -chunk. Il comprend 8 octets la taille du fichier (4 octets) et le nom du format (4 octets, généralement "WAVE").

Le tronçon suivant est le "fmt" -chunk (l'espace dans le nom de tronçon est important). Il comprend le format audio (2 octets), le nombre de canaux (2 octets), le taux d'échantillonnage (4 octets), le taux d'octets (4 octets), le blockalign (2 octets) et les bits par échantillon (2 octets) .

Le troisième et dernier segment est le bloc de données. Voici les données réelles et les amplitudes des échantillons. Il inclut 4 octets pour le datasize, qui est le nombre d'octets pour les données.

Vous trouverez des explications supplémentaires sur les propriétés d'un fichier .wav here.

De cette connaissance j'ai déjà créé la classe suivante:

public sealed class WaveFile 
{ 
    //privates 
    private int fileSize; 
    private string format; 
    private int fmtChunkSize; 
    private int audioFormat; 
    private int numChannels; 
    private int sampleRate; 
    private int byteRate; 
    private int blockAlign; 
    private int bitsPerSample; 
    private int dataSize; 
    private int[][] data;//One array per channel 

    //publics 
    public int FileSize => fileSize; 
    public string Format => format; 
    public int FmtChunkSize => fmtChunkSize; 
    public int AudioFormat => audioFormat; 
    public int NumChannels => numChannels; 
    public int SampleRate => sampleRate; 
    public int ByteRate => byteRate; 
    public int BitsPerSample => bitsPerSample; 
    public int DataSize => dataSize; 
    public int[][] Data => data; 

    public WaveFile(string path) 
    { 
     FileStream fs = File.OpenRead(path); 
     LoadChunk(fs); //read RIFF Chunk 
     LoadChunk(fs); //read fmt Chunk 
     LoadChunk(fs); //read data Chunk 
     fs.Close(); 
    } 

    private void LoadChunk(FileStream fs) 
    { 
     ASCIIEncoding Encoder = new ASCIIEncoding(); 
     byte[] bChunkID = new byte[4]; 

     fs.Read(bChunkID, 0, 4); 
     string sChunkID = Encoder.GetString(bChunkID); 

     byte[] ChunkSize = new byte[4]; 

     fs.Read(ChunkSize, 0, 4); 

     if (sChunkID.Equals("RIFF")) 
     { 
      fileSize = BitConverter.ToInt32(ChunkSize, 0); 

      byte[] Format = new byte[4]; 
      fs.Read(Format, 0, 4); 
      this.format = Encoder.GetString(Format); 
     } 

     if (sChunkID.Equals("fmt ")) 
     { 
      fmtChunkSize = BitConverter.ToInt32(ChunkSize, 0); 
      byte[] audioFormat = new byte[2]; 
      fs.Read(audioFormat, 0, 2); 
      this.audioFormat = BitConverter.ToInt16(audioFormat, 0); 
      byte[] numChannels = new byte[2]; 
      fs.Read(numChannels, 0, 2); 
      this.numChannels = BitConverter.ToInt16(numChannels, 0); 
      byte[] sampleRate = new byte[4]; 
      fs.Read(sampleRate, 0, 4); 
      this.sampleRate = BitConverter.ToInt32(sampleRate, 0); 
      byte[] byteRate = new byte[4]; 
      fs.Read(byteRate, 0, 4); 
      this.byteRate = BitConverter.ToInt32(byteRate, 0); 
      byte[] blockAlign = new byte[2]; 
      fs.Read(blockAlign, 0, 2); 
      this.blockAlign = BitConverter.ToInt16(blockAlign, 0); 
      byte[] bitsPerSample = new byte[2]; 
      fs.Read(bitsPerSample, 0, 2); 
      this.bitsPerSample = BitConverter.ToInt16(bitsPerSample, 0); 
     } 

     if (sChunkID.Equals("data")) 
     { 
      dataSize = BitConverter.ToInt32(ChunkSize, 0); 
      data = new int[this.numChannels][]; 

      byte[] temp = new byte[dataSize]; 

      for (int i = 0; i < this.numChannels; i++) 
      { 
       data[i] = new int[this.dataSize/(numChannels * bitsPerSample/8)]; 
      } 

      for (int i = 0; i < data[0].Length; i++) 
      { 
       for (int j = 0; j < numChannels; j++) 
       { 
        if (fs.Read(temp, 0, blockAlign/numChannels) > 0) 
        { 
         if (blockAlign/numChannels == 2) 
         { data[j][i] = BitConverter.ToInt32(temp, 0); } 
         else 
         { data[j][i] = BitConverter.ToInt16(temp, 0); } 

        } 
       } 
      } 
     } 
    } 
} 

-directives nécessaires pour l'utilisation:

using System; 
using System.IO; 
using System.Text; 

Cette classe lit tous les morceaux octet par octet et définit les propriétés. Il vous suffit d'initialiser cette classe et elle renverra toutes les propriétés de votre fichier wave sélectionné.