메인 컨텐츠로 가기

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관 보기.

developerWorks에 처음 로그인하면 developerWorks프로파일이 생성됩니다.귀하의 프로파일에서 동의하신 내용이 공개되지만 이 사항은 언제든지 변경 가능합니다. 귀하의 성명(숨김으로 체크되어 있어도 표시됩니다)과 디스플레이 이름은 게시한 컨텐츠나 사이트 엑세스시 표시됩니다.

모든 정보가 안전하게 전송되었습니다.

  • 닫기 [x]

처음 developerWorks에 로그인할 때 프로파일이 작성되므로, 이를 위해 디스플레이 이름을 선택해야 합니다. 선택하신 디스플레이 이름은 developerWorks에 게시한 컨텐츠에 표시됩니다.

3글자 이상 31글자 이하의 길이로 사용 가능합니다. dW커뮤니티 내에서는 보안상 이메일주소를 제외한 다른 이름을 지정하셔야 합니다.

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관 보기.

모든 정보가 안전하게 전송되었습니다.

  • 닫기 [x]

휘파람을 불며 명령어 작동하기 (한글)

오픈 소스 소프트웨어와 마이크가 장착된 랩톱을 사용하여 특정 음성(tonal) 시퀀스를 사용하여 명령 실행하기

Nathan Harrington, Programmer, EMC
Nathan Harrington은 IBM 프로그래머이며, 리눅스 및 리소스 배치 기술 관련 일을 하고 있다.

요약:  리눅스®나 마이크로소프트® 윈도우즈®, 오픈 소스 sndpeek 프로그램, 간단한 Perl 스크립트를 사용하여 음성으로 컴퓨터를 제어할 수 있습니다. 휘파람, 콧노래, 노래소리를 이용해 그 소리의 강약에 따라 명령어를 작동할 수 있는 것입니다. 컴퓨터에 짧은 휘파람을 불어서 이메일을 확인하거나, 베토벤의 5번 교향곡으로 화면보호기를 해제하는 것. 생각만 해도 능률이 오를 것 같지 않나요?

원문 게재일:  2007 년 2 월 06 일
난이도:  중급
페이지뷰:  1207 회
의견:  


수 년 동안, 컴퓨터 사용자들은 음성(voice) 프로세싱을 기반으로 명령을 실행하는 프로세서 중심의 음성 인식 애플리케이션을 실행했다. 최근, 프로세스 기능과 알고리즘이 향상되면서, 에러가 확실히 줄어든 사용자 독립적인(user-independent) 음성 인식 방식이 탄생했다. 이것은 음성(tone) 인식 시스템에 있어서 대단한 발전이다.

최근에 릴리스 된 sndpeek 프로그램을 사용하여, 간단한 Perl 프로그램을 실행하여 음성(tonal) 코드를 만들 것이다. 사용자는 음성 입력과 탐지 환경을 개인화 할 수 있도록 Perl 스크립트도 제공된다.

요구 사항

하드웨어

음성 입력(sound input)을 처리할 수 있는 시스템이어야 한다. 통합 마이크를 사용하는 것이 가장 좋지만, 그렇지 않더라도 뚜렷한 음성 이벤트를 만들어 내기만 하면 된다. 예를 들어, 컴퓨터에 휘파람을 부는 것으로도, (키보드와 마우스를 제외한) 제 3의 입력 채널이 될 수 있고, MP3 플레이어도 아웃풋 재생 설정만 잘 된다면 가능하다. 이 글에 삽입된 코드는 IBM® ThinkPad® T42p(900-MHz 프로세서, 1 GB RAM)에서 개발 및 테스트 되었다. sndpeek이 주로 리소스를 사용하는 것이기 때문에, 테스트 한 시스템보다 성능이 떨어지는시스템에서도 코드를 충분히 실행할 수 있다.

소프트웨어

마이크를 사용하려면 음성 처리 소프트웨어 환경이 필요하다. 사운드 설정과 문제 해결 방법은 이 글의 주제는 아니지만, 사운드 하드웨어의 설정에 필요한 드라이버와 컴포넌트들이 모두 들어있는 Vector Linux Live CD에서 이 코드를 테스트 해보기 바란다. 3D 디스플레이를 할 것이 아니므로, 일부 sndpeek 프로그램만 설치하면 된다.

참고자료에서 sndpeek 웹 페이지 링크를 참조하기 바란다. 코드를 다운로드 하고, src/sndpeek/sndpeek.cpp 파일에서, 다음 코드라인을 찾는다.


Listing 1. sndpeek 수정
				
    fprintf( stdout, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f ", 
         mfcc(0), mfcc(1), mfcc(2), mfcc(3), mfcc(4), mfcc(5), mfcc(6),
         mfcc(7), mfcc(8), mfcc(9), mfcc(10), mfcc(11), mfcc(12) );
    fprintf( stdout, "\n" );

위에서 Stdout에 해당 결과가 전달될 수 있도록 확실히 하기 위해서는, 모든 output에 플러쉬(flush) 하도록 하라. (역주:본 글에서는 fflush(stdout) 명령어를 사용하였다.) 위 코드를 다음과 같이 수정한다.


Listing 2. 두 번째 sndpeek 수정
				
    fprintf( stdout, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f ", 
         mfcc(0), mfcc(1), mfcc(2), mfcc(3), mfcc(4), mfcc(5), mfcc(6),
         mfcc(7), mfcc(8), mfcc(9), mfcc(10), mfcc(11), mfcc(12) );
    fprintf( stdout, "\n" );
    fflush(stdout);

./configure; make; make install 컴파일 명령어를 실행하여 리눅스에 sndpeek을 설치한다. Windows의 경우, 프로그램을 구현하는 많은 옵션들이 있기 때문에 더욱 주의해야 한다. Vector Linux Live CD를 통해 cmdWhistle이 작동하는 모습을 볼 수 있다.

그 다음, 명령어(command-line) 제어용 xwit 애플리케이션을 설치한다. 참고자료 섹션에서, xwit 다운로드 링크를 찾아 설치하기 바란다. 드디어, 간단한 음성(tone)을 만들 준비가 되었다.


설치와 설정 예제

간단한 음성 시퀀스 만들기

소스 코드를 다운로드 하면, cmdWhistle.pl 스크립트를 얻을 수 있다. 이것은 메인 Perl 프로그램으로서, 음성 시퀀스를 생성하고, 특정 음성 시퀀스와 run 명령어들을 리스닝(listen) 한다. 이 글에서는, cmdWhistle.pl 프로그램의 사용자 공간에서의 사용법과 설정을 설명하고, 다양한 기능들을 소개하겠다.

sndpeek --print --nodisplay | perl cmdWhistle.pl -c 명령으로 cmdWhistle.pl 프로그램을 실행하면, sndpeek 프로그램을 시작하여 마이크에서 나오는 소리를 듣고, 그 결과를 Perl 프로그램에 출력한다. 프로그램이 실행되면, 몇 가지 휘파람 소리를 만든다. 뚜렷한 개별 음성을 만들거나, 3분의 1초 간격으로 점점 높아지는 음성을 만들어 본다. 가급적이면, 소음이 없는 환경에서 프로그램을 실행하는 것이 좋다.

다양한 속도와 톤으로 실험하여, cmdWhistle 프로그램이 어떻게 이벤트를 포착하는지를 파악할 수 있다. 프로그램의 음성 탐지 프로세스가 섬세할수록, 복잡한 음성 시퀀스를 만들 수 있다. 음성 시퀀스는 단순해야 한다. "beep beep"에 0.5초 간격을 두고, 두 개의 낮은 톤을 만드는 경우를 생각해 보자. sndpeek --print --nodisplay | perl cmdWhistle.pl -c를 실행하고, "enter a tone sequence(음성을 입력하시오)"라는 문구를 보면, 톤 사이에 0.5 초 간격으로 두 번 휘파람을 분다. 자동 타임아웃이 4초 후에 발생하고(설정 가능), 음성 시퀀스는 다음과 같이 출력될 것이다. 25.00 25.00 _#_ 0 500000 _#_ <command here> _#_ <comment here>

음성 시퀀스의 명령어와 음성 탐지

라인을 분석해 보면, 톤 값, 구분자(delimiter), 타임 값, 구분자, 명령어 영역, 구분자, 코멘트 영역으로 되어 있다. 이 라인을 cmdWhistle.pl 프로그램의 디폴트 설정 파일(/home/<username>/.toneFile인 {$HOME}/.toneFile)로 복사한다. 위 음성 시퀀스로 ~/.toneFile을 만들면, 라인을 수정하여 프로그램을 실행할 수 있다. 명령어 영역 텍스트를 /bin/echo "two low"로 바꾸고, 코멘트 영역을, 25.00 25.00 _#_ 0 500000 _#_ /usr/bin/echo "two low" _#_ two low tones로 수정한다.

설정 파일을 수정했다면, sndpeek --print --nodisplay | perl cmdWhistle.pl 명령어로 데몬 모드(daemon mode)에서 cmdWhistle.pl 스크립트를 실행한다. 이 프로그램은 ~/.toneFile 에서 나오는 이벤트를 듣는다. 같은 속도와 같은 음조로 두 개의 저음 휘파람을 불면, 스크린에 "two low"라는 텍스트가 출력된다. cmdWhistle.pl 스크립트의 실행 방법을 자세히 알고 싶다면, daemon 모드에서 sndpeek --print --nodisplay | perl cmdWhistle.pl -v를 실행하라. 시스템이 그래픽 디스플레이를 지원한다면, --nodisplay 옵션은 삭제해도 된다.


xwit를 사용하는 창 관리 예제

raise, lower, iconify 시퀀스 생성

키보드 단축키 또는 마우스 움직임을 모방한 유용한 톤 입력 옵션들이 많이 있다. 아래 예제는 사용자가 홈(home) 위치에서 자신이 원하는 대로 창을 움직일 수 있는 방법을 설명하는 윈도우(window) 관리 방법 예제이다. "기타 예제" 섹션에서 다른 기능들을 설명하고 있다.

create" 모드에서, sndpeek --print --nodisplay | perl cmdWhistle.pl -c 명령어로 cmdWhistle.pl 프로그램을 실행해 보자. 윈도우(window) 관리를 위해 몇 가지 간단한 톤을 만들어야 한다. 낮은 톤은 "lower", 높은 톤은 "raise", 두 개의 중간 톤은 "iconify"로 설정한다. 반드시, 일관성 있고 정확하게 입력할 수 있는 것을 선택해야 한다. 음성 시퀀스를 입력할 때 정밀도를 관리하는 매개변수를 수정할 수는 있겠지만, 정확한 톤이나 타이밍을 매치하기란 상당히 까다롭다. 따라서, 넓은 피치(pitch) 공간을 차지하고 있는 세 개의 음성 옵션들이 우리에게는 알맞다. 다음은 이 세 개의 명령어를 포함하고 있는 ~/.toneFile 샘플이다.


Listing 3. ~/.toneFile 샘플

20.00 _#_ 0 _#_ /usr/bin/xwit -pop -names rxvt _#_ raise rxvt windows
#
#
40.00 _#_ 0 _#_ /usr/bin/xwit -pop -names nathan _
#_ raise xterms starting with nathan@localhost
#
#
25.00 25.00 _#_ 0 500000 _#_ /usr/bin/xwit -iconify -names nathan _
#_ iconify nathan@localhost~

xwit 명령어를 echo로 대체하고, 계속 사용하기 전에는 많은 연습이 필요하다.

xwit - 쉘 스크립트에서 액세스 할 수 있는 X 함수

X Window System에는 명령어를 사용한 윈도우 제어 방식들이 있지만, 그 중에서 xwit가 가장 단순하고 이식성 있으며, 다른 윈도우 매니저에도 잘 작동한다. xwit를 다운로드 해서 설치하고, xwit -iconify 명령어를 실행하여, 프로그램이 잘 작동하는지를 확인한다. (이 명령어는 현재 창(윈도우)를 최소화하는 명령어이다.) xwit에 "lower" 함수가 없지만, 이 때에는 다른 창(윈도우)들을 늘리면 된다. 이 예제에서는, 높은 톤(40.00)으로, "nathan"으로 시작하는 타이틀을 최대로 늘린다. xterms의 타이틀을 설정하는 것은 전형적인 프로그래밍 태스크에 적합하다. 창이 rxvt로 시작한다면, 낮은 톤(20.00)을 사용하여 최대화 된다. Half-Second 딜레이로 실행되는 두 개의 중간 톤(25.00)은 "nathan"으로 시작하는 모든 창(윈도우)을 아이콘으로(iconified) 만든다. (참고자료)

이렇게 설정하면 다른 창에서는 계속 입력을 하면서, 다른 창 화면을 볼 수 있다.(역주: 이후의 '윈도우' 용어는 '창'으로 번역하도록 한다.) 서브루틴 구조를 구현하면서, API 정보용 전문에 문서 레퍼런스를 가져오는데 유용하다. 실제로, 직접 타이핑 하는 것 보다 빠르게 처리되고, 동시에 창 환경을 관리할 수 있다.

창을 늘리고 줄이는 Window 쉘 스크립트

Microsoft OS에서, 창을 늘릴 때 WshShell.AppActivate 명령어를 사용한다. 예를 들어, "gvim" 애플리케이션을 늘리고 싶다면, 다음과 같은 코드로 "gvimActivate.vbs" 파일을 만든다.

Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.AppActivate "gvim";

파일을 만들어서 실행하면, "gvim" 창이 전면에 나타난다. Windows에서 작업한다면, ~/.toneFile의 "high-tone" 명령어를 40.00 _#_ 0 _#_ gvimActivate.vbs _#_ raise gvim window로 변경한다.


기타 예제

sndpeek 프로그램과 cmdWhistle.pl은 고유한 방식으로 사용할 수 있는 추가적인 사용자 입력 방식을 제공한다. 화면 보호기 암호해제를 설정하고, 책상 앞에서 휘파람을 불면, 더 이상 패스워드를 입력할 필요가 없다. 휘파람으로 이메일을 체크하고, 핸드폰의 고유 톤을 체크하고, 전화 벨을 울려 이메일을 보낼 수 있다.


cmdWhistle.pl 코드

역사와 전략

고속 퓨리에 변환(Fast Fourier transform)시스템과와 Sliding percentage windows, 그리고 일부 리눅스 오디오 프로그래밍은 음성 인식 기능을 제공한다. Ge Wang, Perry R. Cook, Ananya Misra가 작성한 sndpeek 애플리케이션은 cmdWhistle.pl이 음성 이벤트를 탐지하기 위해 필요한 정보를 모으는데 있어서, 이식성 있고 빠른 유닉스® 방식을 제공한다. 'sndpeek --print' 명령어는 현재 사운드 소스에 대해 실시간으로 텍스트를 분석하고, 뛰어난 3D화면을 제공한다. sndpeek에서 출력된 텍스트 분석의 네 번째 엔트리는 sndtool의 "Marsyas" 컴포넌트를 사용하는 Rolloff 함수의 결과물이다. (역주:sndpeek의 실행화면을 확인하기 바란다.)


Listing 4. Rolloff.cpp 소스 코드의 디스크립션
				
Compute Rolloff (a percentile point) of the input fvec. 
For example if perc_ is 0.90 then Rolloff would be the 
index where the sum of values before that index are 
equal to 90% of the total energy. 

이러한 결과물을 기본 "톤(tone)"으로 사용하기 위해서는 cmdWhishle.pl 스크립트는 톤간의 다양한 시간 간격을 인지하여 구분하여야 한다.

매개변수 설정

cmdWhistle.pl의 타이밍(timing)과 센서(sensor) 매개변수 설정을 시작해 보자.


Listing 5. cmdWhistle.pl 타이밍 및 센서 매개변수
				
$|=1; #for non buffered standard output, useful for other programs to read 
require 'sys/syscall.ph'; # for subsecond timing

my $option = $ARGV[0] || ""; # simple option handling

my $MAX_TIMEOUT_LENGTH = 4; # maximum length in seconds of tone pattern
my $LISTEN_TIMEOUT = 2; # timeout value in seconds between tone
my $MAX_TIME_DEV = 	100000; # maximum acceptable deviation between recorded
	# pattern values and current time values
my $MAX_TONE_DEV = 2; # maximum acceptable deviation between recorded
	# pattern values and current tone values
my $MAX_AVG_TONE = 5; # maximum number of samples to be averaged 

위 리스팅의 변수들과 코멘트들은 비교적 단순하다. 사용법과 설정 옵션에 대해서는 나중에 자세히 설명하겠다. 다음은 글로벌 변수의 나머지 부분이다.


Listing 6. 글로벌 변수와 디스크립션
				
my @queTones = ();	# running queue of recent tones detected 
my $prevTone = 0; 	# the last solid tone detected, used for disambiguation
my $prevInterval = 0; 	# previous interval of time
my @baseTones = (); # the currently entered tone sequence
my @baseTimes = (); # the currently entered temporal values
my %toneHash = (); 	# tones, times and commands read from ~/.toneFile
my $toneCount = 0; 	# the current count of tones entered
my $startTime = ""; 	# start of a temporal block
my $currTime = ""; 	# current time in the time out loop
my $toneAge = 0; 		# for tone count synchronization
my $timeOut = 0;		# to reset the timer window

서브루틴(Subroutine)

음성 패턴의 상태에 대한 상세한 정보를 제공하는 getEpochSecondsgetEpochMicroSeconds를 보자.


Listing 7. getEpochSeconds와 getEpochMicroSeconds 서브루틴
				
sub getEpochMicroSeconds {

 my $TIMEVAL_T = "LL";   # LL for microseconds
 my $timeVal = pack($TIMEVAL_T, ());

 syscall(&SYS_gettimeofday, $timeVal, 0) != -1 or die "micro seconds: $!";
 my @vals = unpack( $TIMEVAL_T, $timeVal );
 $timeVal = $vals[0] . $vals[1];
 $timeVal = substr( $timeVal, 6);

 my $padLen = 10 - length($timeVal);
 $timeVal = $timeVal . "0" x $padLen;

 return($timeVal);
}#getEpochMicroSeconds

sub getEpochSeconds {
 my $TIMEVAL_T = "LL";   # LL for microseconds
 my $start = pack($TIMEVAL_T, ());
 syscall(&SYS_gettimeofday, $start, 0) != -1 or die "seconds: $!";
 return( (unpack($TIMEVAL_T, $start))[0] );
}#getEpochSeconds

readTones 서브루틴은 sndpeek의 아웃풋에서 Rolloff 데이터 값을 포착한다. 코멘트 섹션에서 보면 알겠지만, 이 코드는 다섯 개의 톤 샘플을 만들어서 이들을 서로 비교하여 기본 편차를 만든다. 톤 어레이 큐의 용량이 차면, 각 톤에 대한 편차를 계산한다. 큐에서 한 톤의 비교치가 최대 음성 편차를 초과하면, 현재 프로세싱이 뚜렷한 톤을 만들어내지 않은 것으로 지정한다.

큐에 있는 모든 톤의 편차가 허용 임계치 이하라면, 모호성 레이어를 탐지한다. 만일 당신이 천천히 증가하는 톤으로 휘파람 소리를 낸다면, 허용 가능한 임계치를 벗어나서 인식 가능한 음성 이벤트를 만들 것이다. 하지만, 이를 지속한다면 문제를 일으킬 수 있다. upDevdownDev 변수들과 비교 로직은, MAX_TONE_DEV 변수 이상으로 편차가 벌어질 경우, 이러한 연속적인 음성 변화들을 인식하도록 설계된다. 최근의 톤 큐 체크와 연속적인 톤 체크가 완료되면, 나중에 비교할 수 있도록 음성 이벤트와 시간을 기록해 둔다.

변수들을 수정하면 특별한 음성 스타일과 편차들을 인식하도록 프로그램을 조정하는데 도움이 된다. 전체적인 주파수 리프레시(refresh) 비율의 분석 결과는 sndpeek 프로그램의 아웃풋에서 나타난다. 다른 모든 매개변수들은, 시간 임계치를 통해 동시 다중 음성 이벤트 또는 음성 이벤트들 간 다른 타이밍 같은, 넓은 공간을 차지하는(widely spaced) 음성 이벤트를 탐지하도록 설정될 수 있다.


Listing 8. 더 넓은 공간을 차지하는 음성 이벤트 탐지하기
				
sub readTones
{ 
 # read the Rolloff output only, 
 my(undef, undef, undef, $currentTone ) = split " ", $_[0];

 if( @queTones == $MAX_AVG_TONE )
 { 
  my $localDiff = 0;
  # check for a solid tone by comparing against the last five tones
  # perform simple time related tonal smoothing, so if the tone
  # wavers just a bit it's still counted as one tone
  for my $chkHistTone ( @queTones )
  { 
   if( abs($currentTone - $chkHistTone) > $MAX_TONE_DEV )
   { 
    $localDiff =1;
    $prevTone = 0;
   }#if deviation less than threshold
  }#for each tone

  if( $localDiff == 0 )
  { 
   # make sure the current tone is different than the previous one, this is to 
   # ensure that long duration tones are not acquired as multiple tone events
   # this step up or down will allow you to whistle continuously and pick up the 
   # steps as discrete tone events
   my $upDev  = $currentTone + $MAX_TONE_DEV;
   my $downDev = $currentTone - $MAX_TONE_DEV;
   if( $prevTone > $upDev || $prevTone < $downDev )
   { 
    my $currVal = getEpochMicroSeconds();
    my $diffInterval = abs($prevInterval - $currVal);
    if( $option ){
     print "Tone: $currentTone ## last: [$currVal] curr: [$prevInterval] ";
     print "difference is: $diffInterval\n";
    }
    if( $toneCount == 0 ){ $diffInterval = 0 }
    push @baseTones, $currentTone;
    push @baseTimes, $diffInterval;
    $toneCount++;
    $prevInterval = $currVal;
   }#if deviation in tone

   # now set the previous tone to the current tone so a continuous tone
   # is not acquired as multiple tone events
   $prevTone = $currentTone;

  }#if a solid tone has been found

  # if enough tones to create an useful queue have been added, pop one off
  shift @queTones;

 }#if enough tones to create a useful queue

 # always push more tones on the avg
 push @queTones, $currentTone;

}#readTones

음성 패턴이 만들어지면, ~/.toneFile 파일에 배치되고, 다음 서브루틴에 의해 읽힌다.


Listing 9. 음성 패턴 생성
				
# readToneFile reads tone sequences and commands from ~/.toneFile
# format is: tones _#_ times _#_ command _#_ comments
sub readToneFile 
{
 #give it a full path to .toneFile if on windows
 open(TONEFILE,"$ENV{HOME}/.toneFile") or die "no tone file: $!";

  while(<TONEFILE>){

   if( !/^#/ ){

    my @arrLine = split "_#_";
    $toneHash{ "$arrLine[0] $arrLine[1]" }{ tones }  = $arrLine[0];
    $toneHash{ "$arrLine[0] $arrLine[1]" }{ times }  = $arrLine[1];
    $toneHash{ "$arrLine[0] $arrLine[1]" }{ cmd }   = $arrLine[2];
    $toneHash{ "$arrLine[0] $arrLine[1]" }{ comment } = $arrLine[3];

   }#if not a comment line

  }#for each line in file

 close(TONEFILE);

}#readToneFile

readTone을 통해서 음성 패턴이 읽히고, readToneFile에서 로딩된 음성 패턴과 비교된다. compareToneSequences 서브루틴은 톤의 타이밍들간 차이를 검사하고, 톤들의 값의 차이를 체크한다. 아주 작은 타이밍 또는 톤을 놓친다고 해서 전체적인 매치 오류(Match Failure)가 일어나지는 않는다.

톤 파일에 있는 각 톤의 경우, 매칭(matching)을 위한 음성 어레이와 Temporal 어레이를 구현해야 한다. 7- tone시퀀스와 2-tone 시퀀스의 비교 포인트가 없으므로, 가장 먼저, 톤을 비교해야 한다. 각 톤과 시간의 경우, 허용 편차 매개변수 내에 값이 존재하는지를 확인해야 한다. 최대 톤과 Temporal 편차는 정확한 음성 시퀀스 매칭(matching)에 있어서 중요하다. 최대 톤 또는 타임 편차를 증가시켜서 타이밍에 변화를 주거나 보다 자유롭게 음성을 생성할 수 있다. 자유 설정(liberal setting)은 틀린 탐지 결과를 만들 수 있으므로 주의해야 한다. 톤 편차 임계치를 5로 늘리고, Temporal 편차 임계치를 100000으로 유지하면, 정확한 시간에, 기대했던 패턴과 관련된 톤을 원격에서 입력할 수 있고, 패턴도 맞출 수 있다.

전체 패턴이 일치하면, ~/.toneFile에서 지정된 명령어가 실행되고, verbose 모드가 실행되면 결과가 프린트 된다. 다음 단계는, 어떤 것도 매치하지 않을 때 서브루틴을 종료하거나, 매치되면, 현재 톤과 타임 기록을 리셋한다.


Listing 10. 음성 패턴 생성
				
sub compareToneSequences 
{
 my $baseCount = @baseTones;
 my $countMatch = 0; # record how many tones matched

 for my $toneFromFile ( keys %toneHash )
 {
  my @confTones = split " ", $toneHash{$toneFromFile}{tones};
  my @confTimes = split " ", $toneHash{$toneFromFile}{times};

  my $confCount = @confTones;

  next unless( $confCount == $baseCount );

  # as a learning aid, the matching and non matching portions of the
  # comparison are printed out, so at least you can see what is going 
  # wrong while trying to remember your tone codes
  my $pos =0;
  my $toneMatchFail = 0;
  for( @baseTones )
  { 
   my $tonDiff = abs($confTones[$pos] - $baseTones[$pos]);
   my $tonStr = "t $pos b $baseTones[$pos] ".
          "c $confTones[$pos] \n";

   my $timeDiff = abs($confTimes[$pos] - $baseTimes[$pos]);
   my $timStr = "t $pos b $baseTimes[$pos] ".
          "c $confTimes[$pos] d $timeDiff\n";

   if( $tonDiff > $MAX_TONE_DEV )
   { 
    $toneMatchFail = 1;
    if( $option ){ print "NOTE DISSONANCE $tonStr" }
   }else
   { 
    if( $option ){ print "NOTE MATCH $tonStr" }
   }#if tone detected outside of deviation


   # if it's an exact match, increment the matching counter
   if( $timeDiff < $MAX_TIME_DEV ){
    if( $option ){ print "TIME MATCH $timStr" }
    $countMatch++;
   }else{
    if( $option ){ print "TIME DISSONANCE $timStr" }
    last;
   }# deviation check

   $pos++;

  }# for each tone to check 

  if( $countMatch == $confCount && $toneMatchFail == 0 )
  { 
   my $cmd = $toneHash{$toneFromFile}{ cmd };
   if( $option ){ print "run: $cmd\n" }
   $cmd =`$cmd`;
   if( $option ){ print "result: $cmd\n" }
   last;

  # otherwise, make the count of matches zero, in order to not reset
  }else
  { 
   $countMatch = 0;
  }

 }#for each tone in tone file

 # if the match count is zero, exit and don't reset variables so a longer
 # tone sequence can be entered and checked
 if( $countMatch == 0 ){ return() }

 # if a match occured, reset the variables so it won't match another pattern
 $toneCount = 0;
 @baseTones = ();
 @baseTimes = ();

}#compareToneSeqeunces

주 프로그램 로직

서브루틴이 있는 상태에서, 주 프로그램 로직으로 톤 시퀀스를 생성하거나, 데몬 모드(daemon mode)로 실행되어 톤을 듣고 명령을 실행한다. 사용자가 create mode의 "-c" 옵션을 지정하면 첫 번째 섹션이 실행된다. 간단한 타임아웃 프로세스가 사용되어 knock 시퀀스를 종료한다. 최대 타임아웃 길이 변수를 늘려서 톤 사이 중지(pause) 시간을 4초 이상 되도록 한다. 최대 타임아웃 길이를 4로 계속 둔다면, 프로그램은 종료하고, 현재 입력된 톤 시퀀스를 출력한다.


Listing 11. 타임아웃 프로세스
				
if( $option eq "-c" ){

 print "enter a tone sequence:\n";

 $startTime = getEpochSeconds(); # reset time out start

 while( my $sndPeekOutput = <STDIN> )
 { 

  $currTime = getEpochSeconds();

  # check if there has not been a tone in a while 
  if( $currTime - $startTime > $MAX_TIMEOUT_LENGTH ){

   $timeOut = 1; # exit the loop

  }else{

   # if a tone has been entered before timeout, reset timers so
   # more tones can be entered

   if( $toneCount != $toneAge ){
    $startTime = $currTime;  # reset timer for longer delay
    $toneAge = $toneCount; # synchronize tone counts
   }# if a new tone came in

  }# if timer not reached

  readTones( $sndPeekOutput );

  if( $timeOut == 1 ){ last }
 }#while stdin

 if( @baseTones ){
  print "place the following line in $ENV{HOME}/.toneFile\n\n";
  for( @baseTones ){ print "$_ " }
  print "_#_ ";
  for( @baseTimes ){ print "$_ " }
  print "_#_ (command here) _#_ <comments here>\n\n";
 }#if tones entered

주 로직의 두 번째 섹션에서는 sndpeek의 print 명령어의 결과를 읽는다. 타임아웃 임계치에 다다른 후에 음성 그룹들은 자동으로 리셋되어 개별 음성 패턴들을 구분한다. LISTEN_TIMEOUT 변수를 수정하여 음성 입력 시간을 더욱 빠르게 하거나, 타임아웃을 늘려서 더 광범위한 폭의 이벤트를 가진 톤 패턴을 얻을 수 있다.


Listing 12. LISTEN_TIMEOUT 수정
				
}else
{ 
 # main code loop to listen for tones and run commands
 readToneFile();
 $startTime = getEpochSeconds();

 while( my $sndPeekOutput = <STDIN> )
 { 

  $currTime = getEpochSeconds();

  if( $currTime - $startTime > $LISTEN_TIMEOUT ){

   $toneCount = 0;
   @baseTones = ();
   @baseTimes = ();
   $startTime = $currTime;
   if( $option ){ print "listen timeout - resetting tones \n" }

  }else{

   if( $toneCount != $toneAge ){
    $startTime = $currTime;  # reset timer for longer delay
    $toneAge = $toneCount;  # synchronize tone counts
   }# if a new tone came in

   compareToneSequences();

  }#if not reset timeout

  readTones( $sndPeekOutput );

 }#while stdin

}#if option set


주의 사항 및 보안 문제

공유 사이트...

cmdWhistle 프로그램은 마우스와 키보드 외에, 또 하나의 입력 방식을 제공한다. 하지만 cmdWhistle를 사용하여 시스템 인증이 필요한 일을 수행할 때 주의해야 한다.

리스너(listener)가 음성 시퀀스를 녹음 및 모사(mimic)하여 시스템에서 명령을 수행해야 한다는 뚜렷한 문제 외에도, 아직은 시기 상조인 음성 인증 (tonal authentication)과 관련된 문제들도 남아있다. 음성 시퀀스는 현재 두 자리수 "노트(note)"로 ~/.toneFile에 저장되고, 여기에 네 자리에서 9 자리로 딜레이(마이크로초)를 나타낸다. "password" 파일을 읽고, 톤 패턴을 매치하여 시스템에 액세스 하는 것은 비교적 쉽다. 정밀도를 낮추어서 일방(One-way) 해쉬를 사용할 수도 있지만, 위험 부담은 독자들의 몫이다.

기사의 원문보기



다운로드 하십시오

설명이름크기다운로드 방식
Source codeos-whistle.zip3KBHTTP

다운로드 방식에 대한 정보


참고자료

교육

제품 및 기술 얻기

토론

필자소개

Nathan Harrington은 IBM 프로그래머이며, 리눅스 및 리소스 배치 기술 관련 일을 하고 있다.

잘못된 도움말 신고

부정사용 신고

감사합니다. 이 항목은 운영자가 관심을 표시했습니다.


잘못된 도움말 신고

부정사용 신고

제출실패 신고. 나중에 다시 실행해주세요.


디벨로퍼웍스 로그인


IBM ID가 필요하세요?
IBM ID를 잊으셨습니까?


비밀번호를 잊으셨습니까?
비밀번호 변경

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관.

 


developerWorks에 처음 로그인하면 developerWorks프로파일이 생성됩니다.귀하의 프로파일에서 동의하신 내용이 공개되지만 이 사항은 언제든지 변경 가능합니다. 귀하의 성명(숨김으로 체크되어 있어도 표시됩니다)과 디스플레이 이름은 게시한 컨텐츠나 사이트 엑세스시 표시됩니다.

화면상에 보여지는 닉네임을 정하세요.

처음 developerWorks에 로그인할 때 프로파일이 작성되므로, 이를 위해 디스플레이 이름을 선택해야 합니다. 선택하신 디스플레이 이름은 developerWorks에 게시한 컨텐츠에 표시됩니다.

3글자 이상 31글자 이하의 길이로 사용 가능합니다. dW커뮤니티 내에서는 보안상 이메일주소를 제외한 다른 이름을 지정하셔야 합니다.

3개의 &이나 대쉬를 포함해주시고 31글자내로 제한해주세요.


developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관.

 


아티클 순위

의견

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=20
Zone=오픈 소스, 리눅스
ArticleID=194070
ArticleTitle=휘파람을 불며 명령어 작동하기 (한글)
publish-date=02062007
author1-email=harrington.nathan@gmail.com
author1-email-cc=

태그

Help
검색 필드를 사용하여 My developerWorks 내에서 해당 태그가 사용된 모든 종류의 컨텐츠를 검색하십시오.

태그를 더 많이 보거나 적게 보기 위해 슬라이더 막대를 사용하십시오.

인기 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 최고 인기 태그를 보여줍니다.

내 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 귀하의 태그를 보여줍니다.

검색 필드를 사용하여 My developerWorks 내에서 해당 태그가 사용된 모든 종류의 컨텐츠를 검색하십시오. 인기 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 최고 인기 태그를 보여줍니다. 내 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 귀하의 태그를 보여줍니다.