1

したがって、これは説明が非常に複雑になる可能性がありますが、シンプルでありながら有益な情報を提供するように努めます。C#.netで記述された私のプログラムは、マイクを2秒間監視し、サンプルから最大値を返します。私はwinmm.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;
    }

(これを投稿することで、問題を見つけたばかりかもしれませんが、それでも質問します)

そこで、waveinファイルで最大サウンドレベルのイベントを設定します。ソースコードを正しく理解していれば、バッファがいっぱいになると起動します。これがそのコードです

    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:18760

未処理の例外:System.OverflowException:2の補数の最小値を否定することは無効です。

私はかつて私にMaxSound:32767(0x7FFF)を与えるためにそれを手に入れました。

だから私は私の問題が32ビットの数値を16ビットの数値に変換しようとしていることにあると考えました。それが私がGetMaxSoundをshortからintに切り替えた理由です。だからわかりません。私は困惑しています。では、なぜ私はこの問題を抱えているのですか?私の波は、最大値が32,767であり、winmm.dllがそれを認識し、それを超えないことを示唆していませんか?2バイトのデータをshortに変換しているだけなので、この問題が発生することはありませんか?助けてください :)

4

1 に答える 1

0

これを検討している人のための私の解決策は、本質的にかなり単純でした。16ビットの符号付き数値の最大の正の値は32767です。最大の負の数は-32768です。32768の絶対値を取得し、それを16ビットの数値にしようとすると、オーバーフロー例外がスローされます。したがって、解決策は、絶対値を取得する前に、短い値を32ビット数にキャストすることです。これが修正された関数です

    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;
    }

ushortを使用することで、符号なしの数値を使用することもできたかもしれませんが、Math.Abs​​は

于 2012-05-17T14:17:38.033 に答える