2012-05-16 2 views
1

설명하기가 너무 복잡해 질 수는 있지만 간단하지만 유익한 정보로 유지하려고 노력할 것입니다. C# .net으로 작성된 내 프로그램은 2 초 동안 마이크를 모니터링하고 샘플에서 최대 값을 반환합니다. WinMil.dll에서 소리 등을 생성하는 방법에 능숙하지는 않지만 내 프로그램은 NAudio와 CodeProject의 다른 프로젝트를 기반으로 파도를 시각화합니다. 내가 사용하고 웨이브 형식이 웨이브에서 숫자가 커지지 않게하는 방법

//WaveIn.cs 
    private WaveFormat Format= new WaveFormat(8000, 16,1); 
    //waveFormat.cs 
[StructLayout(LayoutKind.Sequential)] 
public class WaveFormat 
{ 
    public short wFormatTag; 
    public short nChannels; 
    public int nSamplesPerSec; 
    public int nAvgBytesPerSec; 
    public short nBlockAlign; 
    public short wBitsPerSample; 
    public short cbSize; 

    public WaveFormat(int rate, int bits, short channels) 
    { 
     wFormatTag = (short)WaveFormats.Pcm; 
     nChannels = channels; 
     nSamplesPerSec = rate; 
     wBitsPerSample = (short)bits; 
     cbSize = 0; 

     nBlockAlign = (short)(nChannels * (wBitsPerSample/8)); 
     nAvgBytesPerSec = nSamplesPerSec * nBlockAlign; 
    } 

(난 그냥이를 게시하여, 내 문제를 발견 할 수 있습니다 생각하지만 난 여전히 물어거야)

그래서 다음 카드를 설치 이벤트를

을 내 웨이브 파일의 최대 사운드 레벨. 소스 코드가 올바르게 이해되면 버퍼가 가득 차면 실행됩니다. 여기에 내가 여기이 테스트에서 모니터 할 때 나는 소음 수준을 유지하는 경우 때문에 충돌하지 않습니다 그 코드

private void CallBack(IntPtr waveInHandle, WaveMessage message, int userData, ref WaveHeader waveHeader, IntPtr reserved) 
    { 
     if (message == WaveMessage.WIM_DATA) 
     { 
      GCHandle hBuffer = (GCHandle)waveHeader.dwUser; 
      WaveInBuffer buffer = (WaveInBuffer)hBuffer.Target; 
      Exception exception = null; 
      if (DataAvailable != null) 
      { 
       DataAvailable(buffer.Data, buffer.BytesRecorded); 
      } 
      if (MaxSoundLevel != null) //FOLLOW THIS ONE 
      { 
       byte[] waveStream = new byte[buffer.BytesRecorded]; 
       Marshal.Copy(buffer.Data, waveStream, 0, buffer.BytesRecorded); 
       MaxSoundLevel(GetMaxSound(GetWaveChannels(waveStream))); 
      } 
      if (recording) 
      { 
       try 
       { 
        buffer.Reuse(); 
       } 
       catch (Exception e) 
       { 
        recording = false; 
        exception = e; 
       } 
      } 
     } 
    } 
    private short[] GetWaveChannels(byte[] waveStream) 
    { 
     short[] monoWave = new short[waveStream.Length/2]; 
     int h=0; 
     for (int i = 0 ; i < waveStream.Length; i += 2) 
     { 
      monoWave[h] = BitConverter.ToInt16(waveStream, i); 
      h++; 
     } 
     return monoWave; 
    } 

    private int GetMaxSound(short[] wave) 
    { 
     int maxSound = 0; 
     for (int i = 0; i < wave.Length; i++) 
     { 
      maxSound = Math.Max(maxSound, Math.Abs(wave[i])); 
     } 
     return maxSound; 
    } 

가 "정상"

[Test] 
    public void TestSound() 
    { 
     var waveIn = new WaveIn(); 
     waveIn.MaxSoundLevel += new WaveIn.MaxSoundHandler(waveIn_MaxSoundLevel); 
     waveIn.StartRecording(); 
     Console.WriteLine("Starting to record"); 
     Thread.Sleep(4800); //record for 4.8 seconds. 
     waveIn.StopRecording(); 
     Console.WriteLine("Done Recording"); 

    } 
    void waveIn_MaxSoundLevel(int MaxSound) 
    { 
     Console.WriteLine("MaxSound:{0}", MaxSound); 
    } 

여기 내 출력

MaxSound입니다 28 MaxSound 24 MaxSound 31 MaxSound 17 MaxSound : 18,760

되지 않은 전 ception : System.OverflowException : 2 진수의 최소값을 부정하면 유효하지 않습니다.

나는 한번 MaxSound : 32767 (0x7FFF)을 주었다.

그래서 내 문제가 32 비트 숫자를 16 비트 숫자로 변환하려고 시도하는 동안 거짓말을 했으므로 GetMaxSound를 short에서 int로 전환했습니다. 그래서 나는 모른다. 나는 곤두박질 친다. 그런데 왜이 문제가 있습니까? 내 웨이브가 최대 32,767이고 winmm.dll이이를 알고 그것을 지나치지 않는다고 제안합니까? 그리고이 문제가 발생하지 않는다면 단지 2 바이트의 데이터를 short로 변환하기 때문에? 제발 도와주세요 :)

+0

을한다 하나의 웨이브에 대해 시스템이 성공적으로 실행 되었기 때문에 32,767 "**이라는 결과가 다음 웨이브에 적용될 것이라는 의미는 아니며 시스템이 동일한 파일을 여러 번 실행하는 경우 다르게 작동한다고 말하는 것입니까? 또한 당신은'GetMaxSound'를 바꾸었지만 당신은'BitConverter.ToInt16'에서 떠났습니다. –

+1

@ JoshuaDrake이 웨이브는 웨이브 파일이 아니라 내 마이크에서 가져온 것입니다. 내 마이크에서 시끄러운 소리를 내지 않으면 소리가 나지 않습니다. 'GetMaxSound'를 사용하여 연주하는 것은 그것이 설정과 충돌 할 수 있음을 완전히 이해하지 못하는 것입니다. 그것은 비트 컨버터 오버플로 결코 실행해서는 안된다 ??? 그리고 32767 또는 -32768을 돌려 주면 안됩니다 ... 잠시 복근을 사용하겠습니다. 어떤 32768 오버플로 허 ... BRB –

+1

그게 다야! 나는 내 웨이브에 int를 던져서 32768에 맥스 아웃한다. :) maxSound = Math.Max ​​(maxSound, Math.Abs ​​((int) wave [i]))'는 해결책이다. 나는 그것을 불어서 다음과 같은 결과를 얻었다.MaxSound : 399 MaxSound 320 MaxSound 264 MaxSound : 32768 MaxSound : 32768 MaxSound : 32768 MaxSound : 32768 MaxSound : 32768 MaxSound : 32768 MaxSound : 32768 MaxSound : 0 MaxSound : 32768 MaxSound : 32768 –

답변

0

내 솔루션은이 문제를 조사하는 사람들에게 매우 자연 스럽습니다. 16 비트 부호있는 숫자의 최대 양수 값은 32767입니다. 최대 음수는 -32768입니다. 32768의 절대 값을 가져 와서 16 비트 숫자에 넣으려고하면 오버 플로우 예외가 발생합니다. 그래서 해결책은 절대 값을 취하기 전에 짧은 값을 32 비트 숫자로 변환하는 것입니다. 여기 ** "파도가 최대의 제안 것을 나는 아마 USHORT 사용하여뿐만 아니라 부호없는 숫자로 붙어 있었다

private int GetMaxSound(short[] wave) 
    { 
     int maxSound = 0; 
     for (int i = 0; i < wave.Length; i++) 
     { 
      maxSound = Math.Max(maxSound, Math.Abs((int)wave[i])); 
     } 
     return maxSound; 
    } 

수정 된 기능이지만 Math.Abs는 수집 할 것과

관련 문제