Kinect 开发 —— 录音

不涉及语音识别~~


<Window x:Class="KinectRecordAudio.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Audio Recorder" Height="226" Width="405">
    <Grid Width="369" Height="170">
        <Button Content="Play" Height="44" HorizontalAlignment="Left" Margin="12,13,0,0" Name="button1" VerticalAlignment="Top" Width="114" Click="button1_Click"  IsEnabled="{Binding IsPlayingEnabled}" FontSize="18"></Button>
        <Button Content="Record" Height="44" HorizontalAlignment="Left" Margin="132,13,0,0" Name="button2" VerticalAlignment="Top" Width="110" Click="button2_Click"  IsEnabled="{Binding IsRecordingEnabled}" FontSize="18"/>
        <Button Content="Stop" Height="44" HorizontalAlignment="Left" Margin="248,13,0,0" Name="button3" VerticalAlignment="Top" Width="107" Click="button3_Click"  IsEnabled="{Binding IsStopEnabled}" FontSize="18"/>
        <CheckBox Content="Noise Suppression" Height="16" HorizontalAlignment="Left" Margin="16,77,0,0"  VerticalAlignment="Top" Width="142" IsChecked="{Binding IsNoiseSuppressionOn}" />
        <CheckBox Content="Automatic Gain Control" Height="16" HorizontalAlignment="Left" Margin="16,104,0,0"  VerticalAlignment="Top"  IsChecked="{Binding IsAutomaticGainOn}"/>
        <CheckBox Content="AEC" Height="44" HorizontalAlignment="Left" IsChecked="{Binding IsAECOn}" Margin="16,129,0,0"  VerticalAlignment="Top" />
    </Grid>
</Window>

namespace KinectRecordAudio
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        // INotifyPropertyChanged 接口用于向客户端(通常是执行绑定的客户端)发出某一属性值已更改的通知。
        
        string _recordingFileName;  // 录音文件名
        MediaPlayer _mplayer;
        bool _isPlaying;
        bool _isNoiseSuppressionOn;
        bool _isAutomaticGainOn;
        bool _isAECOn;

            // IsEnabled="{Binding IsRecordingEnabled}" 将控件与方法绑定

        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += delegate { KinectSensor.KinectSensors[0].Start(); };
            _mplayer = new MediaPlayer();
            _mplayer.MediaEnded += delegate { _mplayer.Close(); IsPlaying = false; };
            this.DataContext = this;
        }



        private void Play()
        {
            IsPlaying = true;
            _mplayer.Open(new Uri(_recordingFileName, UriKind.Relative));
            _mplayer.Play();
        }


        private void Record()
        {
            Thread thread = new Thread(new ThreadStart(RecordKinectAudio));
            thread.Priority = ThreadPriority.Highest;   // 线程优先级
            thread.Start();
        }

        private void Stop()
        {
            KinectSensor.KinectSensors[0].AudioSource.Stop();
            IsRecording = false;
        }
        private object lockObj = new object();

        private void RecordKinectAudio()
        {
            lock (lockObj)
            {
                    // 线程加锁
                IsRecording = true;

                var source = CreateAudioSource();

                var time = DateTime.Now.ToString("hhmmss");
                _recordingFileName = time + ".wav";
                using (var fileStream =
                new FileStream(_recordingFileName, FileMode.Create))
                {
                    RecorderHelper.WriteWavFile(source, fileStream);
                }

                IsRecording = false;
            }

        }

        private KinectAudioSource CreateAudioSource()
        {
            var source = KinectSensor.KinectSensors[0].AudioSource;
            source.BeamAngleMode = BeamAngleMode.Adaptive;
            source.NoiseSuppression = _isNoiseSuppressionOn;
            source.AutomaticGainControlEnabled = _isAutomaticGainOn;

            if (IsAECOn)
            {
                source.EchoCancellationMode = EchoCancellationMode.CancellationOnly;
                source.AutomaticGainControlEnabled = false;
                IsAutomaticGainOn = false;
                source.EchoCancellationSpeakerIndex = 0;
            }

            return source;  // 返回经过处理的数据源
        }

        #region user interaction handlers

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            Play();
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {
            Record();
        }


        private void button3_Click(object sender, RoutedEventArgs e)
        {
            Stop();
        }

        #endregion

        #region properties

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }

        private bool IsPlaying
        {
            get
            {
                return _isPlaying;
            }
            set
            {
                if (_isPlaying != value)
                {
                    _isPlaying = value;
                    OnPropertyChanged("IsRecordingEnabled");
                }
            }
        }

        private bool IsRecording
        {
            get
            {
                return RecorderHelper.IsRecording;
            }
            set
            {
                if (RecorderHelper.IsRecording != value)
                {
                    RecorderHelper.IsRecording = value;
                    OnPropertyChanged("IsPlayingEnabled");
                    OnPropertyChanged("IsRecordingEnabled");
                    OnPropertyChanged("IsStopEnabled");
                }
            }
        }
        public bool IsPlayingEnabled
        {
            get { return !IsRecording; }
        }

        public bool IsRecordingEnabled
        {
            get { return !IsPlaying && !IsRecording; }
        }

        public bool IsStopEnabled
        {
            get { return IsRecording; }
        }


        public bool IsNoiseSuppressionOn
        {
            get
            {
                return _isNoiseSuppressionOn;
            }
            set
            {
                if (_isNoiseSuppressionOn != value)
                {
                    _isNoiseSuppressionOn = value;
                    OnPropertyChanged("IsNoiseSuppressionOn");
                }
            }
        }

        public bool IsAutomaticGainOn
        {
            get
            {
                return _isAutomaticGainOn;
            }
            set
            {
                if (_isAutomaticGainOn != value)
                {
                    _isAutomaticGainOn = value;
                    OnPropertyChanged("IsAutomaticGainOn");
                }
            }
        }


        public bool IsAECOn
        {
            get
            {
                return _isAECOn;
            }
            set
            {
                if (_isAECOn != value)
                {
                    _isAECOn = value;
                    OnPropertyChanged("IsAECOn");
                }
            }
        }

        #endregion
    }
}

class RecorderHelper
{
    static byte[] buffer = new byte[4096];
    static bool _isRecording;


    public static bool IsRecording
    {
        get
        {
            return _isRecording;
        }
        set
        {
            _isRecording = value;
        }
    }


    public static void WriteWavFile(KinectAudioSource source, FileStream fileStream)
    {
        var size = 0; 
        //write wav header placeholder
        WriteWavHeader(fileStream, size);   // size=0;
        using (var audioStream = source.Start())
        {
            // Starts capturing audio from the device. The data can be read using the returned stream.
            //chunk audio stream to file
            while (audioStream.Read(buffer, 0, buffer.Length) > 0 && _isRecording)
            {
                fileStream.Write(buffer, 0, buffer.Length);
                size += buffer.Length;

            }
        }

        //write real wav header
        // 方法开始写入一个假的头文件,然后读取Kinect中的音频数据流,然后填充FileStream对象,直到_isRecoding属性被设置为false。然后检查已经写入到文件中的数据流大小,用这个值来改写之前写入的文件头
        long prePosition = fileStream.Position;
        fileStream.Seek(0, SeekOrigin.Begin);
        WriteWavHeader(fileStream, size);   // size = file length
        fileStream.Seek(prePosition, SeekOrigin.Begin);
        fileStream.Flush();
    }

    public static void WriteWavHeader(Stream stream, int dataLength)
    {
        using (MemoryStream memStream = new MemoryStream(64))
        {
            // 基于指定的字节数组初始化 MemoryStream 类的无法调整大小的新实例

            int cbFormat = 18;
            WAVEFORMATEX format = new WAVEFORMATEX()
            {
                wFormatTag = 1,
                nChannels = 1,
                nSamplesPerSec = 16000,
                nAvgBytesPerSec = 32000,
                nBlockAlign = 2,
                wBitsPerSample = 16,
                cbSize = 0
            };

            using (var bw = new BinaryWriter(memStream))
            {

                WriteString(memStream, "RIFF");
                bw.Write(dataLength + cbFormat + 4);
                WriteString(memStream, "WAVE");
                WriteString(memStream, "fmt ");
                bw.Write(cbFormat);

                bw.Write(format.wFormatTag);
                bw.Write(format.nChannels);
                bw.Write(format.nSamplesPerSec);
                bw.Write(format.nAvgBytesPerSec);
                bw.Write(format.nBlockAlign);
                bw.Write(format.wBitsPerSample);
                bw.Write(format.cbSize);

                WriteString(memStream, "data");
                bw.Write(dataLength);

                memStream.WriteTo(stream);
            }
        }
    }

    static void WriteString(Stream stream, string s)
    {
        byte[] bytes = Encoding.ASCII.GetBytes(s);
        stream.Write(bytes, 0, bytes.Length);
    }

    struct WAVEFORMATEX
    {
        public ushort wFormatTag;
        public ushort nChannels;
        public uint nSamplesPerSec;
        public uint nAvgBytesPerSec;
        public ushort nBlockAlign;
        public ushort wBitsPerSample;
        public ushort cbSize;
    }
}

C#不支持直接写wma文件,需要C++的 WAVEFORMATEX 结构体

原文地址:https://www.cnblogs.com/sprint1989/p/3854627.html