2017-12-05 19 views
0

WAV 파일을 C#의 버퍼 배열로 읽으려고하는데 문제가 있습니다. 오디오 파일을 관리하기 위해 파일 스트림을 사용하고 있습니다. 여기에 제가 가지고있는 것이 있습니다 ...C#의 배열로 오디오 파일을 읽는 방법

FileStream WAVFile = new FileStream(@"test.wav", FileMode.Open); 

     //Buffer for the wave file... 
     BinaryReader WAVreader = new BinaryReader(WAVFile); 

     //Read information from the header. 
     chunkID = WAVreader.ReadInt32(); 
     chunkSize = WAVreader.ReadInt32(); 
     RiffFormat = WAVreader.ReadInt32(); 

     ... 

     channels = WAVreader.ReadInt16(); 
     samplerate = WAVreader.ReadInt32(); 
     byteRate = WAVreader.ReadInt32(); 
     blockAllign = WAVreader.ReadInt16(); 
     bitsPerSample = WAVreader.ReadInt16(); 

     dataID = WAVreader.ReadInt32(); 
     dataSize = WAVreader.ReadInt32(); 

위의 내용은 WAV 파일 헤더의 데이터를 읽는 것입니다. 그렇다면 나는 이것을 가지고 있습니다 :

musicalData = WAVreader.ReadBytes(dataSize); 

... 실제 샘플 데이터를 읽으려면 ... 이것은 오디오의 60 초 동안 26 바이트에 불과합니다. 이 올바른지?

byte [] 배열을 double []으로 변환하는 방법은 무엇입니까?

+0

26 바이트 크기를 볼 때 즉시 잘못 알아야합니다. – Steve

+0

데이터 ID의 값을 확인하십시오. 그것은 "fmt"문자를 포함해야합니다. 32 비트 int로 읽으면 다음과 같은 내용이 포함될 것임을 의미합니다. 0x20 0x74 0x6d 0x66. 그러면 올바른 위치에서 dataSize 값을 읽는 지 확인할 수 있습니다. – Olan

답변

0

WAVE 파일 처리를 시작한 지 10 ~ 15 년이되었지만 대부분의 사람들이 웨이브 파일을 PCM 인코딩 오디오 데이터에 이어 간단한 고정 크기 헤더로 가져 오는 첫 인상과 달리 WAVE 파일은 복잡한 RIFF 형식 파일.

RIFF 파일 처리 및 다양한 경우를 다시 처리하는 대신 RIFF 파일 형식을 처리하는 API에 대한 interop 및 호출을 사용하는 것이 좋습니다.

this example에 데이터 버퍼 (및 어떤 버퍼가 있는지에 대한 메타 정보)를 열고 얻는 방법의 예제를 볼 수 있습니다. C++이지만 적절한 오디오 버퍼를 사용하려면 mmioOpen, mmioRead, mmioDescend, mmioAscend API를 사용해야합니다.

0

이 코드는 트릭을 수행해야합니다. 그것은 웨이브 파일을 정규화 된 double 배열 (-1 대 1)로 변환하지만 int/short 배열로 바꾸는 것은 간단합니다 (/32768.0 비트를 제거하고 대신 32768을 추가하십시오). 로드 된 wav 파일이 모노 인 경우 right [] 배열이 null로 설정됩니다.

완전히 불완전하다는 주장은 할 수 없지만 (65536 개의 샘플 배열을 만들고 -1에서 1로 웨이브를 생성 한 후에는 샘플이 전혀 나타나지 않습니다. 천장이나 바닥. 당신이 다음 WAV 파일을 가정, 플러그인을 사용하고자하는 경우

// convert two bytes to one double in the range -1 to 1 
static double bytesToDouble(byte firstByte, byte secondByte) 
{ 
    // convert two bytes to one short (little endian) 
    short s = (secondByte << 8) | firstByte; 

    // convert to range from -1 to (just below) 1 
    return s/32768.0; 
} 

// Returns left and right double arrays. 'right' will be null if sound is mono. 
public void openWav(string filename, out double[] left, out double[] right) 
{ 
    byte[] wav = File.ReadAllBytes(filename); 

    // Determine if mono or stereo 
    int channels = wav[22];  // Forget byte 23 as 99.999% of WAVs are 1 or 2 channels 

    // Get past all the other sub chunks to get to the data subchunk: 
    int pos = 12; // First Subchunk ID from 12 to 16 

    // Keep iterating until we find the data chunk (i.e. 64 61 74 61 ...... (i.e. 100 97 116 97 in decimal)) 
    while(!(wav[pos]==100 && wav[pos+1]==97 && wav[pos+2]==116 && wav[pos+3]==97)) 
    { 
     pos += 4; 
     int chunkSize = wav[pos] + wav[pos + 1] * 256 + wav[pos + 2] * 65536 + wav[pos + 3] * 16777216; 
     pos += 4 + chunkSize; 
    } 

    pos += 8; 

    // Pos is now positioned to start of actual sound data. 
    int samples = (wav.Length - pos)/2;  // 2 bytes per sample (16 bit sound mono) 

    if (channels == 2) 
    { 
     samples /= 2;  // 4 bytes per sample (16 bit stereo) 
    } 

    // Allocate memory (right will be null if only mono sound) 
    left = new double[samples]; 

    if (channels == 2) 
    { 
     right = new double[samples]; 
    } 
    else 
    { 
     right = null; 
    } 

    // Write to double array/s: 
    int i=0; 
    while (pos < length) 
    { 
     left[i] = bytesToDouble(wav[pos], wav[pos + 1]); 
     pos += 2; 

     if (channels == 2) 
     { 
      right[i] = bytesToDouble(wav[pos], wav[pos + 1]); 
      pos += 2; 
     } 

     i++; 
    } 
} 

는 (가장 일반적입니다) 16 비트 PCM, 당신은 바이트 배열로 그것을 읽어 NAudio를 사용하고, 다음에 있음을 복사 할 수 있습니다 포함되어 있습니다 편의상 16 비트 정수 배열. 스테레오 인 경우 샘플이 왼쪽, 오른쪽으로 인터리브됩니다.

using (WaveFileReader reader = new WaveFileReader("myfile.wav")) 
{ 
    Assert.AreEqual(16, reader.WaveFormat.BitsPerSample, "Only works with 16 bit audio"); 
    byte[] buffer = new byte[reader.Length]; 
    int read = reader.Read(buffer, 0, buffer.Length); 
    short[] sampleBuffer = new short[read/2]; 
    Buffer.BlockCopy(buffer, 0, sampleBuffer, 0, read); 
} 

개인적으로 가능한 한 제 3 자 라이브러리를 사용하지 마십시오. 그러나 코드를 더 잘 보이게 처리하려면이 옵션을 그대로 사용하십시오.

+0

26 바이트를 반환하는 이유를 알고 있습니까? 30 초 동안 오디오가 제대로 표시되지 않습니다. – Bluehand