C#으로 만드는 음성인식/TTS 프로그램
(업데이트: 2023-03-30) 이 글에 대한 질문은 더 이상 받지 않습니다. (하시다 보면, 제가 왜 이 기술에 대해 흥미를 못 느끼는 지 아시게 될 것입니다. ^^ SpeechRecognitionEngine에 특별한 업데이트가 없는 한 다루지 않을 것입니다.)
개발자로 일하면서 두 번째로 일하게 되었던 직장이 바로 "L&H Korea"였습니다. 그 당시에는 나름 음성인식/TTS(Text-to-Speech) 관련해서 유명했던 회사였지만, 그보다는... 아마도 한국 지사의 분식 회계로 벨기에 본사까지 파산시킨 사례로 더 유명했을 수도 있습니다. 아직도 그 시절의 기사가 검색되는군요. ^^;
음성인식 전문기업 L&H 코리아 파산
; http://www.lawtimes.co.kr/LawNews/News/NewsContents.aspx?kind=AA&serial=4831
기존의 국내 음성인식 회사였던 '범일 정보 통신'을 벨기에의 "L&H"가 인수해서 운영하던 지사였는데, 나름 외국계 회사라 근무 환경도 그 당시의 다른 IT업체와 비교해서 꽤 좋았던 걸로 기억합니다. 예를 들어, 한 달에 한 번씩 맥주집을 통째로 빌려서 전 직원들 모두 서로 간에 가볍게 술 한잔하며 인사를 나눌 수 있는 복지 정책도 있었는데... 아... 그 시절 생각하니 (이후
다나와에 계셨던) ijb 소장님이 생각나는군요. ^^
암튼... 제 경우에는 당시에 음성인식의 핵심 내부 엔진을 다루는 연구소에서
(한국말은 끝까지 들어봐야 한다는) 일하지는 못했고 '웹 음성 인식 사이트'를 다루는 파트에서 일하게 되었더랬습니다. 당시에는 COM 개체가 생소했고, 회사의 음성인식을 다루는 엔진이 COM 개체로도 제공되긴 했지만 사용하기 어려워서 제가 임의로 좀 더 사용하기 편하게 COM 개체로 만들었고, 그것을 같이 일하던 웹 프로그래머가 HTML 웹 페이지에서 사용할 수 있도록 제공을 해서... 나름 재미있는 아이디어들이 피어나고 있었는데... 웬일인지 사업부 전체가 개편되면서 제가 있던 팀 자체가 해체되는 일이 발생했고, 저는 그 틈을 타서 자연스럽게 (현재
옥션에 계신) 김현승 수석님의 부름을 받아 가온아이(
http://www.kaoni.com/)라는 회사에 이직을 하게 되었습니다.
아... 그 시절 생각하니 또 옛 추억에 잠기게 되는군요. ^^
그나저나 오늘은 왜캐 서론이 길죠? ^^;
정신차리고... 본론으로 돌아와서, 제 기억으로는 그 유명했던 L&H의 음성인식 엔진이 그 이후 윈도우의 기본 음성인식 엔진으로는 명맥을 이어갔다는 소식이 있었습니다. (현재의 윈도우에 있는 음성인식 엔진이 L&H의 것인지는 모르겠습니다.)
물론, 윈도우 내에서만 사용할 수 있도록 숨겨져 있지는 않고 C#으로도 이미 사용법이 잘 공개되어 있습니다.
Speech 101, Part 2 - Using C# to Recognize “Hello World”
; http://blogs.msdn.com/b/rlucero/archive/2012/01/10/speech-101-part-2-using-c-to-recognize-hello-world.aspx
SpeechRecognitionEngine Class
; https://learn.microsoft.com/en-us/dotnet/api/system.speech.recognition.speechrecognitionengine
위의 글에서도 잘 소개되어 있지만, 음성 인식 응용 프로그램을 만드려면 다음과 같은 단계를 밟아주면 됩니다.
- System.Speech 어셈블리 참조
- SpeechRecognitionEngine 인스턴스 생성
- 음성인식이 될 단어들을 적절하게 제시한 "Grammar" 지정
- 음성인식 입력 소스 지정
- SpeechRecognized 이벤트를 구독
- 음성인식 시작
SpeechRecognitionEngine 인스턴스야 그냥 new하면 되는데요. 이때, 음성인식에 사용될 '언어'를 지정해 주어야 합니다. 즉, 영어인지 한글인지를 지정해 주어야 하는데, 이를 알기 위해서는 현재의 윈도우에 어떤 언어의 음성인식 엔진이 설치되어 있는지 확인하는 방법이 필요합니다. 바로 이때, SpeechRecognitionEngine.InstalledRecognizers 메서드를 이용하실 수 있습니다.
foreach (RecognizerInfo ri in SpeechRecognitionEngine.InstalledRecognizers())
{
Console.WriteLine(ri.Culture);
}
// 영문 윈도우 7 Ultimate 버전에서는 다음과 같이 출력되었고,
en-US
en-GB
// 한글 윈도우 7에서는 아무런 출력도 없었습니다.
기본값으로는 운영체제의 언어 설정을 따라가니, 다음과 같이 빈 생성자로 초기화해 줄 수도 있습니다.
using (SpeechRecognitionEngine recognizer = new SpeechRecognitionEngine())
{
}
그다음은 인식될 단어들에 대한 후보를 명시해 주어야 합니다. "Speech 101, Part 2 - Using C# to Recognize “Hello World”" 글에서는 XML 파일을 이용한 방법을 설명하고 있고, "
SpeechRecognitionEngine Class" 글에서는 코딩을 이용한 방법이 설명되고 있습니다.
처음에는 "
SpeechRecognitionEngine Class" 글을 보고 코드로 직접 입력해 보려고 했는데, 아쉽게도 SetDictationContext 호출 코드에서 예외가 발생했습니다.
DictationGrammar grammar = new DictationGrammar("grammar:dictation");
grammar.Name = "question dictation";
grammar.SetDictationContext("Computer, hibernate yourself", null); <=== 예외: "Grammar is not loaded into this recognizer"
grammar.SetDictationContext("Yes", null);
grammar.Enabled = true;
recognizer.LoadGrammar(grammar);
단서가 많지 않았기 때문에 할 수 없이 XML 파일로 방향을 돌려야 했습니다. 그래서, 다음과 같이 xml 파일을 구성하고,
<grammar version="1.0" sapi:alphabet="x-microsoft-ups" xml:lang="en-us" root="Command"
tag-format="semantics-ms/1.0" xmlns="http://www.w3.org/2001/06/grammar"
xmlns:sapi="http://schemas.microsoft.com/Speech/2002/06/SRGSExtensions">
<rule id="Command" scope="public">
<one-of>
<item>Computer, hibernate yourself</item>
<item>Yes</item>
<item>No</item>
</one-of>
</rule>
</grammar>
음성인식 엔진에 적용을 시켰습니다.
Grammar grammar = new Grammar("computer.xml");
recognizer.LoadGrammar(grammar);
그다음으로 할 일이, 음성을 입력받을 Source를 지정해 주어야 하는데요. WAV 파일로부터도 입력을 받을 수 있고,
recognizer.SetInputToWaveFile("helloworld.wav");
컴퓨터에 연결된 마이크로폰으로부터도 입력받을 수 있습니다. (여기서는 마이크로부터 입력받을 것입니다.)
recognizer.SetInputToDefaultAudioDevice();
이제 마지막으로, 음성인식이 된 경우 컴퓨터가 인식된 '텍스트'를 구할 수 있도록 이벤트 핸들러를 지정한 후, 음성인식 엔진을 시작시키면 됩니다.
recognizer.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(recognizer_SpeechRecognized);
recognizer.RecognizeAsync(RecognizeMode.Multiple);
while (true)
{
Console.ReadLine();
}
static void recognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
Console.WriteLine("Recognized text: " + e.Result.Text);
}
컴파일하고 실행한 후, 컴퓨터에 달린 마이크에 "Computer, hibernate yourself"라고 말하면 콘솔 화면에 "Recognized text: Computer, hibernate yourself"라고 찍힙니다.
음성인식과 쌍을 이루는 TTS 엔진도 마저 간단하게 살펴볼 텐데요. 동일하게 System.Speech 어셈블리에서 제공되며 다음과 같이 음성출력을 할 수 있습니다.
SpeechSynthesizer tts = new SpeechSynthesizer();
tts.SetOutputToDefaultAudioDevice();
tts.Speak("Are you sure?");
그렇게 훌륭한 품질의 음성 출력은 아니지만... ^^; 좀 견딜만은 합니다.
자... 그럼, 음성인식과 출력을 곁들여서 다음과 같이 예제 제작을 해보면 어떨까요? 컴퓨터를 최대절전모드로 진입시키는 작업을 음성인식으로 할 수 있습니다. ^^
static RecognitionState current = RecognitionState.None;
static void recognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
if (e.Result.Text == "Computer, hibernate yourself" &&
current == RecognitionState.None)
{
current = RecognitionState.Question;
System.Speech.Synthesis.SpeechSynthesizer tts = new System.Speech.Synthesis.SpeechSynthesizer();
tts.SetOutputToDefaultAudioDevice();
tts.Speak("Are you sure?");
Console.WriteLine("Are you sure?");
return;
}
if (current == RecognitionState.Question)
{
current = RecognitionState.None;
if (e.Result.Text == "Yes")
{
Console.WriteLine("hibernating...");
DoHibernation();
}
else
{
Console.WriteLine("Canceled.");
}
}
}
private static void DoHibernation()
{
ProcessStartInfo psi = new ProcessStartInfo();
psi.Arguments = "/h /f";
psi.FileName = "c:\\windows\\system32\\shutdown.exe";
Process.Start(psi);
}
public enum RecognitionState
{
None,
Question,
}
그런데, 한글 음성인식은 안 되는 걸까요? 이를 위해서는 별도로 "Microsoft Speech Platform - Runtime 11.0"을 설치해야 하고, 그 버전에 맞는 한글 음성인식 데이터 파일을 설치해 주어야 합니다. (물론, TTS도 필요하다면.)
그래서, 각각 다음의 경로에서 먼저 파일들을 다운로드해 설치합니다.
Microsoft Speech Platform - Runtime 11.0
; http://go.microsoft.com/fwlink/?LinkID=223568&clcid=0x409
Microsoft Speech Platform - Server SDK
; http://go.microsoft.com/fwlink/?LinkID=223570&clcid=0x409
이어서, 한글에 대한 음성인식과 TTS 데이터 파일을 다운로드/설치하고,
Microsoft Speech Platform - Runtime Languages (Version 11)
; http://www.microsoft.com/download/en/details.aspx?id=27224
한글 음성인식: MSSpeech_SR_ko-KR_TELE.msi
한글 TTS: MSSpeech_TTS_ko-KR_Heami.msi
이제 위에서 만든 예제 프로젝트에 약간의 변화를 가해주어야 합니다. 우선, System.Speech 어셈블리를 참조 해제하고, 대신 "Microsoft Speech Platform - Server SDK"의 설치 폴더로부터 "C:\Program Files\Microsoft SDKs\Speech\v11.0\Assembly\Microsoft.Speech.dll" 파일을 복사해서 참조 추가합니다.
이후, 코드에서 사용된 네임스페이스를 각각 다음과 같이 바꿔주어야 합니다.
System.Speech.Recognition ==> Microsoft.Speech.Recognition
System.Speech.Synthesis ==> Microsoft.Speech.Synthesis
음성인식을 위해 설정한 computer.xml 파일도 바꿔야겠지요.
<grammar version="1.0" sapi:alphabet="x-microsoft-ups" xml:lang="ko-KR" root="Command"
tag-format="semantics-ms/1.0" xmlns="http://www.w3.org/2001/06/grammar"
xmlns:sapi="http://schemas.microsoft.com/Speech/2002/06/SRGSExtensions">
<rule id="Command" scope="public">
<one-of>
<item>컴퓨터, 최대 절전 모드로 들어가</item>
<item>응</item>
<item>아니</item>
</one-of>
</rule>
</grammar>
마지막으로, SpeechRecognized 이벤트 핸들러 내의 코드를 다음과 같이 바꿔줍니다.
static void recognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
if (e.Result.Text == "컴퓨터, 최대 절전 모드로 들어가" &&
current == RecognitionState.None)
{
current = RecognitionState.Question;
SpeechSynthesizer tts = new SpeechSynthesizer();
tts.SelectVoice("Microsoft Server Speech Text to Speech Voice (ko-KR, Heami)");
tts.SetOutputToDefaultAudioDevice();
tts.Speak("정말?");
Console.WriteLine("정말?");
return;
}
if (current == RecognitionState.Question)
{
current = RecognitionState.None;
if (e.Result.Text == "응")
{
Console.WriteLine("hibernating...");
DoHibernation();
}
else
{
Console.WriteLine("Canceled.");
}
}
}
전체적으로 소스 코드의 호환성은 System.Speech.dll과 Microsoft.Speech.dll에서 지켜지는 편인데, 단지 영문/한글에 대한 부분만 살짝 바꿔주기만 하면 됩니다.
가장 중요한 것! 그래서 한글 음성인식이나 TTS가 어느 정도냐 하는 것인데요. 음... 그냥 '무료'라는 점을 감안하라는 조언만 드리고 싶군요. ^^
*
첨부파일은 2가지 예제 프로젝트를 압축한 것입니다.
- basic_version: System.Speech.dll 사용 예제 (영문 음성인식/TTS)
- ms_speech_server_version: Microsoft.Speech.dll 사용 예제 (한글 음성인식/TTS)
이 글과 관련해서 오류가 발생한다면, 다음의 글을 참고하세요.
SpeechRecognitionEngine 사용 시 오류 유형 2가지
; https://www.sysnet.pe.kr/2/0/1449
SpeechRecognitionEngine.SetInputToDefaultAudioDevice 호출 시 System.InvalidOperationException 예외 발생
; https://www.sysnet.pe.kr/2/0/1317
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]