Как предотвратить увеличение числа из волны

Так что это может стать слишком сложным для объяснения, но я постараюсь сделать его простым, но информативным. моя программа, написанная на 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: отрицание минимального значения числа с дополнением до двух недопустимо.

Однажды я получил его, чтобы дать мне MaxSound: 32767 (0x7FFF).

Итак, я понял, что моя проблема заключалась в попытке преобразовать 32-битное число в 16-битное число, поэтому я переключил GetMaxSound с короткого на целое. Так что я не знаю. Я в тупике. Так почему у меня эта проблема? Разве моя волна не предполагает, что максимальное значение составляет 32 767, и что winmm.dll будет знать об этом и не превысит это? и поскольку он просто преобразует 2 байта данных в короткие, он никогда не столкнется с этой проблемой? Пожалуйста помоги :)


person Robert Snyder    schedule 16.05.2012    source источник
comment
Из чего вы поняли, что ваша волна предполагает, что ее максимальное значение составляет 32 767, только потому, что система успешно работала для одной волны, не означает, что она будет работать для следующей, или вы говорите, что система ведет себя по-другому? в течение нескольких прогонов с одним и тем же файлом? Также вы переключились на GetMaxSound, но оставили на BitConverter.ToInt16.   -  person Joshua Drake    schedule 16.05.2012
comment
@JoshuaDrake Эта волна с моего микрофона, а не из волнового файла. если я не буду издавать громкие звуки в свой микрофон, он не сломается. и я играю с GetMaxSound из-за того, что не совсем понимаю, как он может вылететь с его настройкой. Если это битовый преобразователь, разве он никогда не должен сталкиваться с переполнением??? и не должен ли winmm просто возвращать 32767 или -32768 ... подождите, я использую абс на коротком замыкании. что 32768 приведет к переполнению, ха... BRB   -  person Robert Snyder    schedule 16.05.2012
comment
это было! я применил int к своей волне [i], и теперь она достигает максимума 32768 :) maxSound = Math.Max(maxSound, Math.Abs((int)wave[i])); - это решение. Я вдул в него, и он дал мне следующий вывод. 32768   -  person Robert Snyder    schedule 16.05.2012
comment
Еще один, на который вы должны ответить сами. Вскоре вы будете на пути к значку самообучения.   -  person Joshua Drake    schedule 16.05.2012


Ответы (1)


Мое решение для тех, кто, возможно, изучает это, было довольно простым по своей природе. Максимальное положительное значение 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 ​​делает

person Robert Snyder    schedule 17.05.2012