Как стать автором
Обновить

Распознавание с нестандартного микрофона

Время на прочтение4 мин
Количество просмотров6.3K
Некоторые сталкиваются с тем что необходимо распознать речь перевести её в текст и обработать. Проблема описывалась много раз как впрочем и пути её решения так что Google в помощь, но вот я столкнулся на собственном опыте с проблемой которая потребовала нетривиального решения, а именно как заставить распознавать речь с микрофона которые не установлен «по умолчанию». Если вы тоже столкнулись с подобной проблемой то эта статья именно для вас.

Итак что мы имеем — есть два различных движка для распознавания речи в Microsoft Windows (стандартный и Microsoft Speech SDK 11) причём сразу скажу что русский язык поддерживает пока только один из них, а именно Microsoft Speech SDK 11 с установленным русским языком. Если внимательно прочитать документацию по обоим движкам, то видно что в качестве устройства можно выбрать только DefaultInputDevice, но копнув глубже, а именно открыв сборку декомпилятором Telerik JustDecompile я убедился что все классы являются лишь обёрткой над СОМ объектами, а как раз в этих СОМ объектах нужная функция есть. Естественно что как и все программисты я ленивый и работать с СОМ не хотел, поэтому совмести два решения. Итак первое что нам необходима это найти Token нужного нам микрофона для этого существует следующая функция:
private SpeechLib.SpObjectToken FindMicByName(string name)
        {
            if (isot != null)
            {
                for (int i = 0; i < isot.Count; i++)
                {
                    sot = isot.Item(i);
                    string desc = sot.GetDescription(1033);
                    string id = sot.Id;
                    if (desc.Contains(name) != false)
                    {
                        break;
                    }
                }
                return sot;
            }
            else
                return null;
        }

После того как мы получим Token необходимо вызвать приватные методы у класса «движка» распознавания для этого используется следующая функция:
public void SetMicByName(string name, ref System.Speech.Recognition.SpeechRecognitionEngine sre)
        {
            if (isot != null)
            {
                sre.SetInputToDefaultAudioDevice();
                sot = FindMicByName(name);
                if (sot != null)
                {
                    FieldInfo fi = sre.GetType().GetField("_sapiRecognizer", BindingFlags.Instance | BindingFlags.NonPublic);
                    object _sapiRecognizer = fi.GetValue(sre);
                    MethodInfo mi = _sapiRecognizer.GetType().GetMethod("SetInput", BindingFlags.Instance | BindingFlags.NonPublic);
                    object[] parms = new object[] { sot, true };
                    mi.Invoke(_sapiRecognizer, parms);
                }
            }
        }

В конце я приведу полный текст вспомогательного класса, который используется в моей разработке, Вы можете использовать его полностью или частично или просто вставить необходимые фрагмента кода себе. Всё это проверенно на Windows 7,8,8.1 ,NET 4.0, 4.5, но думаю что и с другими версиями будет работать также.
using System;
using System.Reflection;

namespace RMI.SmartHouse.Service
{
    /// <summary>
    /// Позволяет осуществить выбор микрофонов.
    /// </summary>
    public class MicSelector : IDisposable
    {
        #region Приватные поля

        private SpeechLib.SpInProcRecoContext _siprc;
        private SpeechLib.ISpeechObjectTokens _isot;
        private SpeechLib.SpObjectToken _sot;
        private bool _isDisposed;
        #endregion

        #region Конструкторы

        /// <summary>
        /// Конструктор по умолчанию.
        /// </summary>
        public MicSelector()
        {
            _siprc = new SpeechLib.SpInProcRecoContext();
            _isot = _siprc.Recognizer.GetAudioInputs(null, null);
            _sot = null;
        }

        #endregion

        #region Публичные свойства

        /// <summary>
        /// Список доступных устройств.
        /// </summary>
        public SpeechLib.ISpeechObjectTokens Isot
        {
            get
            {
                return _isot;
            }
        }

        #endregion

        #region Публичные методы

        /// <summary>
        /// Устанавливает выбранный микрофон.
        /// </summary>
        /// <param name="name">Имя микрофона.</param>
        /// <param name="sre">Движок для распознавания.</param>
        public void SetMicByName(string name, ref System.Speech.Recognition.SpeechRecognitionEngine sre)
        {
            if (_isot != null)
            {
                sre.SetInputToDefaultAudioDevice();
                _sot = FindMicByName(name);
                if (_sot != null)
                {
                    FieldInfo fi = sre.GetType().GetField("_sapiRecognizer", BindingFlags.Instance | BindingFlags.NonPublic);
                    if (fi != null)
                    {
                        object sapiRecognizer = fi.GetValue(sre);
                        MethodInfo mi = sapiRecognizer.GetType().GetMethod("SetInput", BindingFlags.Instance | BindingFlags.NonPublic);
                        object[] parms = { _sot, true };
                        mi.Invoke(sapiRecognizer, parms);
                    }
                }
            }
        }

        /// <summary>
        /// Устанавливает выбранный микрофон.
        /// </summary>
        /// <param name="name">Имя микрофона.</param>
        /// <param name="sre">Движок для распознавания.</param>        
        public void SetMicByName(string name, ref Microsoft.Speech.Recognition.SpeechRecognitionEngine sre)
        {
            if (_isot != null)
            {
                sre.SetInputToDefaultAudioDevice();
                _sot = FindMicByName(name);
                if (_sot != null)
                {
                    FieldInfo fi = sre.GetType().GetField("_sapiRecognizer", BindingFlags.Instance | BindingFlags.NonPublic);
                    if (fi != null)
                    {
                        object sapiRecognizer = fi.GetValue(sre);
                        MethodInfo mi = sapiRecognizer.GetType().GetMethod("SetInput", BindingFlags.Instance | BindingFlags.NonPublic);
                        object[] parms = { _sot, true };
                        mi.Invoke(sapiRecognizer, parms);
                    }
                }
            }
        }

        /// <summary>
        /// Обновляет список доступных устройств.
        /// </summary>
        /// <returns>Список доступных устройств.</returns>
        public SpeechLib.ISpeechObjectTokens UpdateDeviceList()
        {
            if (_siprc != null)
            {
                _isot = _siprc.Recognizer.GetAudioInputs(null, null);
                return _isot;
            }
            return null;
        }

        /// <summary>
        /// Освобождение ресурсов.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion

        #region Приватные функции
        /// <summary>
        /// Освобождение ресурсов.
        /// </summary>
        protected virtual void Dispose(bool disposing)
        {
            if (!_isDisposed)
            {
                if (disposing)
                {
                    _sot = null;
                    _isot = null;
                    _siprc = null;
                }
                _isDisposed = true;
            }
        }
        /// <summary>
        /// Поиск микрофона по имени.
        /// </summary>
        /// <param name="name">Имя для поиска.</param>
        /// <returns>Токен микрофона.</returns>
        private SpeechLib.SpObjectToken FindMicByName(string name)
        {
            if (_isot != null)
            {
                for (int i = 0; i < _isot.Count; i++)
                {
                    _sot = _isot.Item(i);
                    string desc = _sot.GetDescription(1033);
                    if (desc.Contains(name))
                    {
                        break;
                    }
                }
                return _sot;
            }
            return null;
        }

        #endregion
    }
}
Теги:
Хабы:
+3
Комментарии3

Публикации

Истории

Работа

.NET разработчик
75 вакансий

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн