zoukankan      html  css  js  c++  java
  • 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 结构体

  • 相关阅读:
    文件操作实例加强
    文件操作的一般基础操作
    列表与if语句的结合
    难题记录
    字典,集合,列表混合使用需注意:
    列表的一些难度操作
    字符串知识巩固
    and与or的用法
    AngularJS中的过滤器
    NodeJS中的静态资源管理服务
  • 原文地址:https://www.cnblogs.com/sprint1989/p/3854627.html
Copyright © 2011-2022 走看看