Praat Script를 이용한 음성분석과 변형

양병곤 지음



만수출판사

머리말

이 책은 지난 몇 년간 프라트(Praat)라는 음성분석 소프트웨어를 활용해 오면서 많은 시행착오를 통해 알게 된 스크립트 작성과 활용에 대한 지식을 공유하기 위해 쓰게 되었다. 저자는 연구프로젝트를 수행하기위해 매번 필요할 때마다 스크립트를 만들어 왔는데, 이 책에 들어있는 스크립트 가운데는 새벽잠을 설쳐가며 몇 주일에 걸쳐서 만든 것도 있고, 단숨에 만든 것도 있지만, 일단 만들면 컴퓨터로 많은 자료를 짧은 시간에 자동으로 처리할 수 있게 되어 큰 보람을 느끼곤 했다.

이 책은 스크립트를 주로 설명하기 때문에 프라트의 기본적인 사용 방법에 대한 세부적인 내용을 생략한 경우가 많다. 프라트의 메뉴구성이나 사용법에 대한 기초적인 공부를 할 분들은 먼저 저자의 홈페이지(Http://www.deu.ac.kr /~bgyang/praat/praat.pdf)에서 파일을 받아 읽어보길 바란다. 이 책은 4 장으로 되어 있다. 제 1장에서는 프라트를 설치하는 과정을 설명했고, 제 2장에서는 스크립트의 기초적인 개념과 활용에 대해 실례를 들어 개괄적으로 설명하였다. 제 3장에서는 여러 가지 짧은 스크립트를 이용한 강도, 피치, 포먼트에 대한 음성분석과 음성변형에 관한 스크립트를 개발하는 과정을 다루었고, 제 4장에서는 연구 프로젝트를 수행하면서 저자가 만들었던 여러 가지 음성분석과 합성용 파일을 만드는 복잡한 스크립트를 소개하고 필요한 부분에 설명을 덧붙였다. 저자의 프로그래밍 경험이 적어서 프라트의 스크립트 기능을 모두 다루거나 간결한 스크립트를 만들지는 못했지만, 이 책을 바탕으로 보다 나은 연구 발표가 많이 나오길 빈다.

이번에도 음성분석에 관심이 있는 보다 더 많은 분들이 부담 없이 읽으며 연구할 수 있도록 전자파일을 저자의 홈페이지(Http://www.dongeui.ac.kr/~ bgyang/praat/script.pdf)에 올려놓는다. 이 책에 나와 있는 일부 스크립트는 보건복지부 보건의료기술진흥사업의 연구프로젝트(02-PJ1-PG10-31401-0005)를 수행하며 만들었고 다른 연구원들에게도 배포하기위해 보고서 작성 경비의 일부를 출판비에 사용하였음을 밝힌다.

2004년 2월 19일

동의대 연구실에서 양 병 곤 씀

차 례

머리말 1

제 1 장 프라트 설치와 실행 7

제 2 장 프라트 스크립트의 기초 9

2.1 스크립트 작성 9

2.2 스크립트 작성할 때 유의사항 11

2.3 스크립트의 기본 구조 13

2.4 객체선택 16

2.5 프라트의 수치 표현과 문자열 표현 방식 17

2.6 수치계산의 예약함수 18

2.7 문자계산의 예약함수 19

2.8 숫자변수 21

2.9 수학계산 함수 21

2.10 변수표시 22

2.11 소리 만들기 공식 23

2.12 계산공식 26

2.13 객체의 속성 26

2.14 계산순위 28

2.15 조건절 29

2.16 되풀이 작업문 30

2.17 개별처리(Procedures) 34

2.18 스크립트 안에서 스크립트를 불러오기 36

2.19 작업끝내기 37

2.20 입력 폼(Form) 38

2.21 정보창에 나타내기 41

2.22 문의(Query) 43

2.23 하드디스크의 파일 읽기 43

2.24 하드디스크에 파일 저장하기 44

2.25 사용자와의 통신 46

2.26 셸 스크립트 46

2.27 음성편집창 선택부분의 스펙트럼 보기 49

2.28 음성을 여과하여 재조합하는 방법 50

2.29 행렬(Matrix) 51

2.30 행렬값 바꾸기 54

2.31 음성에 가우스 소음 섞기 56

2.32 소리의 강도 조절 57

제 3 장 음성 분석 스크립트 개발과정 59

3.1 피치를 구하는 스크립트 59

3.2 숫자음의 음성특성 분석 스크립트 60

3.3 음성구간 자동 분리하기 82

3.4 음성변형에 관한 스크립트 85

3.5 소리의 크기 줄이기 86

3.6 연속스펙트럼 그리기 87

3.7 음성의 재생속도 바꾸기 89

3.8 음성의 높이 바꾸기 91

3.9 음성의 피치, 크기, 속도를 모두 낮추기 92

제 4 장 논문에 사용된 스크립트 95

4.1 남성의 숫자음 발성에 나타난 화자변이 95

4.2 두 개 이상의 음절에 대한 음향파라미터값 구하기 100

4.3 라링고그라프 신호를 이용한 면적값과 변화율 비교 109

4.4 좁은대역스펙트럼의 차이값과 상관계수값에 의한 비교 112

4.5 대역별로 여과한 음성강도의 차이값과 상관계수에 의한

화자확인 연구 122

4.6 악성종양환자와 정상인이 발성한 모음의 좁은대역

스펙트럼값의 상관계수와 절대차이합 비교 134

4.7 SenSynPPC에 입력할 합성용 텍스트 파일 작성 139

참고문헌 164

그림 차례

그림 1.1 프라트 파일 받기 7

그림 1.2 파일을 저장할 하드디스크 지정하기 8

그림 2.1 스크립트 편집창 열기 9

그림 2.2 스크립트 편집창 10

그림 2.3 스크립트 편집창의 File메뉴 10

그림 2.4 스크립트 편집창의 Edit 메뉴 11

그림 2.5 스크립트 편집창의 Run 메뉴 11

그림 2.6 프라트 객체창에 음성을 불러온 모양 13

그림 2.7 스크립트를 Run으로 실행하기 14

그림 2.8 에러메시지 출력 14

그림 2.9 계산기 입력창 18

그림 2.10 음성 정보 창 20

그림 2.11 정현파를 만들어 객체창에 올리기 23

그림 2.12 소리 만들기 대화창 24

그림 2.13 빗금친 사선의 파형 만들기 27

그림 2.14 오류정보 표시 정보창 38

그림 2.15 form 파라미터 입력 대화창 39

그림 2.16 색깔 선택 대화창 만들기 40

그림 2.17 주기 계산 공식 41

그림 2.18 실행 에러 메시지 41

그림 2.19 안내문 출력 정보창 42

그림 2.20 구구단 출력 정보창 42

그림 2.21 스크립트 일시 중단 대화창 46

그림 2.22 스펙트럼 조각보기 47

그림 2.23 메뉴 더하기 명령어 48

그림 2.24 파일열기 에러메시지 48

그림 2.25 메뉴 감추기 명령어 49

그림 2.26 음성 여과하기 50

그림 2.27 객체창에 여과한 음성 나타내기 50

그림 2.28 엑셀로 보인 행렬의 예 51

그림 2.29 단순행렬 만들기 메뉴 52

그림 2.30 행렬 작성 대화창 52

그림 2.31 복합 행렬 대화창 53

그림 2.32 행렬값 구하기 54

그림 2.33 가우스 소음 섞기 위한 객체창의 메뉴 선택 56

그림 2.34 가우스 소음 섞기 대화창 56

그림 3.1 '아버지' 의 피치 곡선 그림 60

그림 3.2 피치값이 0이상인 시작점 62

그림 3.3 피치값이 0이상인 분석구간 64

그림 3.4 숫자음 6의 피치, 포먼트, 진폭, 스펙트로그램 81

그림 3.5 엑셀을 이용한 피치, 포먼트, 진폭 그래프 82

그림 3.6 숫자음 6의 일부를 잘라서 나타내기 85

그림 3.7 강도값 변형 그림 86

그림 3.8 좁은대역 연속 스펙트럼 만들기 88

그림 3.9 넓은대역 연속스펙트럼 88

그림 3.10 변형 편집창의 커서 위치 89

그림 3.11 속도변화 지점 지정하기 90

그림 3.12 숫자음 '6'의 지속시간 늘리기 91

그림 3.13 피치 낮추기 92

그림 4.1 '아버지' 분석 결과창 105

그림 4.2 피치 포먼트 주파수 결과 보이기 108

그림 4.3 피치와 진폭값을 곱하여 나타낸 그림 108

그림 4.4 여과된 음성의 강도값 곡선 평균 구하기 131

제 1 장 프라트 설치와 실행

프라트(Praat)는 암스테르담 대학의 Paul Boersma와 David Weenink가 만든 음성분석 및 변형 프로그램 패키지인데 이것은 인터넷 홈페이지 http:// www.fon.hum.uva.nl/praat/download_win.html 에서 무료로 받을 수 있다. 그림 1.1은 윈도우즈용 실행파일을 받는 곳인데, 한 칸 위로 올라가면 http:// www. fon.hum.uva.nl/praat/ 유닉스, 맥킨토시, 리눅스용 실행파일도 있으므로 사용자의 컴퓨터에 알맞은 것을 받으면 된다. 이 책에서는 독자의 대부분이 윈도우즈를 많이 사용한다고 가정하고 윈도우즈용 프라트에 대해서 설명한다. 프라트의 메뉴구성이나 기능은 어떤 종류의 컴퓨터에서도 비슷하거나 동일하기 때문에 이 책의 설명을 따라 사용하면 큰 어려움은 없을 것이다.

그림 1.1 프라트 파일 받기

다운로드 과정은 그림 1.1과 같이 이 홈페이지의 두 번 째 줄의 praat4122 winsit.exe를 한번 클릭 하고 저장할 하드디스크의 폴더를 선택하면 된다. 익스플로러로 인터넷을 사용하는 경우에는 한번 클릭으로 그림 1.2와 같이 저장할 하드디스크 폴더를 선택하는 대화창을 보여주지만, 넷스케이프로 접속했을 때는 마우스의 오른쪽 단추를 누르고 디스크에 저장하기를 선택해야한다.

그림 1.2 파일을 저장할 하드디스크 지정하기


가능하면 파일을 다운로드하기 전에 미리 자신의 하드디스크인 C:드라이브에 Praat라는 폴더를 만들어 그곳에 다운로드할 파일을 저장하고 압축을 풀도록 한다. 이어서 익스플로러를 닫고 하드디스크에 저장된 파일 praat4122_winsit.exe 을 찾아 두 번 누르면 자동으로 압축된 파일이 풀리고 praat.exe란 이름의 실행 프로그램이 아래와 같은 경로에 만들어 진다.

C:\Praat\praat.exe

이 책의 스크립트에 제시되는 음성자료는 C:\Praat\Sounds 폴더에 저장하는 것으로 가정한다. 실행프로그램을 자주 사용할 경우에는 바탕화면에 [바로가기 만들기]를 해주면 된다. 윈도우 왼 쪽 아래의 시작메뉴에 넣고 싶으면 마우스로 [시작]을 누른 뒤, 이어서 [작업표시줄 및 시작]메뉴를 누르고 시작메뉴의 사용자 정의 대화창에서 [추가]단추를 눌러 저장된 폴더를 찾아 하드디스크의 경로를 입력해 주면된다. 이어서 [다음]단추를 누르고 저장할 폴더이름을 선택한 뒤 praat.exe라는 이름을 그대로 받아들이고 [확인]단추를 누르면 작업 표시줄에 등록이 된다. 다음부터 프라트를 실행할 때는 마우스로 바탕화면의 왼 쪽 아래에 있는 [시작메뉴-->프로그램-->시작프로그램-->praat.exe]를 차례로 눌러 선택하여 실행시키면 된다. 가능하면 바탕화면에서 [바로가기]를 이용하는 것이 시간을 절약할 수 있다.

제 2 장 프라트 스크립트의 기초

프라트를 사용해보면 많은 수의 파일을 불러와 분석하고 그 결과를 자료로 저장하는 일이 되풀이 되는 경우가 많다. 만약 녹음한 어떤 음성파일을 분석하는데 사용하는 방법을 또 다른 파일에서도 이용하게 된다면 스크립트를 이용하는 것이 매우 편리하다. 다행히 프라트에서 동작하는 거의 모든 작업들이 자동으로 기록되기 때문에 실제 스크립트를 만드는 과정은 그다지 어렵지 않다고 할 수 있다. 이 장에서는 주로 프라트의 스크립트에 대한 기본적인 개념과 구성을 살펴보기로 한다.

2.1 스크립트 작성

스크립트를 만들려면 프라트를 실행한 뒤 그림 2.1과 같이 화면 맨 위의 기본메뉴 가운데 Control을 선택하고 그 아래의 하위메뉴인 New script를 선택하면 된다. 이미 만들어 놓은 스크립트를 불러올 때는 그 아래의 Open script를 클릭 하고 파일선택 대화창에서 원하는 폴더로 들어가서 스크립트 파일을 열면 된다.

그림 2.1 스크립트 편집창 열기


New Praat script를 마우스로 클릭 하면 그림 2.2와 같은 편집창이 나타난다.

그림 2.2 스크립트 편집창

스크립트 편집창의 메뉴 구성을 보면 그림 2.3과 같다.

그림 2.3 스크립트 편집창의 File메뉴

그림 2.3의 파일메뉴에는 새 스크립트를 만들 때 사용하는 New, 이미 작성한 스크립트를 불러오는 Open...이 있고, 작업 후 저장할 때는 Save를, 다른 이름으로 저장하려면 Save as...를 이용하면 된다. 그 다음에 나와 있는 Add to fixed menu...는 만들어진 스크립트를 프라트의 객체창의 기본메뉴 또는 그림창의 기본메뉴 밑에 넣을 수 있다. Add to dynamic menu...는 객체창에 올려지는 메뉴로서 사용자가 지정한 속성의 조합에 맞을 때만 메뉴로 나타난다. 예를 들어, 음성파일 "Sound"라는 속성을 지정해두면 Pitch나 Spectrogram 등 다른 속성을 가진 객체를 선택했을 때는 흐려진다. 마지막의 Close메뉴는 스크립트 편집창을 닫는다. 창의 오른 쪽 위의 네모박스를 클릭해도 닫힌다. 덧붙여, 메뉴 New 옆에 있는 Ctrl-N은 키보드의 왼쪽 맨 아래에서 두 번째에 있는 컨트롤키를 누른 채 N 키를 누르면 메뉴의 New를 마우스로 클릭 한 것과 동일한 결과를 보인다. 이러한 단축키를 이용하면 보다 빨리 작업을 할 수 있다.

그림 2.4의 Edit메뉴에는 다음과 같은 하위메뉴가 있다.

그림 2.4 스크립트 편집창의 Edit 메뉴

그림 2.4의 Edit메뉴에는 스크립트의 일부를 잘라 내거나(Cut), 복사하거나(Copy) 붙이기(Paste)기능이 있고 Erase로 임시메모리에 보관하지 않고 지워버릴 수 있다. 맨 위의 Cannot undo는 스크립트를 실행하다가 중지할 수 없기 때문에 보통 편집창에 나와 있는 Undo가 표시되지 않았다. Clear History는 메모리에 이미 저장된 동작기록들을 임시메모리에서 모두 지우고 지금부터 하는 작업을 기록할 때 편리하다. 프라트에서 사용자가 마우스를 클릭 하거나 메뉴를 선택하여 실행하는 거의 모든 작업들이 기록이 되어 History에 임시로 저장되므로 이것을 활용하면 스크립트를 처음부터 하나씩 모두 타자하여 작성하지 않고서도 많은 스크립트를 만들 수 있다. 마지막으로 그림 2.5의 Run메뉴에는 전체스크립트를 실행해주는 Run이 있고 스크립트로 만든 파일의 일부만을 실행하려면 마우스로 원하는 부분을 선택한 다음 Run selection을 실행시키면 된다.

그림 2.5 스크립트 편집창의 Run 메뉴

2.2 스크립트 작성할 때 유의사항

스크립트를 작성할 때 주의할 점은 각 명령어 대화창에 나오는 파라미터의 입력 숫자는 명령어 다음에 차례로 제시하면 되고, 체크단추는 yes, no로 표시되며, 라디오단추(╃)의 선택은 해당부분의 영어어구로 나타나게 된다. 스크립트에 대한 설명부분은 줄 맨 앞에 !, #, ; 가운데 하나의 기호를 넣으면 실행하지 않는다. 이 기호를 사용하여 필요한 설명을 붙일 수 있다. 줄 맨 앞에 ...으로 시작되면 윗줄에 연속된 단어나 표현을 나타낸다.

객체창에 불러온 객체를 마우스로 선택하는 것은 {select 객체이름}을 쓰고 거기에 마우스로 덧붙여 선택하는 동작은 {plus 객체이름}을 제외할 때는 {minus 객체이름}을 사용한다. {}는 스크립트를 나타내는 명령어 가운데 한글이 포함된 경우를 임의로 구별시켜주기 위해 이 책의 본문 중에서만 사용하며 실제 스크립트에서는 없어야 한다. 모든 객체를 한꺼번에 선택하려면 select all을 사용한다. 선택된 음성파일의 이름을 정보창에 나타내려면 다음과 같이 입력해보면 된다.

name$=selected$("Sound")

print 'name$'

프라트의 숫자변수가 가질 수 있는 값의 범위는 -10308에서 +10308까지이기 때문에 계산처리상의 오류는 없다고 볼 수 있다. 각 변수에 숫자 값을 대입하려면 count=100과 같이 하면 된다. 변수 값의 첫 글자는 반드시 영어 소문자가 되어야하고 그 다음 글자는 문자나 숫자 또는 밑줄을 사용해도 된다. 숫자 값의 자릿수를 표시하려면 숫자 변수 뒤에 'count:3'으로 하면 소수점 세 자리까지만 정보창에 결과를 표시해준다. 반올림한 정수로 표시하려면 'count:0'을 하면 된다. 일반적으로 유효한 자릿수는 피치나 포먼트일 경우에는 0으로 지정하면 되고 시간일 때는 3을 주어 밀리초 까지 나타내도록 하면 된다. 소수점 이하의 자릿수가 많다고 해서 정확한 것은 아니며, 통계처리에서는 소수점이 많을수록 유효 단위 값이 달라지기 때문에 비록 유의미한 결과가 나왔더라도 실제 들어보거나 합성하여 비교해보면 무의미한 차이인 경우가 발생하게 된다. 예를 들어, 모음 음절의 지속시간 차이 값이 32.6593847394 ms라면 실제 우리가 관심을 두어야 할 부분은 소수점아래 숫자를 제외한 32 ms이다.

문자변수 이름은 끝 부분에 $표시를 해야 하며 name$="Sound a"와 같이 입력할 문자의 양쪽에 인용부호를 넣는다. tab$나 newline$는 변수사이에 탭 키를 누르거나 새 줄로 바꾸어 표시하고자 할 때 사용하는 예약어다. 참과 거짓의 판단에 사용되는 문자간의 비교에는 a$=b$로 표시하면 a, b 두 변수가 같을 때는 true 값을 돌려주고 a$<>b$로 표시하면 그 반대로 서로 다를 때 true 값을 돌려준다. 물론 크기비교 (<, >, >=, <=)나 문자끼리 더하거나 {a$+b$}, 빼기 {a$-b$}를 사용할 수 있다. 파일이름에 일정한 확장자를 붙이거나 제거하는데 도움이 된다. 아래와 같이 하면 선택한 파일이름에 덧붙여 확장자를 첨가하여 준다.

name$=selected$("Sound")

textname$=name$+".txt"

print 'textname$'

결과 --a.txt

그 외에도 문자의 길이를 알아내려면 length(name$)로 하면 된다. 전체 문자 가운데 지정한 개수의 문자를 왼 쪽부터 시작하여 꺼내려면 left("name", 3)로 하면 "nam"이 결과로 나오며 오른 쪽부터 시작하여 꺼내려면 right("name", 3)로 하면 "ame"가 결과로 나온다. 물론 중간에서 일부를 꺼내려면 mid("name", 3, 2)를 하면 "me"가 선택된다. 각 문자열의 왼 쪽에서부터의 순서 상 위치 값을 알아보려면 position=index("seoul", "o")하면 position 값은 3이 된다. 문자가 없을 때는 0을 돌려준다. 오른 쪽에서부터의 특정한 문자열의 위치 값을 알려면 rindex라는 함수를 이용하면 된다.

2.3 스크립트의 기본 구조

가장 간단한 스크립트를 만들어 보면 먼저 그림 2.6과 같이 객체창에 모음 "a"라는 음성을 불러온다.

그림 2.6 프라트 객체창에 음성을 불러온 모양


이어서 Control기본메뉴를 선택하고 그 아래 New Script를 실행하여 스크립트 편집창을 연 뒤 그림과 같이 본문에 Play라고 입력한다. 이어서 스크립트창의 메뉴에서 Run을 클릭하면 "아"라는 음성이 컴퓨터의 스피커를 통해 나온다.

그림 2.7 스크립트를 Run으로 실행하기

이 때 play라고 첫글자를 소문자로 하면 그림 2.8과 같이 에러메시지가 나타난다.

그림 2.8 에러메시지 출력


프라트 스크립트에서는 예약된 단어들은 주로 대문자로 시작된다. 대화창이 나와서 사용자가 어떤 숫자나 문자를 입력하거나 단추 가운데 하나를 선택하는 경우의 명령어는 모두 ...로 끝난다. 예를 들어, 피치분석을 할 때는 분석간격값과 최소피치값, 최대피치값을 지정하여 그 범위 안에 들어오는 값들을 분석해야하기 때문에 이런 파라미터들을 숫자로 입력해야한다. 이때 스크립트로 만들려면 다음과 같이 한다.

To Pitch... 0 75 600

또한 피치분석방식 가운데 좀 더 가중치를 입력하여 정확히 구하려면 다음과 같은 방식을 사용하는데 이 방식을 선택하는 라디오모양의 단추를 선택하느냐 아니냐에 따라 yes, no로 각각 표현된다.

To Pitch (ac)... 0 75 15 yes 0.03 0.45 0.01 0.35 0.14 600

여러 개 가운데 하나를 나타내는 라디오 단추가 있는 경우에는 선택된 문자열이 연결되어 나타난다. 보통 두 개 이상의 단어(예, US Letter)로 되어 있을 때는 빈칸이 연결되어 있다는 점을 나타내기 위해 겹따옴표로 표시한다("US Letter").

그림창에 단어나 문자열을 표시할 경우에는 겹따옴표 없이 그대로 표현해야한다.

Text... 2 Centre 3 Half This is sound a.

꼭 인용부호를 나타내려면 아래와 같이 표시해도 된다.

Text... 2 Centre 3 Half This is sound "a".

거의 모든 문자열은 맨 뒤에 표시되도록 한다. 메뉴를 첨부할 때 인용부호를 삽입하려면 겹따옴표를 이중으로 해야 한다.

Add menu command... Objects New "Create a ""computer""

파일을 불러오거나 하드디스크에 저장할 때, 경로를 반드시 표시해줘야 한다. 보통은 다음과 같이 모든 경로를 다 나타낸다.

Read from file... C:\Praat\a

만약 파일이 맨 위의 바탕화면에 나타나면 다음과 같이 표시된다.

Read from file... C:\Documents and Settings\bgyang\바탕 화면\a

이런 완전한 경로를 나타내지 않고 프라트 실행파일과 같은 폴더 안에 음성파일이 있는 경우에는 상대적으로도 표시할 수 있다.

Read from file... ..\a

다음은 프라트 스크립트에서 빈칸, 설명, 연속된 줄을 어떻게 나타내는지에 대해 살펴보기로 한다.

프라트 스크립트에서 명령어 줄 앞의 빈칸이나 탭은 아무리 많아도 스크립트 실행에는 관계가 없다. 가능하면 적어도 3개 이상의 빈칸을 두어 들여쓰기를 하면 수정하거나 읽을 때 편리하다.

예를 들어, 3개의 수를 곱하여 더한 합을 구하는 다음 스크립트를 생각해보자.

sum=0

for i to 3

for j to 3

sum+=i*j

endfor

endfor

print 'sum'

echo 곱한 값의 합은 'sum'이다.

이것을 실행하면 36이 된다. 이렇게 스크립트 앞에 아무런 문자가 없는 빈칸들은 무시되므로 단락을 지어 명령어 무리를 만드는 것이 좋다.

스크립트 안에 설명을 덧붙여 놓으려면, 해당 줄 앞에 !, #, ;와 같은 부호를 사용하면 된다.

! 다음 명령어는 75∼600 Hz 범위의 피치값을 구하는 것임

To Pitch... 0 75 600

만약 프라트 스크립트에서 너무 긴 명령어를 써야 하거나 작은 컴퓨터 화면에 모든 내용을 나타내기 어려울 경우에는 계속 이어진다는 것을 표시하는 ...을 사용한다.

예를 들어, 다음과 같은 텍스트를 그림창에 나타내려면 따라오는 줄이 연속되어 있다는 것을 ...으로 표시할 수 있다.

Text top... yes Praat is a wonderful speech analysis tool. I want you

...to try it once.

2.4 객체선택

객체창에 불러온 객체를 선택할 때 스크립트에서는

select 객체이름

을 사용한다.

만약 같은 이름의 객체가 있으면 목록 가운데 가장 아래 것을 선택하므로 파일이름이 동일하더라도 차례로 분석해 결과를 나타내는 데는 문제가 없다.

두개 이상의 객체를 선택하려면 다음과 같이 나타낸다.

select 객체이름

plus 객체이름

다음 스크립트는 이와는 반대로 작용한다.

select 객체이름

minus 객체이름

모든 객체를 한꺼번에 선택하여 객체창에서 제거하려면 다음과 같이 표현하면 된다.

select all

Remove

파일이름 대신에 각 객체에 붙여진 고유번호(ID:Identification)를 이용하여 선택할 수 있다.

select 12

위의 명령어는 프라트를 실행한 뒤 12번째 만든 객체를 선택하는 것이다. 실제 각 객체의 번호를 하나씩 기억하고 있을 수 없기 때문에 다음과 같이 선택된 객체의 고유번호를 알아내어 처리하는 방법도 있다.

soundID=selected("Sound")

select 'soundID'

또한 선택된 음성객체의 이름을 다음과 같이 불러와 하나의 변수(name$)로 지정할 수 있다.

name$=selected("Sound")

pitchname$=selected("Pitch")

이 때 객체창에 불러와 있는 음성객체나 피치객체 가운데 맨 위의 것을 가리킬 때는 위와 같이 아무런 숫자 없이 나타낸다. 다섯 번째 객체를 나타내려면

name$=selected("Sound", 5)

을 쓰고 맨 아래의 음성객체를 나타내려면

name$=selected("Sound", -1)

으로 표시한다.

그런데 만일 객체창에서 선택한 이름이 name$에 지정되더라도 다른 음성객체를 가져오게 되면 순서가 달라지는 경우가 생기므로 앞서 설명한 고유번호를 활용하는 것이 필요하다.

선택된 객체의 수를 나타내려면 지정된 함수를 사용한다.

number=numberOfSelected("Sound")

print 'number'

위와 같이 스크립트를 만들고 다섯 개의 음성객체를 선택한 뒤 실행해보면 정보창에 "5"라고 나타난다.

2.5 프라트의 수치 표현과 문자열 표현 방식

프라트의 수치계산은 Control아래 Goodies의 Calculator와, 대화창의 수치입력칸에 계산공식을 넣어 사용할 수 있다. 먼저 계산기창에서 사용할 수 있는 예를 살펴보자. 그림 2.9와 같이 입력하고 OK단추를 누르면 정보창에 25란 값이 나타난다.

그림 2.9 계산기 입력창

문자열끼리도 더할 수 있다. 계산기창에 "Cal"+"culator"라고 입력하면 정보창에 Calculator라고 나타난다. 물론, "Calculator"-"culator"라고 입력하면 정보창에 Cal만 나타난다. 이 기능을 이용하면 다른 분석용 대화창의 수치값 칸에 계산공식을 입력하기 전에 제대로 작동할지 미리 확인하는데 편리하다.

이러한 문자열 기능을 이용하여 .wav로 끝나는 파일을 디스크에서 불러올 수 있다.

soundName$="aboji"

fileName$=soundName$+".wav"

Read from file... 'fileName$'

덧붙여 다음 스크립트를 실행하면 음성파일이름에서 일부를 제외하고 그림창에 인쇄할 수 있다.

soundName$="aboji.aifc"

fileName$="'soundName$'"-".aifc"

Viewport... 1 6 1 5

Text... 1 Centre 1 Half 'fileName$'

2.6 수치계산의 예약함수

예약함수란 프라트에 이미 들어있는 함수로서 값을 처리하는데 매우 편리하다. 물론 스크립트의 다른 곳에서 예약된 용어를 변수나 함수로 사용해서는 에러가 발생할 수 있다.

곱셈은 5*5와 같이 표시하고, 나눗셈은 5/5로 표현한다. 덧셈은 5+5, 뺄셈은 5-5, 제곱은 5^2이다. 5의 6제곱(5x5x5x5x5x5)은 5^6으로 나타낸다. 제곱근은 sqrt(2)가 된다. 그 외에도 삼각함수 등이 포함되어 있는데 sin(1/3*pi)는 Ր/3의 sine값을 구해준다.

2.7 문자계산의 예약함수

Control기본메뉴의 Goodies아래 Calculator를 연 다음 length("mydocuments")와 같이 입력하면 정보창에 11이라고 단어안의 문자수를 출력해 준다. 두 번째 제시된 문자열이 첫 번째 문자열 가운데 몇 번째 문자열 위치에서 시작되는지를 보여주는 index("mydocuments", "ments")를 입력하면 7이란 숫자가 정보창에 뜬다. 덧붙여, 문자열 가운데 마지막으로 나타나는 위치를 구하는 경우에는 rindex("mydocumentsments", "ments")를 사용한다. 결과는 12가 된다. 이런 문자열 함수들은 파일이름이나 파일의 내용을 검색할 때에 사용할 수 있으며, 확장자의 위치를 찾아 그 앞부분만을 선택하여 파일이름으로 그림창에 표시하거나 저장할 때 사용할 수 있다.

숫자로 된 문자열 가운데 소수점아래 자리수를 지정하려면 fixed$(수치, 소수점아래 자리수)를 이용한다. 예를 들어, fixed$(12.34567,3)하면 12.345를 나타내고, fixed$(12.34007,3)하면 12.340을 나타낸다. percent$(수치, % 소수점아래 자리수)도 마찬가지로 출력된다.

특정한 문자열의 위치를 찾은 다음 그 위치를 기준으로 왼쪽으로 또는 중간의 위치에서 오른쪽으로 몇 자를 선택하려면 다음과 같은 함수를 사용한다. 먼저 left$("mydocuments",5)를 하면 mydoc가 선택된다. mid$("mydocuments",7,4)를 입력하면 ment가 선택된다. date$()를 하면 날짜를 문자열로 받아 정보창에 Sun Jan 18 12:39:28 2004와 같이 나타내어준다. 물론 이런 결과값을 변수로 처리하려면 now$=date$()로 정의할 수 있다. 다음 스크립트는 현재의 날짜와 시간을 받아서 한국식으로 정보창에 표시해준다.

clearinfo

now$=date$()

weekday$=left$(now$,3)

day$=mid$(now$,9,2)

month$=mid$(now$,5,3)

year$=right$(now$,4)

print 'year$''tab$''month$''tab$''day$''tab$''weekday$'

정보창의 출력은 다음과 같다.

2004 Jan 18 Sun

그림 2.10 음성 정보 창

입력된 정보 가운데 일부를 추출하는 함수로는 extractNumber, extractWord$, extractLine$ 등이 있다. 객체창에 음성을 불러온 뒤 Edit단추를 눌러 음성 편집창으로 열고 편집창의 Query기본메뉴 아래의 하위메뉴인 Settings report를 실행하면 그림 2.10과 같이 정보창에 음성과 관련된 모든 내용을 나타내어 준다.

이것을 편집창 스크립트에 문자열 변수로 받아들인 뒤 최대주파수를 구하려면 다음 스크립트를 이용하면 된다.

clearinfo

report$=Settings report

duration=extractNumber(report$, "Editor end:")

print 'duration'

정보창에는 다음과 같이 결과값이 나타난다.

0.34471655328798184

프라트의 스크립트에서 사용하는 변수, 수치표현, 함수, 문자열, 수치계산 등은 일반 컴퓨터 프로그램인 베이식의 표현양식을 따랐다.

먼저 변수값을 표시하는 방법을 살펴보자. 변수란 컴퓨터에서 여러 가지로 변하는 값을 가질 수 있는 임의의 문자나 숫자값을 가질 수 있는 문자나 단어를 말한다. 스크립트를 작성할 때 그때그때 필요한 값을 변수로 지정하여 편리하게 활용할 수 있다.

2.8 숫자변수

숫자변수는 정수값일 때는 -1,000,000,000,000,000에서 +1,000,000,000,000,000까지의 값을 가질 수 있다. 실수에서는 -10308에서 +10308까지의 값을 가질 수 있다. 이것은 308자리의 숫자를 말한다. 가장 작은 수는 -10-308에서 +10-308까지의 값들을 가질 수 있다. 이것은 소수점 이하 308자리를 말한다.

숫자를 나타낼 때는 3.14159, -3.14159와 같이 소수점으로 나타낼 수 있고, 아주 큰 수일 경우에는 지수를 이용하여 3.14159e5로 하면 314159값을 말한다. 또한 3.14159e-5를 하면 0.0000314159를 나타낸다. 314.5%도 3.1415를 나타낸다. 그러나 자릿수가 기본값을 넘게 되면 계산상의 에러를 나타내므로 주의해야한다. 예를 들어 1e200*1e100의 결과값은 1e300이 되지만, 1e300*1e100은 계산되지 않고 undefined란 메시지가 나오게 된다. 나누기에서도 1e-300/1e100을 하면 결과값이 0이 된다. 상수값으로는 e와 pi가 있는데, e값은 2.7182818284590452354가 배당되어 있고, pi값은 3.14159265358979323846이 입력되어 있다. 다음 스크립트를 실행하면, 정보창에 일부만 인쇄된다.

clearinfo

evalue=e

pivalue=pi

print 'evalue''newline$'

print 'pivalue''newline$'

결과값은 다음과 같다.

2.718281828459045

3.141592653589793

이것은 소수점아래 16자리까지 저장되어 있기 때문이다. 덧붙여, 계산기에 3.149999999999999라고 입력하고 OK단추를 누르면 동일한 숫자가 정보창에 나타나지만, 3.1499999999999999라고 소수점이하 17 자리로 된 숫자를 입력하면 결과값이 3.15로 처리된다. 이렇게 자리수를 제한한 것은 아마 컴퓨터 연산에 필요한 메모리의 한계와 이를 최적으로 배당하여 처리하기위한 것으로 짐작된다.

2.9 수학계산 함수

공식에 사용할 수학계산 함수들은 프라트에 미리 예약된 것으로 다양하게 활용할 수 있다. 모든 목록은 프라트의 Help메뉴아래 Formulas Tutorial을 클릭 하고 그 아래의 연결 개체 가운데 Mathmatical functions를 누르면 된다. 이 책에서는 음성분석과 관련된 스크립트 작성에 자주 사용될 일부분의 함수만 살펴보기로 한다.

abs(x)는 +/-부호를 없앤 절대값을 구할 때 사용한다. round(x)는 정수값을 구해준다. randomUniform(최소값, 최대값)은 지정된 최소값과 최대값 사이의 값을 임의로 구해준다. randomInteger(최소값, 최대값)은 지정된 최소값과 최대값 사이의 값으로 정수값을 구해준다. randomGauss(평균값, 표준편차)는 지정된 평균값에서 표준편차값 사이의 값을 임의로 구해준다. hertzToBark(x)는 음향물리값인 Hertz단위의 값을 청각척도인 Bark로 변환하여 준다. 그 반대는 barkToHertz(x)를 사용한다. hertzToMel(x)는 음향물리값인 Hertz단위의 값을 청각척도인 Mel로 변환하여 준다. 그 반대는 melToHertz(x)를 사용한다. hertzToSemitones(x)는 음향물리값인 Hertz단위의 값을 로그음악척도인 semitone으로 변환하여 준다. 그 반대는 semitonesToHertz(x)를 사용한다. 피치값을 음계에 맞춰 표현할 때 사용할 수 있다.이 모든 함수의 첫 글자는 소문자이다.

2.10 변수표시

변수의 이름은 영어 소문자로 써야하고, 문자, 숫자나 밑줄(Underscore)을 이어서 하나의 이름으로 연결시킬 수 있다. 예를 들어, 정현파를 만드는 스크립트에서 주파수값을 1000 Hz로 지정하여 객체창에 올리고 싶을 때는 다음과 같이 표현한다.

frequency=1000

Create Sound... sinewave 0 1 22050 1/2 * sin(2*pi*frequency*x)

위의 스크립트를 이용하여 다섯 개의 주파수에 해당하는 정현파를 만들려면 다음과 같이 덧붙일 수 있다.

for i to 5

frequency=1000*i

Create Sound... sinewave 0 1 22050 1/2 * sin(2*pi*frequency*x)

endfor

위의 스크립트를 실행하면 다섯 개의 정현파가 객체창에 올려진다.

변수명에 문자열을 지정하려면 변수명 끝에 이것이 문자열을 나타내는 변수라는 $표시를 반드시 넣어야하고 대입되는 값도 겹인용부호를 표시해야한다.

sinename$="1000Hz"

두 개의 문자열을 합칠 때는 +를 사용하고 숫자값을 문자열로 변환하려면 해당변수를 겹따옴표로 감싸도록 한다.

sinename$="'frequency'"+"Hz"

앞서 만든 주파수의 정현파의 주파수를 객체창에 표시하고자 한다면 다음과 같이 수정할 수 있다.

for i to 5

frequency=1000*i

sinename$="'frequency'"+"Hz"

Create Sound... 'sinename$' 0 1 22050 1/2 * sin(2*pi*frequency*x)

endfor

위의 스크립트를 실행하면 객체창에 그림 2.11과 같이 다섯 개의 정현파가 올려진다.

그림 2.11 정현파를 만들어 객체창에 올리기


2.11 소리 만들기 공식

음성학 강의에 사용할 정현파나 연구를 하다보면 소프트웨어의 기능을 점검하기위해 소리를 만들어야할 경우가 있다. 소리를 만들려면 객체창의 New기본메뉴의 아래 Sound아래의 Create Sound...를 이용하면 된다. 이 메뉴를 클릭하면 그림 2.12와 같은 대화창이 나타난다.

여기서 Name은 객체창에 올려질 소리의 이름이고, 시작시간과 끝나는 시간을 입력한다. 대화창에는 표본속도를 22050Hz로 1초분의 소리를 만들도록 선택되어 있다. 그 아래에 있는 Formula 칸에는 1/2 * sin(2*pi*377*x) + randomGauss(0,0.1)라고 입력되어 있는데 첫 번째 분모인 1/2이 소리의 진폭을 결정하는 값이 된다. 소리의 진폭값이 최대 1파스칼에서 최저 -1파스칼 사이에 분포하게하려면 1을 주면되고, 1/2이 되면 최대 0.5파스칼에서 최저 -0.5파스칼 사이에 분포한다. 보통 이 값의 분모가 클수록 출력음의 진폭이 작아지고 적을수록 커진다.

그림 2.12 소리 만들기 대화창


다음의 sin(2*pi*377*x)에서 377부분은 주파수를 말한다. 이 값이 크면 피치가 높은 음이 되고 작으면 피치가 낮은 음이 된다. 다음에 나오는 x는 시간점마다 진폭값이 달라지게 한다. 예를 들어, 22050 Hz의 표본속도라면 x값은 1/22050초, 2/22050초, 3/22050초 등의 값으로 커진다. 마지막으로 덧붙여진 + randomGauss(0,0.1)는 소음을 더해주는 공식이다. 첫 번째 0은 기준선이 되고 0.1은 표준편차를 나타낸다. 표준편차가 커질수록 소음이 크게 된다.

선택한 음성 파일 이름을 변수로 지정한 뒤 이것을 그림창에 인쇄하려면 다음과 같이 한다.

name$=selected$("Sound")

Text top... no 'name$'

이 때 selected$의 문자열을 표시하는 $가 없으면 실행이 안 된다. 변수끼리 곱하거나 더하여 다른 변수의 이름에 넣을 수 있다.

clearinfo

s=10

ss=s*s

sss=s*s*s

print 's', 'ss', 'sss'

첫 번째 줄의 clearinfo는 정보창에 들어있는 모든 내용을 지워버리라는 명령어다. 위의 스크립트를 실행하면 정보창에 다음과 같이 나타난다.

10, 100, 1000

만약에 소수점 이하 자릿수를 조절하려면 콜론다음에 자릿수를 표시하면 된다.

clearinfo

s=9.12345

print 's:0', 's:1', 's:2', 's:3', 's:4', 's:5'

위의 스크립트를 실행하면 다음과 같이 정보창에 나타난다.

9, 9.1, 9.12, 9.123, 9.1235, 9.12345

이 기능을 이용하면 피치나 포먼트 값 등 소수점 이하 긴 숫자를 지우고 원하는 정수 값만 정보창에 나타내거나 하드디스크에 저장할 수 있다.

덧붙여, 비율을 나타내고 싶을 때는 자릿수와 %를 이용하면 된다.

clearinfo

s=9.12345

print 's:5%'

위의 스크립트를 실행하면 정보창에 다음과 같이 나타난다.

912.34500%

이외에도 스크립트의 예약된 문자열 변수로는 newline$, tab$, shellDirectory$가 있다. newline$는 다음 줄로 바꾸라는 변수이고, tab$는 키보드의 탭키를 누르는 효과를 보인다. 마지막 예약변수는 유닉스나 도스에서 사용한다. newline$와 tab$를 이용하면 정보창에 줄을 바꾸거나 일정한 간격을 띄어서 결과값을 깨끗하게 나타내거나 하드디스크에 파일로 저장할 때 큰 도움이 된다. 다음 스크립트를 실행해보자.

clearinfo

s=9.12345

print 's:0''tab$' 's:1''tab$''s:2''newline$'

print 's:3''s:4''s:5'

위의 스크립트를 실행하면 다음과 같이 정보창에 나타난다.

9 9.1 9.12

9.1239.12359.12345

만약 newline$가 없었다면 다음과 같이 모두 연이어 나타날 것이다.

9 9.1 9.129.1239.12359.12345

2.12 계산공식

프라트에서는 임의의 변수값을 입력한 다음 변수끼리 숫자값을 계산하는 스크립트를 만들 수 있다. 다음은 가로 20cm 세로 30cm 인 삼각형의 면적을 구하여 정보창에 나타내는 스크립트이다.

clearinfo

length=20

height=30

area=(length*height)/2

print The area is 'area'.

물론 공식 가운데 변수나 공식을 사용해도 된다. 이 때 마지막에 오는 변수 다음에 빈칸이 없어야한다. 스크립트를 만드는 과정에서 명령어 끝부분의 빈칸 때문에 실행이 안 되는 경우가 있으므로 주의해야 한다. 또한 마지막 변수 위치에서는 겹따옴표를 사용해서는 안 된다. 다음은 앞서 만든 정현파 스크립트에서 frequency대신 공식 안에 직접 숫자값을 넣은 경우이다.

for i to 5

frequency=1000*i

sinename$="'frequency'"+"Hz"

Create Sound... 'sinename$' 0 1 22050 1/2 * sin(2*pi*1000*i*x)

endfor

2.13 객체의 속성

객체창에 불러온 객체의 속성을 이용하면 빠르게 계산하거나 변형할 수 있다. 예를 들어, Sound_aboji라고 하고 그 뒤에 마침표와 속성이름을 써서 값으로 사용할 수 있다. Sound_aboji.nx라고 하면 Sound_aboji의 표본수를 말하고, 1/Sound_aboji.dx는 표본속도를 말한다. 이렇게 활용할 수 있는 속성들을 적어본다.

xmin 음성, 피치, 포먼트, 스펙트로그램, 강도, 와우관도, 배음객체 등에서는 처음 시간값을 나타내고, 스펙트럼 객체에서는 최저주파수를 나타낸다.

xmax 음성, 피치, 포먼트, 스펙트로그램, 강도, 와우관도, 배음객체 등에서는 마지막 시간값을 나타내고, 스펙트럼 객체에서는 최대주파수를 나타낸다.

ncol 행렬, 실수표, 표 등의 열수를 말한다.

nrow 행렬, 실수표, 표 등의 행수를 말한다.

nx 음성에서는 샘플수, 피치, 포먼트, 스펙트로그램, 강도, 배음객체에서는 분석프레임수, 스펙트럼에서는 주파수 저장 개수, 행렬에서는 x축의 차원수를 말한다.

dx 음성에서는 표본주기를 초단위로 나타내고, 피치, 포먼트, 스펙트로그램, 강도, 배음객체에서는 분석프레임 사이의 간격시간, 스펙트럼에서는 주파수대역, 행렬에서는 자료사이의 수평간격을 말한다.

ymin 스펙트로그램과 와우관도의 최저주파수를, 행렬에서는 y차원의 맨 밑 값을 나타낸다.

ymax 스펙트로그램과 와우관도의 최고주파수를, 행렬에서는 y차원의 맨 위 값을 나타낸다.

ny 스펙트로그램, 와우관도에서는 주파수대의 수를 나타내고, 스펙트럼에서는 항상 2개가 되는데, 첫 번째 줄은 실수부, 두 번째 줄은 허수부를 나타낸다. 행렬에서는 x축의 열수를 말한다.

dy 스펙트로그램에서는 이웃하는 주파수대의 거리를 나타내고, 와우관도에서는 이웃하는 주파수대의 거리, 행렬에서는 자료사이의 수직 열사이의 거리를 말한다.

그림 2.13 빗금친 사선의 파형 만들기

만약 빗금친 사선을 그리려면 Create sound...다음에 다음의 공식을 입력하면 그림 2.13과 같은 음성이 생긴다.

(x-xmin)/(xmax-xmin)

만약 음성을 객체창의 음성을 선택하고 분석단추 가운데 Modify를 클릭하고 Formula란에 self*20^(-(x-xmin)/(xmax-xmin))을 입력하면 해당 음성의 크기가 지수함수로 서서히 줄어드는 음성이 된다. 음성의 끝부분을 서서히 줄이는데 사용하면 편리하다.

스크립트에서 이런 예약용어를 사용하면 계산이 훨씬 빨라진다. 예를 들어, 어떤 행렬자료를 빗금모양으로 더하기위해 다음과 같은 예약용어를 사용하여 스크립트를 만들 수 있다.

sumDiagonal=0

for I to Matrix_hello.ncol

sumDiagonal+=Matrix_hello[i,i]

endfor

echo The sum is 'sumDiagonal'

이것을 Query의 메뉴기능을 이용하여 다음과 같이 쓸 수 있다.

select Matrix hello

sumDiagonal=0

ncol=Get number of columns

for i to ncol

value=Get value in cell... i i

sumDiagonal+=value

endfor

echo The sum is 'sumDiagonal'.

2.14 계산순위

스크립트에서의 계산 순서는 곱셈, 나눗셈, div, mod 등이 먼저 계산되고 다음으로 더하기 빼기 등이 실행되는데, 만약 이 순서보다 더 빨리 계산하려면 ( )를 사용하여 묶어준다. 공식에서 계산되는 순서는 왼쪽에서 오른쪽으로 차례로 진행되고 연산자 사이의 빈칸은 무시한다. 몇 가지 예를 들어보자.

1/4*5-->1.25

1/(4*5)-->0.05

34 div 5 -->30 (나머지는 무시하고 계산된 정수값만 표시)

34 mod 5 -->4 (계산값은 무시하고 나머지만 표시)

-34 mod 5 -->1

5+7*8 -->61

(5+7)*8 -->96

9+9/3+6 -->18

(9+9)/(3+6) -->2

5+7=10 -->0

5+7=12 -->1

5+7<>12 -->0

5+7>=12 -->1

5+7<=12 -->1

문자열의 계산은 문자열의 첫 글자가 아스키 문자의 순서에서 앞인가 뒤인가를 나타내어준다. 예를 들어, a$<b$라면 a$에 book이 대입되어 있고 b$에 apple이 대입되어 있다면 정보창에 1이란 숫자를 나타낸다. 다음 스크립트를 실행해보자.

clearinfo

a$="book"

b$="apple"

output=a$<b$

print 'output'

2.15 조건절

스크립트를 만들다보면 어떤 조건을 만족할 때 실행하고 만족하지 않을 때는 건너뛰게 하는 조건절을 만들어야할 때가 있다. 예를 들어, 피치 값(f0)이 0보다 크면 "voiced"(유성음)이라 정보창에 인쇄하고 0이하이면 "unvoiced"(무성음)이라 인쇄시키려면 다음과 같이 스크립트를 만들면 된다.

if 'f0'>0

print "voiced"

else

print "unvoiced"

endif

이 때 조건이 세 개 이상이 되면 elsif를 사용하면 된다. elsif를 elif로 나타내도 된다.

clearinfo

counter=6

if counter<=3

print "counter is <=3"

elsif counter<=5

print "counter is <=5"

else

print "counter is <=7"

endif

위의 스크립트를 실행하면 정보창에 다음과 같이 나타난다.

"counter is <=7"

만약 대화창에 공식으로 입력하려면 if...then...else...fi로 사용할 수 있다. 예를 들어, 0.3이상이 되는 진폭값을 가지는 표본을 모두 0.3으로 잘라주는 스크립트는 다음과 같다.

if abs(self)>0.3 then if self>0 then 0.3 else -0.3 fi else self fi

2.16 되풀이 작업문

프라트 스크립트에서 되풀이 작업을 할 때는 for와 repeat, while의 세 가지 정해진 방식을 이용한다. 먼저 for구문을 이용하면 아래와 같이 표현된다.

for 변수 from 시작값 to 종료값

print '변수'

endfor

여기서 지정된 변수 값이 시작 값부터 1씩 증가하면서 종료 값이 될 때까지 차례로 되풀이된다. 다음 스크립트를 실행하면 정보창에 10개의 숫자를 연이어 표시한다.

clearinfo

for i from 1 to 10

print 'i'

endfor

여기서 시작값이 1부터 시작된다면 아래와 같이 from 시작값을 생략해도 같은 결과를 보여준다.

clearinfo

for i to 10

print 'i'

endfor

프라트를 이용하여 일정한 간격으로 한 단어를 들려주고 답을 표시하거나 따라할 시간을 준 다음 두 번째 단어를 들려주는 경우를 생각해 보자. 구체적으로 10가지 목소리 가운데 모델과 같은 것이 어느 것인지 들으면서 답지에 표시한다고 가정해보자. 우선, 사용자의 하드디스크에 1∼10까지 "일, 이...십"이라는 소리로 파일을 만들어 두고, 모델이 되는 사람의 목소리는 model이라는 이름으로 음성을 저장하고, 다른 사람의 목소리를 열 개 녹음하여 각각 90번부터 99번까지 번호를 매겨 저장해둔다. 마지막으로, 약 1초길이의 묵음 파일을 만들어 silence라고 이름붙이고, 약 3초길이의 묵음파일을 만들어 respond로 저장한다. 실험은 '일', 모델목소리, 1초 묵음, 비교하고자하는 사람의 목소리, 답안지에 쓰는 시간을 주는 3초 묵음의 순서로 진행되고 이것이 계속 되풀이 되게 한다고 보면 다음과 같은 스크립트로 진행할 수 있을 것이다.

<Listeningtest.sk>

for i from 1 to 10

Read from file... C:\Praat\sounds\'i'

endfor

for j from 91 to 100

Read from file... C:\Praat\sounds\'j'

endfor

Read from file... C:\Praat\sounds\model

Read from file... C:\Praat\sounds\silence

Read from file... C:\Praat\sounds\respond

select Sound 1

Play

select Sound model

Play

select Sound silence

Play

select Sound 91

Play

select Sound respond

Play

select Sound 2

Play

select Sound model

Play

select Sound silence

Play

select Sound 92

Play

select Sound respond

Play

<이하 생략>

위의 스크립트를 개수만큼 쓰려면 매우 복잡하고 번거롭다. 이를 보다 더 간단하게 되풀이 구문으로 이용하면 다음과 같이 줄일 수 있다.

<Listeningtestshort.sk>

for i from 1 to 10

Read from file... C:\Praat\sounds\'i'

endfor

for j from 91 to 100

Read from file... C:\Praat\sounds\'j'

endfor

Read from file... C:\Praat\sounds\model

Read from file... C:\Praat\sounds\silence

Read from file... C:\Praat\sounds\respond

for k from 1 to 10

select Sound 'k'

Play

select Sound model

Play

select Sound silence

Play

select Sound 'k'+90

Play

select Sound respond

Play

endfor

변수 값은 흔히 되풀이 작업 구문에서 파일 이름이나 다른 처리에 사용되는데 이 값을 1씩 감소시키려면 {종료 값-변수 값}을 해두면 된다. 예를 들어, 음성파형 a.aifc를 객체창에 불러와 0.005초마다 음성파형의 진폭 값을 20개 정보창에 인쇄하고 객체창에서 제거(Remove)하려면 다음과 같이 처리한다.

Read from file... C:\Praat\sounds\a.aifc

clearinfo

for i from 1 to 20

timepoint=i*0.005

db=Get value at time... 'timepoint' Sinc70

print 'timepoint:2''tab$''db:3''newline$'

endfor

Remove

이 과정을 repeat를 사용하여 처리한다면 다음과 같이 나타낼 수 있다.

Read from file... C:\Praat\sounds\a.aifc

clearinfo

i=1

repeat

timepoint=i*0.005

db=Get value at time... 'timepoint' Sinc70

print 'tab$''timepoint:2''tab$''db:3''newline$'

i=i+1

until i=21

Remove

이 때 조건절의 until의 숫자를 21로 하지 않으면 19번째 지점까지만 실행되고 끝나게 됨을 유의해야 한다. 얼마나 시행되었는지 정보창에 나타내어 보려면 i에 20을 넣고 정보창에 인쇄된 i값을 확인해보기 바란다. 이렇게 스크립트의 실행이 어디까지 진행되었는지 일종의 프로그램 진행 추적(Debugging)기능을 넣으려면 중간 중간마다 print '변수값'하여 확인해 보면 된다. 그리고 마지막에서 두 번째 줄의 i=i+1로 숫자가 하나씩 더해지는 부분을 생략하면 무한으로 동작이 계속되므로 주의해야한다. 이 때는 Control+Alt+Delete 키를 동시에 눌러 [해당 작업종료]를 선택하고 프라트를 종료한 뒤 Windows화면에서 다시 시작해야 한다.

또 다른 되풀이 작업으로는 이와 같이 끝 부분에 조건을 붙이지 않고 시작 부분에 조건을 붙여 만족할 때까지 되풀이해서 작업을 하는 while구문이 있다. 위의 스크립트를 while로 처리해보면 다음과 같다.

Read from file... C:\Praat\sounds\a.aifc

clearinfo

i=1

while i<21

timepoint=i*0.005

db=Get value at time... 'timepoint' Sinc70

print 'i''tab$''timepoint:2''tab$''db:3''newline$'

i=i+1

endwhile

Remove

다음 스크립트는 숫자값을 일정한 범위 안(0;2Ր)에 들어가도록 한다.

while x<0

x=x+2*pi

endwhile

while x>=2*pi

x=x-2*pi

endwhile

이 기능을 이용하면 음성파형의 최대값을 구하여 기준값(1)에 대한 비율값을 곱하여 모두 변환시키는 정규화(normalize)를 시킬 수 있다.

2.17 개별처리(Procedures)

프라트 스크립트에는 개별처리(Procedures)라는 기능을 가지고 있다. 이것은 베이식이나 일반 컴퓨터 프로그램에서 서브루틴을 말한다. 스크립트 안에서 자주 되풀이 사용되는 부분을 정의하고 필요한 곳에서 몇 번이고 불러낼 수 있는 편리한 장치다. 스크립트를 쓸 때 되풀이되는 부분이 여기저기에 반복되어 있다면 매우 지저분하고 명확한 개념을 파악하기 어려울 것이다. 예를 들어, 다음과 같이 세 개의 정현파를 만들어 재생(Play)한 뒤 객체창에서 제거(Remove)하는 스크립트를 가정해보자.

Create Sound... sinename 0 1 22050 1/2 * sin(2*pi*1000*x)

Play

Remove

Create Sound... sinename 0 1 22050 1/2 * sin(2*pi*2000*x)

Play

Remove

Create Sound... sinename 0 1 22050 1/2 * sin(2*pi*3000*x)

Play

Remove

위의 스크립트에서 Play/Remove는 되풀이 되어 있다. 이것을 개별처리로 만들면 다음과 같이 표현할 수 있다.

procedure playremove

Play

Remove

endproc

이렇게 하면 위의 스크립트를 다음과 같이 나타낼 수 있다.

Create Sound... sinename 0 1 22050 1/2 * sin(2*pi*1000*x)

call playremove

Create Sound... sinename 0 1 22050 1/2 * sin(2*pi*2000*x)

call playremove

Create Sound... sinename 0 1 22050 1/2 * sin(2*pi*3000*x)

call playremove

procedure playremove

Play

Remove

endproc

물론 여기서 정현파를 생성하는 부분도 되풀이되어 있으므로 변수를 받는 개별처리로 만들 수 있다.

procedure playsine frequency

Create Sound... sinename 0 1 22050 1/2 * sin(2*pi*frequency*x)

endproc

개별처리 안에서도 또 다른 개별처리를 불러올 수 있는데, 이것을 포함한 두 개의 개별처리로 구성된 스크립트를 만들면 다음과 같다.

call playsine 1000

call playsine 2000

call playsine 3000

procedure playsine frequency

Create Sound... sinename 0 1 22050 1/2 * sin(2*pi*frequency*x)

call playremove

endproc

procedure playremove

Play

Remove

endproc

물론 앞서 나타낸 되풀이하는 방법이 가장 간략하고 좋을 것이다. 가능하면 이런 되풀이되는 부분은 개별처리로 분리하여 여러 곳에서 불러오거나 프로그램의 라이브러리와 같이 이용할 수 있다.

개별처리 변수에 해당하는 값이 반드시 숫자값일 필요는 없다. 문자열을 받아서 이것을 조합하여 음성분석에 활용하는 방법도 있다. 여기서는 우선 문자열을 정보창에 인쇄하는 처리과정을 하나로 만들어 사용하는 법을 보인다. 문자열 가운데 빈칸이 있는 경우에는 양쪽에 겹따옴표를 붙여야한다. 마지막의 문자열은 겹따옴표 없이 나타내도 하나의 변수로 받아들이게 된다.

call printcolor red blue "navy blue" sky blue

procedure printcolor color1$ color2$ color3$

echo This prints colors:

printline Color1 'color1$'

printline Color2 'color2$'

printline Color3 'color3$'

endproc

스크립트를 작성할 때 문자와 숫자가 합쳐진 변수 이름을 지정하여 그 이름을 사용해야할 경우가 있다. 예를 들어, formant1, formant2, formant3...formant5와 같이 나타내고 이를 변수로 필요한 작업을 할 경우에는 다음과 같이 작성할 수 있다.

for i from 1 to 5

formant'i'=Get value at time... i 'timepoint' Hertz Linear

endfor

위의 되풀이 작업을 실행하면 formant1, formant2, formant3...formant5에 각각의 포먼트 값들이 입력되어진다. 이 때 인덱스가 되는 'i'의 값도 변수일 때는 임의의 변수를 넣어서 그 변수값을 정보창에 나타내는데 이용해야 한다.

for i from 1 to 5

formant'i'=Get value at time... i 'timepoint' Hertz Linear

formantvalue= formant'i'

printline Formant 'i' is 'formantvalue'

endfor

이 기능을 이용하여 해당 시간점의 앞 뒤 10개 정도의 포먼트 값들의 평균이나 표준편차 등을 구하고 이를 평균하여 해당 시간점의 값으로 지정할 때 편리하다. 만약 더 많은 수의 문자와 숫자가 합쳐진 변수를 구하여 처리하려면 행렬(Matrix)를 이용하는 것이 좋다.

2.18 스크립트 안에서 스크립트를 불러오기

스크립트를 작성한 뒤 만약 하드디스크의 같은 폴더 안에 저장되어 있는 스크립트는 {include 스크립트이름}을 이용해 사용할 수 있다. 만약, product.sk라는 이름의 스크립트가 x=x*x로 정의되어 있다면 다음의 스크립트를 실행하여

x=10

include product.sk

printline 'x'

100이란 값을 정보창에 인쇄할 수 있다. 그러나 이 과정에서 포함할 스크립트의 이름을 다음과 같이 변수로 정의하여 작업할 수 없다.

name$="product.sk"

include 'name$'

2.19 작업끝내기

스크립트 작업 가운데 사용자에게 메시지를 보내지 않고 끝나게 하려면 exit이란 단어를 넣으면 된다. 이 때 스크립트 작업에 의해 주어진 파라미터의 값들은 모두 사라진다. 파라미터의 값을 그대로 보존한 채 사용자에게 오류 메시지를 보내면서 작업을 중단하고 싶으면 {exit error-message}로 하면 된다.

clearinfo

call calculator 3 5

error$="Error here"

print 'add''tab$''multiple'

exit 'error$'

procedure calculator x y

add=x+y

multiple=x*y

endproc

이 스크립트를 실행하면 그림 2.14와 같이 8, 15 라는 계산 값을 제시하고는 "Error here"라는 메시지를 창에 제시하고 더 이상 실행이 되지 않는다. 긴 스크립트를 만든 뒤, 끝까지 실행하는데 시간이 많이 걸릴 때 중간 부분까지만 실행하고 결과를 확인해 볼 경우에 사용하면 편리하다.

그림 2.14 오류정보 표시 정보창

2.20 입력 폼(Form)

스크립트의 form을 이용하면 사용자에게 필요한 숫자나 문자를 입력하도록 요구할 수 있다. 예를 들어, 다음 스크립트는 파일 이름을 불러오고 숫자를 지정한다.

clearinfo

form Tell me your foldername, filename and number.

word foldername vowels

word filename vowel_a

integer number 9

endform

echo 'foldername $' 'tab$' 'filename$' 'tab$' 'number'

위의 스크립트를 실행하면 2.15와 같은 대화창이 나타나고 OK단추를 누르면 정보창에 [ vowels vowel_a 9]로 인쇄된다. 여기에서 echo대신에 printline을 사용하면 에러가 발생한다. form에 입력된 문자열은 해당되는 변수이름에 대입되기 때문에 다음에 연결되는 스크립트에서 활용할 수 있다.

그림 2.15 form 파라미터 입력 대화창


이 때 form 다음에 오는 문장은 어떤 용도인지 대화창에 인쇄되는 설명을 나타내고 그 다음 줄에 올 수 있는 표현은 {예약어 변수이름 기본 값}의 순서로 제시된다. 예약어로는 real(실수), positive(양의 정수) natural(양의 자연수), word(빈칸이 없이 연속된 단어), sentence(짧은 문자열), text(긴 문자열), boolean(체크박스로 0과 1의 값을 가진다), choice(1 이상의 선택 값을 가진다.), button(라디오 단추) comment(설명문)가 올 수 있다. sentence를 사용할 때는 단어 사이에 생기는 빈칸을 밑줄(_)로 연결하면 파일이름에서는 빈칸으로 처리되므로 편리하다. endform 아래에 form안에서 정의된 변수 이름을 이용하여 하드디스크에 저장할 파일이름으로 사용할 수 있다. 위의 스크립트에서는 foldername칸에 입력된 파일이름을 빈칸이 없이 연속된 한 단어로 받아들여 foldername이라는 변수에 대입해주고, 마찬가지로 filename칸에 입력된 파일이름을 빈칸이 없이 연속된 한 단어로 받아들여 filename이라는 변수에 대입해준다. 세 번째 줄의 integer는 빈칸에 들어온 숫자를 정수값으로 number란 변수에 대입해준다. 기본값인 9를 표시하지 않으면 빈칸으로 대화창이 나타나는데 만일 정수를 입력하지 않으면 대화창의 OK단추를 눌렀을 때 에러메시지가 뜨게 된다.

다음은 단추기능을 이용해서 선택하게 하는 스크립트이다.

form fill color pattern

comment Choose any color and texture for a wonderful output.

choice Color: 3

button Sea green

button Navy blue

button red

choice Texture: 1

button Smooth

button Rough

button With holes

endform

echo You chose the color 'color$' and texture 'texture$'

이 스크립트를 실행하면 그림 2.16과 같은 대화창이 나타나고 정보창에는 You chose the color red and texture Smooth로 표시된다. 이렇게 선택된 변수값은 각각 color$와 texture$에 대입된다.

그림 2.16 색깔 선택 대화창 만들기


또한 연속된 두 개의 칸을 이용하여 지속 기간을 계산할 수 있다. 만약 첫 번째 값이 두 번째 값보다 크면 에러메시지를 보이고 스크립트 실행을 중단할 수 있다.

clearinfo

form Period

natural left_yearstart 1950

natural right_yearend 2004

endform

if right_yearend<=left_yearstart

exit 시작값이 높아 계산할 수 없습니다.

endif

period=right_yearend -left_yearstart

echo Period is 'period' years.

위의 스크립트를 실행하면 2.17과 같은 대화창이 나타난다.

그림 2.17 주기 계산 공식

OK단추를 누르면 정보창에는 [Period is 54 years.]라고 인쇄된다.

만약 left_yearstart값을 3000으로 하고 right_yearend값을 2004로 두면 그림 2.18과 같은 메시지를 보이고 스크립트 실행을 종료한다.

그림 2.18 실행 에러 메시지

그 외에도 같은 폴더 안에 Sinewave.praat라는 주파수(550 Hz)와 지속시간 (1.5 초)을 입력받아 재생하는 스크립트가 들어있다면 다른 스크립트에서 이 스크립트 파일을 실행할 수 있다.

execute Sinewave.praat 550 1.5

이 때 숫자값이 아닌 문자값을 받아들일 때 두 개 이상의 단어로 구성된 한 변수를 받아들이게 하려면 "Navy blue"와 같이 겹따옴표로 나타내야 한다.

2.21 정보창에 나타내기

정보창은 스크립트를 실행하면서 변수값들이 어떻게 대입되는지 처리과정이 얼마나 진행되었는지를 살펴보는데 매우 편리하다. 이 창에 어떤 글이나 경고문을 나타내려면 다음과 같은 명령어를 사용한다.

echo 문장

예를 들어, 다음과 같이 스크립트를 만든 다음 실행하면 그림 2.19와 같이 나타난다.

echo Now the script is running....

그림 2.19 안내문 출력 정보창

정보창의 자료를 모두 없애는 것은 {clearinfo}라고 입력한다. 문자열을 다음 줄로 바꾸지 않고 길게 연이어 제시하려면 {print 문자열}을 하고, {printtab}이나 {printline 문자열}을 하면 정보창에서 한 줄을 바꾸어 나타내어준다. 이것을 단어로는 {'tab$'} 또는 {'newline$'}로 표시하면 된다.

그림 2.20 구구단 출력 정보창

다음 스크립트는 구구단을 정보창에 그림 2.20과 같이 나타내어 준다.

clearinfo

for i from 2 to 10

for j from 1 to 10

multiple='i'*'j'

print 'i''tab$'X'tab$''j''tab$'='multiple''newline$'

endfor

endfor

아주 긴 스크립트를 작성하여 처리시간이 오래 걸릴 때 몇 번 째 까지 진행되고 있는지를 정보창에 표시하고 싶다면 아래와 같은 줄을 더 첨가하면 된다.

final=1000-'i'

print Current loop at 'i' / 'final' more loops to go

!(긴 작업 처리과정 스크립트 생략)

clearinfo

예를 들어, 30번째 작업이 진행되고 있을 때 정보창에 "Current loop at 30 / 970 more loops to go"가 나타나고 그 사이에 있는 긴 작업 처리과정이 끝나면 clearinfo에 의해 이것이 지워지고 "Current loop at 31 / 969 more loops to go"가 표시된다. 최근의 컴퓨터에서는 작업처리과정이 간단하면 정보창의 숫자가 바뀌는 것을 거의 눈으로 볼 수 없을 정도로 빨리 처리된다.

2.22 문의(Query)

어떤 음성파일을 불러와 지정한 시간점의 소리의 크기를 정보창에 나타낼 때는 다음과 같이 스크립트를 작성한다.

Read from file... C:\Praat\sounds\a.aifc

clearinfo

amp=Get value at time... 0.5 Sinc70

amp$=Get value at time... 0.5 Sinc70

print 'amp:3''tab$''amp$'

결과--0.062 0.062017642587644292 Pascal

이렇게 하면 결과에서 보듯이 amp로만 하면 뒤에 오는 단위는 생략하고 숫자만 받는 변수가 되며 amp$로 하면 뒤에 따라오는 단위인 Pascal이라는 문자열까지 포함한 값을 돌려준다.

2.23 하드디스크의 파일 읽기

일반적으로 하드디스크에 저장된 파일(fileName)을 읽어서 한 덩어리의 연속된 문자열로 변수 하나에 넣으려면 다음과 같이 표현한다.

text$<fileName

여기서 파일이름은 겹따옴표를 쓰지 않는다. 만일 파일이 디스크에 없으면 에러메시지가 뜨고 스크립트 실행이 중단된다.

만일 저장된 파일 history.inf라는 파일에서 2004년을 year$에 대입하여 두었다면, 이것을 따로 문자변수로 분리해내고, 이것을 또 숫자변수로 변형하려면 아래와 같이 스크립트를 쓰면 된다.

year$<history.inf

year='year$'

이 때 파일이 디스크에 없으면 에러메시지가 나오고 스크립트가 중단되기 때문에 이것을 방지하기위해 임의의 기본값을 부여하는 스크립트를 만들 수 있다. 다음은 history.inf에 들어있는 년도 정보(2002)를 불러내어 year$라는 문자변수에 넣고 이것을 다시 숫자변수로 변형하여 year에 넣는 스크립트이다. 만약, history.inf가 하드디스크에 없을 때는 2004라는 임의의 숫자를 넣어준다.

clearinfo

fileName$="history.inf"

if fileReadable(fileName$)

year$<history.inf

year='year$'

else

year=2004

endif

print 'year$' 'tab$' 'year'

위와 같이 실행하면 정보창에 [2002 2002]와 같이 나타난다.

만일 분석하여 변수값에 넣은 텍스트 문서를 새로운 파일이름으로 저장하려면 <표시를 반대로 하여 다음과 같이 표현한다.

text$>fileName

앞의 스크립트 다음에 아래와 같이 한 줄을 더 넣으면 하드디스크에 2002란 숫자가 newhistory.inf파일로 저장된다.

year$>newhistory.inf

다음은 이와 같이 하드디스크에 원하는 파일이름으로 자료를 저장하는 방법을 알아본다.

2.24 하드디스크에 파일 저장하기

일반적으로 음성분석을 하여 필요한 포먼트나, 피치값 등을 수집할 때 하나씩 마우스로 클릭 한 값을 구하여 저장하려면 엄청난 시간이 소모된다. 가능하면 파일입력 기능을 이용하여 스크립트를 통해 하드디스크에 저장하는 것이 좋다. 저장된 결과값 파일을 나중에 통계프로그램이나 마이크로소프트 엑셀을 이용하여 그래프로 그린 뒤 평균과 표준편차에서 지나치게 벗어난 값들은 재점검하면 시간을 많이 절약할 수 있다.

실제 컴퓨터 하드디스크에 파일을 저장할 때는 {fileappend 'filename$'}를 사용한다. 이 때 저장할 파일이름으로 된 파일이 다른 응용프로그램으로 열려져 편집중에 있으면 시스템 에러가 생기기 때문에 먼저 하드디스크에 파일이 있는지를 fileReadable('filename$')를 사용해 확인해보고, 만일 있다면 다른 이름으로 저장하는 것이 좋다. 다음 스크립트는 만약 같은 이름의 파일이 있으면 "There is a file"이란 메시지를 정보창에 나타내고, 없다면 파일을 새로 생성하여 자료를 입력해주는 스크립트이다.

filename$="C:\sounds\newfile.txt"

if fileReadable('filename$')

print There is a file with the same name!

else

fileappend 'filename$' I saved this file on my computer.

endif

만약에 앞서의 구구단을 정보창에도 표시하고, 동시에 컴퓨터 하드디스크에 multiple.txt라는 이름으로 저장하려면 다음과 같은 스크립트를 사용한다.

clearinfo

filename$="C:\sounds\multiple.txt"

for i from 2 to 10

for j from 1 to 10

multiple='i'*'j'

print 'i' X 'j' = 'multiple''newline$'

fileappend 'filename$' 'i' X 'j' = 'multiple''newline$'

endfor

endfor

위의 스크립트를 실행하면 정보창에 앞서 구구단스크립트에서 보았던 내용들이 나타나며 동시에 하드디스크에도 multiple.txt가 만들어져 있다. 만약 fileappend 'filename$' 'i'를 fileappend 'filename$''i'와 같이 스페이스 없이 변수값을 두면 multiple2.txt, multiple3.txt...multiple10.txt로 저장되므로 주의해야한다. 덧붙여, 정보창에 있는 정보를 그대로 파일로 저장할 때는 {fappendinfo 'filename$'}를 사용하면 된다. 이미 작성한 파일이 더 이상 필요 없을 때는 {filedelete 'filename$'}라는 스크립트를 입력하면 된다.

2.25 사용자와의 통신

스크립트 처리과정을 일단 중지하고 사용자에게 질문을 하여 계속할건지(Continue), 중단할건지(stop) 단추로 선택하게 하는 스크립트는 아래와 같이 작성한다.

pause 어떻게 할까요?

이것을 실행하면 그림 2.21과 같은 대화창이 나타난다.

그림 2.21 스크립트 일시 중단 대화창

2.26 셸 스크립트

하드디스크에 2초 이상의 시간으로 저장된 counter.aifc란 음성을 객체창에 불러와 편집단추를 눌러 편집창을 띄우고, 편집창에서 불러온 음성의 일부를 확대하여 선택하고 이 부분만 객체창에 불러낸 뒤 재생하는 복잡한 스크립트를 살펴보자.

sound$="counter"

start=0.5

finish=1

Read from file... 'sound$'.aifc

Edit

editor Sound 'sound$'

Zoom... start finish

Extract selection

endeditor

Play

이렇게 편집창에서 작업하는 스크립트 명령어나 동작들은 특별히 editor∼endeditor안에서만 작동한다. 이것을 만드는 순서는 먼저 객체창에 음성을 불러온 뒤, Edit단추를 눌러 편집창을 열어놓는다. 다음으로는 편집창의 File기본메뉴아래의 New editor script를 클릭 하여 스크립트 편집창을 열면, 마우스로 필요한 부분을 선택하거나 메뉴를 클릭 하여 실행하는 내용들이 모두 history로 기록된다. 스크립트 편집창에서 Paste history를 이용하여 입력한 뒤 필요한 수정을 하고 디스크에 저장한다. 만일 자주 쓰는 편집기능이면 객체창의 File기본메뉴아래의 Add to menu...를 클릭 하면 음성 편집창에 다른 하위메뉴와 같이 등록하여두고 쓸 수 있다.

실제 음성 편집창에서 커서가 있는 곳의 앞뒤 50 밀리초 분량을 추출하여 fft하여 보여주는 편집창 스크립트를 만들어 메뉴로 등록해보자.

cursor=Get cursor

Select... cursor-0.025 cursor+0.025

Extract windowed selection... slice Kaiser2 2 no

endeditor

To Spectrum (fft)

Edit

그림 2.22 스펙트럼 조각보기

음성 편집창을 열고 마우스로 음성의 한 부분을 클릭 하여 선택한 다음 File메뉴아래(객체창의 File메뉴에서는 실행이 안 됨) New editor script를 열어 위의 스크립트를 넣고 Run을 클릭 하여 실행하면 그림 2.22와 같은 스펙트럼 편집창이 뜨게 된다.

위의 스크립트를 편집창에서 자주 써야 한다면 먼저 하드디스크에 spectrum.sk라고 저장한 뒤, 객체창의 File기본메뉴아래 Add to menu를 클릭한 뒤 그림 2.23과 같은 대화창이 나오면 첫줄 Window칸에 "SoundEditor"라고 입력하고, Menu칸에는 Spectrum이라고 입력한다. 이어서 Command란에 spectra...라고 입력하면 이 명령어가 메뉴표시로 나타나게 된다. After command는 음성편집창의 기본메뉴아래의 특정한 하위메뉴 다음에 넣도록 지시할 때 사용한다. 마지막으로 Script file칸에 spectrum.sk이라고 입력하고 OK단추를 누르면 된다.

그림 2.23 메뉴 더하기 명령어

그림과 같이 입력하면 SoundEditor창의 Spectrum 기본메뉴 맨 끝에 Spectra...라고 나타난다. 스크립트 파일을 만드는 과정에서 만약 윈도우즈에 있는 메모장(Notepad)을 사용했다면, 파일이름이 spectrum.sk.txt로 저장되는 경향이 있다. 그래서 그림 2.24와 같이 파일을 읽을 수 없다는 메시지가 뜨게 된다. 이것을 피하기 위해서는 스크립트 편집창에서 작업한 내용을 하드디스크에 바로 저장하면 .txt 확장자가 붙지 않는 텍스트 파일이 된다.

그림 2.24 파일열기 에러메시지

덧붙인 하위메뉴를 없애고 원래의 하위메뉴로 되돌리려면, 객체창의 Hide menu command...를 클릭하고 그림 2.25와 같이 입력한다.

그림 2.25 메뉴 감추기 명령어


이 때 정확한 창문이름과 메뉴와 명령어를 입력해야 없어진다. 현재 작업 중이라면 메뉴는 그대로 남아있는데, 프라트를 닫았다가 다시 실행시키면 해당 하위메뉴가 사라진 편집창이 뜬다. 이러한 현상은 프라트를 처음 실행하거나 다시 실행할 때, 저장되어 있던 환경설정 사항들을 불러오기 때문에, 각종메뉴는 실행할 때만 사용자가 더하거나 변한 것이 나타나게 된다.

2.27 음성편집창 선택부분의 스펙트럼 보기

만약 편집창에 불러낸 음성파일(a.aifc)을 마우스로 일부분 선택한 다음 그 구간의 스펙트럼 정보를 보고 싶다면 다음과 같은 스크립트를 만든다. 마우스로 선택한 지점의 시작점과 끝점의 시간값을 구한 다음 이것을 이등분하여 시작점에 더해줌으로써 선택한 부분의 중심값을 구한다. 이어서 선택된 부분을 객체창에 올려놓은 뒤 스펙트럼을 구하고 이 스펙트럼의 주파수범위를 4000 Hz까지만 나타나게 하고 해당 음성부분은 객체창에서 지워버린다.

select Sound a

Edit

editor Sound a

begin=Get begin of selection

end=Get end of selection

midpoint=(end-begin)/2+begin

timepoint=round(midpoint*1000)

Extract windowed selection... 'timepoint'ms Kaiser2 2 no

endeditor

To Spectrum (fft)

Edit

editor Spectrum 'timepoint'ms

Zoom... 0 4000

endeditor

select Sound 'timepoint'ms

Remove

2.28 음성을 여과하여 재조합하는 방법

음성을 여과하여 재조합하기 위해서는 먼저 녹음한 음성을 객체창에 불러온 뒤, 객체창의 합성단추인 Filter를 열어서 그림 2.26과 같이 저주파 대역(0-2000)을 통과하게 하고, 여과된 파일이름을 name_lo로 지정한다.

그림 2.26 음성 여과하기


이어서, 객체창의 합성단추인 Filter를 열어서 고주파 대역(2000-4000)을 통과하게 하고, 여과된 파일이름을 name_lo로 지정한다. 그림 2.27과 같이 "아버지"(aboji) 라는 음성이 여과되어 객체창에 나타난다.

그림 2.27 객체창에 여과한 음성 나타내기

마지막으로 두개의 파일을 서로 재결합하려면 다음과 같이 한다.

select Sound aboji_hi

sampleno=Get number of samples

for k to 'sampleno'

select Sound aboji_hi

hi=Get value at index... k

select Sound aboji_lo

lo=Get value at index... k

newlo='hi'+'lo'

Set value at index... k 'newlo'

endfor

2.29 행렬(Matrix)

행렬이란 어떤 행과 열로 된 수치자료를 나타내는 것이다. 그림 2.28과 같이, 엑셀의 가로와 세로로 된 자료가 행렬자료의 대표적인 예가 된다.

그림 2.28 엑셀로 보인 행렬의 예


이 엑셀의 자료에서 A, B, C는 열(column)이 되고 1, 2, 3, 4는 행(row)이 된다. 숫자 91은 두 번째 행의 세 번째 열에 있다. 엑셀에서는 C2(C열의 2번째 행)로 표시하는데, 프라트에서는 row와 col로 나타낸다.

그림 2.29 단순행렬 만들기 메뉴

위와 같이 3X4의 행렬을 만들려면, 먼저 그림 2.29와 같이 객체창의 New기본메뉴아래 Matrix하위 메뉴아래 Create simple Matrix...를 클릭 하면 그림 2.30과 같은 대화창이 나타난다.

그림 2.30 행렬 작성 대화창


이 창에서 Name은 객체창에 표시되는 이름을 말하고, Number of rows는 몇 개의 행으로 만들 것인지, Number of columns는 몇 개의 열로 만들 것인지를 입력한다. Formula란에는 원하는 공식을 입력하여 계산된 값을 넣거나 0을 넣으면 모든 행렬값이 0인 것으로 된다. 스크립트로는 다음과 같이 만들면 된다.

Create simple Matrix... MyMatrix 4 3 0

좀 더 복잡한 행렬값은 객체창의 New기본메뉴아래 Matrix아래 Create simple Matrix...를 클릭 한다.

그림 2.31의 대화창에서 보듯 기본적으로 x는 열을 나타내고, y는 행을 나타낸다. 이 복잡한 행렬에서는 앞서의 행렬에 더하여 행과 열의 증가값(dx, dy)을 조절할 수 있고, 최대값과 최소값(xmin, xmax, ymin, ymax), 초기값(x1, y1)을 지정할 수 있다. 거의 모든 프라트의 포먼트나 피치값 등의 분석 자료들은 이런 행렬자료로 구성되어 있으므로 여러 가지로 변형할 때 매우 편리하다. 예를 들어, 음성파일을 행렬로 바꾸면 한 개의 행과 표본 값의 수만큼의 열로 되어있다. 스펙트럼을 행렬 객체로 바꾸면 두 개의 행으로 되어 있는데 첫 번 째 행은 실수부이고, 두 번 째 행은 허수부가 된다. 스펙트로그램을 행렬 객체로 바꾸면 두 개의 행으로 되어 있는데 첫 번 째 행은 주파수를 나타내고 각 열은 시간 값을 나타낸다. 이 값들은 음성파일이나 스펙트럼 정보를 행렬로 바꿀 때 자동으로 설정되기 때문에 음성처리의 문턱 값으로 활용할 수 있다. 해당 값을 한꺼번에 self라고 표현한다. 이러한 모든 행렬 값들은 지정된 변수로 불러내거나 계산에 사용할 수 있고 Modify기능을 이용해 다른 값을 넣을 수 있다.

그림 2.31 복합 행렬 대화창

2.30 행렬값 바꾸기

먼저 만들어진 행렬의 값을 확인해 보려면 Matrix MyMatrix가 선택된 상태에서 그림 2.32와 같이 객체창에 있는 분석 단추 가운데 Query-->Get value in cell을 선택하고 대화창에 원하는 행과 열을 지정하여 OK단추를 누르면 된다.

그림 2.32 행렬값 구하기


이것을 스크립트로 나타내면 다음과 같이 된다.

select Matrix MyMatrix

Get value at xy... 3 2

위와 같이 하면 3열의 2행에 있는 값을 구해준다.

매트릭스안의 모든 숫자들을 차례로 읽어 정보창에 인쇄하려면 아래와 같이 입력하여 실행한다.

clearinfo

select Matrix MyMatrix

rowno=Get number of rows

colno=Get number of columns

for i to colno

for j to rowno

val=Get value in cell... i j

print 'val''newline$'

endfor

endfor

덧붙여, Matrix MyMatrix가 선택된 상태에서 객체창에 있는 분석 단추 가운데 Modify-->Set value...를 선택하고 대화창에 원하는 행과 열을 지정하여 OK단추를 누르면 각 셀의 값을 임의로 바꿀 수 있게 된다. 모든 값을 0으로 바꾸려면 다음과 같이 스크립트를 만들어 실행시키면 된다.

clearinfo

select Matrix MyMatrix

rowno=Get number of rows

colno=Get number of columns

for i to colno

for j to rowno

Set value... i j 0

endfor

endfor

위의 스크립트는 셀을 하나씩 바꾸어 나가는 것인데, 변형할 값이 일정하다면, 한꺼번에 행렬의 데이터를 변환하는 Formula기능을 이용한다. 객체창의 분석 단추 가운데 하나인 Modify-->Formula를 실행하고 대화창에 0이나 원하는 숫자를 입력하면 된다. 물론 양수인 행렬 값을 모두 음수값으로 바꾸려면 대화창에 -self라고 입력하면 된다. 보통 라링고그라프의 입력신호가 전류에 근거를 둔 경우와 그 반대쪽인 저항에 근거를 둔 입력신호가 있는데, 완전히 정반대의 신호로 변환하여 처리하고 싶을 때 -self가 매우 편리하다. self+self[row, col-1]은 한 셀(self)과 이전 셀(self[row, col-1])을 더하여 결국에는 모든 셀의 값들을 합해준다. 이것은 self[col-1]+self*dx로도 표현할 수 있다. 여기서, row는 현재의 행을 말하고 col은 현재의 열을 말한다. x값은 현재의 열에 할당된 값으로 음성, 스펙트로그램, 배음성 등에서는 시간점값을 말한다. 스펙트럼 객체에서는 주파수(Hertz)를 말하고 지각자극객체(Excitation)에서는 주파수(Bark)를 나타낸다. y값은 현재의 행과 연관된 값으로 스펙트로그램에서는 주파수(Hertz)를 말하고 와우관도(Cochleagram)에서는 주파수(Bark)를 나타낸다. 이 행렬객체는 여러 개의 스펙트럼 정보를 평균하여 따로 저장하거나 객체창에서 값들을 저장하였다가 호출하는 경우에 매우 편리하다.

2.31 음성에 가우스 소음 섞기

음성파형에 소음을 섞으려면 객체창에 음성을 불러온 뒤 객체창의 분석단추인 Modify를 선택하고 그림 2.33과 같이 그 아래의 Formula...를 클릭 한다.

그림 2.33 가우스 소음 섞기 위한 객체창의 메뉴 선택

클릭하면 그림 2.34와 같은 대화창이 나타나고 빈칸에 필요한 공식을 입력해야 한다.

그림 2.34 가우스 소음 섞기 대화창

여기서 self+randomGauss(0,0.1)를 입력하면 된다. 이것은 원래의 음성파형에 소음을 섞어 바꾸라는 명령이 된다. 이를 간단히 스크립트로 한다면 다음과 같이 쓸 수 있다.

select Sound hello

Formula... self + randomGauss(0,0.1)

2.32 소리의 강도 조절

객체창에 불러온 소리의 크기를 조절하려면 객체창의 Modify단추를 눌러 Formula를 실행하면 된다. 예를 들어, 하드디스크에 있는 aboji란 음성을 불러와 재생한 뒤 강도를 2배하고 재생하는 스크립트는 다음과 같다.

Read from file... C:\Praat\sounds\aboji

Play

Formula... self*2

Play

물론 강도를 1/2로 줄이려면 Formula... self/2를 입력하면 된다.

소리의 강도를 조절할 때 총 표본수를 구한 뒤 각각의 표본값을 불러와 oldvalue에 대입하고, 이를 두 배한 새 값으로 대치하는 스크립트를 다음과 같이 쓸 수 있다.

Read from file... C:\Praat\sounds\aboji

select Sound aboji

ncol=Get number of samples

x=0

for col from 1 to ncol

oldvalue=Get value at index... col

newvalue=oldvalue*2

Set value at index... col newvalue

x=x+1

endfor

전체의 파형보다는 일부를 수정하려면 다음과 같은 순서로 작업한다. 예를 들어, "아버지"라는 음성 가운데 "아"부분만 2배로 확대하려면 객체창에 음성을 불러온 뒤 Edit단추를 눌러 편집창에 올리고 "아"부분을 선택한 뒤 Extract selection을 실행하여 객체창에 Sound untitled가 올라가게 하고 객체창의 Modify단추를 눌러 Formula하위메뉴를 클릭하고 공식대화창이 나오면 Formula... self*2를 입력하고 이렇게 변형된 Sound untitled를 Edit 단추를 눌러 연 뒤, 음성 "아"의 처음부터 끝까지 마우스로 선택한다. 이어서, 편집창의 Edit기본메뉴 아래 Copy selection to Sound clipboard를 클릭 한다. 키보드조합으로는 Ctrl+C를 하면 된다. 원래의 "아버지" 음성 편집창을 열어서 Edit기본메뉴의 하위메뉴인 Paste after selection을 클릭 한다. 키보드조합으로는 Ctrl+V를 하면 된다. 이렇게 하면 원래의 모음 "아" 다음에 진폭이 커진 모음 "아"가 덧붙여져 나타난다. 마우스로 음성재생막대를 클릭 해보면 큰소리로 변했음을 알 수 있다. 이런 변형은 국어나 영어, 불어 등의 단어에서 한 음절의 음성강도의 크기가 지각에 어떤 영향을 미치는지 실험하는데 사용할 수 있다. 우리말과 달리 영어의 단어에는 초분절음인 강세가 있어 여러 개의 음절 가운데 하나를 돋들리게 발음하는 경향이 있다. 강세의 특징으로는 피치값이 높거나, 지속시간이 길거나, 강도값이 높은 경향이 있다. 이 세 가지 음향적인 파라미터들이 각각 일정한 비율로 서로 조합되어 강세가 주어진 음절을 나타낸다.

제 3 장 음성 분석 스크립트 개발과정

3.1 피치를 구하는 스크립트

사람은 성대의 떨림 속도를 변화시켜 다양한 감정을 나타내는데, 이런 음원의 변화를 보여주는 피치값은 여러 가지 방식으로 구할 수 있다. 피치에 관한 구체적인 설명은 http://hyomin.dongeui.ac.kr/~bgyang/00praf0.pdf파일을 참고하기 바란다. 이 논문에서 제시한 피치분석의 스크립트의 예약함수들이 약간 바뀌었기 때문에 다음 스크립트는 일부를 수정하여 "아버지"의 두 번째 음절인 "버"의 중심부의 피치값과 전체 평균피치값을 소수점 이하는 반올림하여 정보창에 나타낸다.

<pitchdraw.sk>

clearinfo

Read from file... C:\Praat\aboji

To Pitch (ac)... 0 75 15 yes 0.03 0.45 0.01 0.35 0.14 600

Smooth... 10

meanf0=Get mean... 0 0 Hertz

valuef0=Get value at time... 0.5 Hertz Linear

Viewport... 0 6 0 3

select Pitch aboji

Red

Draw... 0 0 0 500 yes

print 'meanf0:0''tab$''valuef0:0'

그림창에는 그림 3.1과 같이 그려지고 정보창에는 128 150으로 나타난다.


그림 3.1 '아버지' 의 피치 곡선 그림

3.2 숫자음의 음성특성 분석 스크립트

숫자음에 대한 음성분석은 간단하면서도 누구나 비슷하게 발음하기 때문에 여러 가지 음성의 특성을 측정하여 서로 비교할 수 있는 좋은 음성자료이다. 여기서는 http://hyomin.dongeui.ac.kr/~bgyang/pranum.htm 에 제시된 스크립트 가운데, 일부 예약함수가 바뀌었기 때문에 최근의 용어로 바꾸어 나타내어본다. 구체적인 숫자음에 대한 연구 내용은 논문을 참고하기 바란다. 덧붙여, 개별 스크립트로 작업해볼 수 있도록 각기 설명을 한 뒤, 각각의 작업을 하나로 연결한 완전한 파일을 끝에 두기로 한다. 아래 첫 번째 스크립트는 일단 하드디스크에서 분석하고자 하는 파일을 불러온 뒤 객체창에 올려져서 파일이름을 soundName$란 변수에 입력해 두고 전체길이를 length란 변수에 입력하고 피치분석을 해서 그림창에 그려내는 스크립트다. 원고가 출판될 당시의 변수 이름의 첫 글자에 대문자가 허용되었으나, 지금 사용하고 있는 최근의 프라트 프로그램에서는 에러가 나오므로 소문자로 수정하였다.

<pitchanalysis1.sk>

soundName$=selected$("Sound")

select Sound 'soundName$'

length=Get duration

To Pitch (ac)... 0.005 75 3 yes 0.03 0.45 0.01 0.35 0.14 500

Erase all

Viewport... 0 6 0 3

Draw... 0 0 0 500 yes

일반적으로 피치값이 구해지는 구간은 성대의 떨림을 보이는 유성음 구간으로 판단해도 좋다. 보통 유성음 구간에서 포먼트와 진폭값 등 필요한 음향적 특성을 살펴보기 위해서는 피치값이 0보다 큰 음성 구간을 자동으로 분석 하는 것이 매우 중요하다. 두번째 스크립트는 앞의 스크립트에서 분석한 피치객체를 선택해서, 음성이 시작되는 부분은 피치값이 없다고 가정하고 약 20 밀리초 지난 위치(i=0.02)에서부터 시작하여 피치값을 구하고, 이 값이 undefined이나 0일 때는 중단하지 않고, 다음 0.005초가 지난 시간점(i='i'+0.005-->i=0.025)에서 피치값을 구하여 이 값이 또 undefined이나 0일 때는 중단하지 않고 다음 0.005초가 지난 시간점(i=0.03)에서 피치값을 구하는 while의 조건을 만족할 때까지 되풀이하다가 피치값이 0이상인 지점에서 while구간을 빠져나온다. 이지점의 i 값을 onsettime이라는 변수에 넣고 이를 정보창에 인쇄한다. 이러한 스크립트를 만들 때 줄의 끝에 빈칸을 두면 에러가 나므로 주의한다. 또한 별도로 실행하려면 반드시 f0의 초기값을 0으로 하고, i=0.02값을 주어야만 되므로 주의한다.

<pitchanalysis2.sk>

clearinfo

soundName$=selected$("Sound")

select Sound 'soundName$'

length=Get duration

To Pitch (ac)... 0.005 75 3 yes 0.03 0.45 0.01 0.35 0.14 500

Erase all

Viewport... 0 6 0 3

Draw... 0 0 0 500 yes

select Pitch 'soundName$'

f0=0

i=0.02

while f0=0 and 'i'<'length'

f0=Get value at time... i Hertz Linear

if f0=undefined

f0=0

endif

i='i'+0.005

endwhile

onsettime='i'-0.005

print 'onsettime'

그림 3.2 피치값이 0이상인 시작점

이 때 f0가 0보다 큰 양의 값이 되면 while문을 빠져나오게 되는데 이 때의 i값은 0.005가 이미 더해지게 된다. 그래서, 실제의 정확한 onsetime은 i에 0.005가 더해지기 전의 위치가 되어야한다. 위의 스크립트를 숫자음 6에 실행한 결과 0.0599로 나타났다. 반올림하여 0.06에 해당하는 지점을 커서를 옮겨보면 그림 3.2처럼 나타난다. 언제든지 스크립트가 정확하게 원하는 지점을 제대로 찾는지를 반드시 편집창에서 열어보고 확인하도록 한다.

다음으로는 피치 값이 다시 0으로 내려가는 지점을 유성음 구간의 끝으로 지정하는 스크립트다. 위의 f0 시작점을 찾는 스크립트에서 while의 조건을 'f0'>0 and 'i'<'length'로 지정하여 이 조건을 빠져 나온 지점이 유성음 구간의 끝점(offsettime)이 된다. 이 때 마지막 offsettime은 이미 0.005초가 더해졌기 때문에 실제는 0.005초를 뺀 지점이 정확한 위치가 된다. 위의 스크립트에서 이 부분을 추가하여 만들어 보았다.

<pitchanalysis3.sk>

clearinfo

soundName$=selected$("Sound")

select Sound 'soundName$'

length=Get duration

To Pitch (ac)... 0.005 75 3 yes 0.03 0.45 0.01 0.35 0.14 500

Erase all

Viewport... 0 6 0 3

Draw... 0 0 0 500 yes

select Pitch 'soundName$'

f0=0

i=0.02

while f0=0 and 'i'<'length'

f0=Get value at time... i Hertz Linear

if f0=undefined

f0=0

endif

i='i'+0.005

endwhile

onsettime='i'-0.005

print onset 'onsettime:3''newline$'

while f0>0 and 'i'<'length'

f0=Get value at time... i Hertz Linear

if f0=undefined

f0=0

endif

i='i'+0.005

endwhile

offsettime='i'-0.01

print offset 'offsettime:3''newline$

위의 스크립트를 숫자음 6에 실행하면 정보창에는 다음처럼 나타난다. 이 두 지점을 편집창에서 나타내어 보면 다음 그림 3.3과 같다.

onset 0.060

offset 0.400

그림 3.3 피치값이 0이상인 분석구간


여기서 시작점과 끝점사이의 값을 빼면 피치값이 구해진 유성음 구간의 지속시간이 되고, 이를 4로 나누어 시작점과 끝점과 이들 사이에 세 개의 측정 지점을 구하면 비록 지속시간은 다르더라도 서로 비교할 수 있는 상대적인 다섯 개의 측정위치 시간점이 된다. 이런 상대적인 측정위치는 숫자음 6을 발성할 때 어떤 사람은 길게 발음하고 다른 사람은 짧게 발음할 경우에 시간점 위치에 따라 측정값이 바뀌게 된다. 이런 값들은 서로 비교할 수 없게 되는데, 이를 해결하려면 전체지속시간에 따라 상대적인 시간점을 구하여 비교하는 방안이 가능하다. 물론 완전히 다른 방식으로 발음한 사람의 측정값과는 비교할 수 없어도 개인별 변화폭 등을 관찰하는 데 도움이 된다. 위의 스크립트에 추가하여 다섯 개 시간점(aa, bb, cc, dd, ee)을 구하는 방법은 다음 스크립트로 만들 수 있다.

<pitchanalysis4.sk>

f0duration='offsettime'-'onsettime'

divider='f0duration'/4

pointaa='onsettime'

pointbb='onsettime'+'divider'

pointcc='onsettime'+'divider'*2

pointdd='onsettime'+'divider'*3

pointee='offsettime'

print point aa 'pointaa:3''newline$'

print point bb 'pointbb:3''newline$'

print point cc 'pointcc:3''newline$'

print point dd 'pointdd:3''newline$'

print point ee 'pointee:3''newline$'

위의 스크립트에서는 총 지속시간을 구하고 이를 4등분하여 이를 divider변수에 넣고 시작점부터 차례로 더해나가는 방법을 사용했다. 만약 분석할 위치가 10개 이상의 시간점이 된다면 위의 스크립트의 시간점을 배열을 이용하여 point'1', point'2'∼point'10'으로 지정하고, for구문으로 간단하게 만들 수도 있지만 이 책 뒷부분에서 설명하기로 한다. 이렇게 실행하면 정보창에는 다음과 같이 나타난다.

point aa 0.060

point bb 0.145

point cc 0.230

point dd 0.315

point ee 0.400

먼저, 이 다섯 개 시간점 가운데 시작점에 해당하는 aa지점의 피치값을 구하는 과정만 설명한다. 피치값의 변화가 시작점과 끝점과 같은 가장자리에서 측정되는 값은 정확하지 않는 경향이 있다. 이를 피하기 위해서는 측정지점 앞뒤의 값을 구하여 평균과 표준편차값을 구하여 걸러내는 것이 바람직하다. 일반적으로 피치값의 변화를 나타내는 성대의 떨림이 일정한 높이에서 출발하여 서서히 높아지거나 낮아지는 경향이 있고 임의의 시간점 주변에서는 편차가 적다. 피치분석 알고리즘은 단절된 구간을 창문범위로 잡고 그 안에서 값을 구하기 때문에 주변의 피치값을 참조하지 않는 경향이 있다. 그래서 측정 피치값이 갑자기 튀어 오르다가 내려가는 기계적인 값들로 나타나는 경우가 종종 있다. 이를 보완하기위해서 측정 시간점 전후 20 ms구간의 평균값과 표준편차를 취하여 그 범위를 벗어나면 평균값을 피치값으로 지정하는 방법을 살펴보자. 구체적으로는 평균값에 3표준편차 값을 더하거나 빼어서 구한 피치범위(f0low∼f0high)를 찾은 뒤 실제 구한 피치값이 이 범위 안에 들어있을 때는 이 값을 피치값으로 지정하고 그렇지 않으면 이 지점 전후 20 ms구간의 평균값을 대입한다.

<pitchanalysis3.sk> 

select Pitch 'soundName$'

f0on='pointaa'-0.01

f0off='pointaa'+0.01

avf0=Get mean... f0on f0off Hertz

sdf0=Get standard deviation... f0on f0off Hertz

f0high='avf0'+3*'sdf0'

f0low='avf0'-3*'sdf0'

aaf0=Get value at time... pointaa Hertz Linear

if aaf0=undefined

aaf0=0

endif

if aaf0>'f0high' or aaf0<'f0low'

aaf0='avf0'

endif

print avf0 'avf0:1''tab$' sdf0 'sdf0:0''newline$'

print f0high 'f0high:1''tab$' f0low 'f0low:1''newline$'

print aaf0 'aaf0:1''newline$'

위의 스크립트를 추가하여 실행하면 정보창에 다음과 같이 출력된다.

avf0 151.9 sdf0 0.005

f0high 151.9 f0low 151.9

aaf0 151.9

표준편차값의 3배인 0.015이상인 경우와 아닌 경우를 나누어보았지만 다행히 프라트의 분석프로그램에서는 피치값의 에러가 많지 않기 때문에 실제 피치값에서는 별로 큰 변화가 없게 된다. 하지만 소음성이 강한 자음의 경우에는 가끔씩 에러가 나오기 때문에 이를 한번 시도해보는 것도 필요하다.

이어서, 시간점 aa에서의 진폭값을 구하는 경우를 생각해보자. 진폭 값도 피치값과 마찬가지로 20 ms구간내의 평균과 표준편차를 구하여 걸러주도록 다음과 같이 스크립트를 만들어 보자.

<pitchanalysis3.sk>

select Sound 'soundName$'

To Intensity... 100 0.005

dbon='pointaa'-0.01

dboff='pointaa'+0.01

avdb=Get mean... dbon dboff

sddb=Get standard deviation... dbon dboff

dbhigh='avdb'+3*'sddb'

dblow='avdb'-3*'sddb'

aadb=Get value at time... 0.54 Cubic

if aadb=undefined

aadb=0

endif

if aadb>'dbhigh' or aadb<'dblow'

aadb='avdb'

endif

print avdb 'avdb:1''tab$' sddb 'sddb:0''newline$'

print dbhigh 'dbhigh:1''tab$' dblow 'dblow:1''newline$'

print aadb 'aadb:1''newline$'

이 스크립트에서 To Intensity... 100 0.005는 음성의 크기를 나타내는 진폭을 구하는 방식으로 0.005초마다 100 Hz이상의 음성의 특징을 포착한다. 주파수 값을 높이면 보다 더 세부적인 음성의 진폭변화를 볼 수 있다. 음성시작부분과 끝부분의 진폭값은 변화가 급격한 경우가 많기 때문에 평균값을 취하는 것이 바람직한 것으로 여겨진다. 위의 스크립트를 실행하면 정보창에 다음과 같이 나타난다.

avdb 52.1 sddb 5

dbhigh 66.2 dblow 38.1

aadb 52.1

다음으로는 성도의 공명 특성인 포먼트값을 구해야 하는데 분석 구간과 방식에 따라 포먼트값은 음절 초와 음절 말에서 변화가 심하다. 이것을 다음과 같이 평균값과 표준편차를 이용해서 걸러주는 작업을 하는 것이 필요하다. 포먼트값의 변화는 앞서 다루었던 피치와 진폭의 변화보다는 약간 큰 편차를 보이기 때문에 분석할 시간점 앞뒤의 평균값과 2 표준편차를 기준으로 이보다 높거나 낮은 경우에는 음성이 갑자기 변하지는 않는다는 가정 하에 에러 값으로 버리고 이 시간영역의 평균값을 취한다. 지면의 길이를 줄이기 위해 시작점(aa)의 F1, F2, F3값을 구하는 스크립트만 제시한다.

<pitchanalysis5.sk>

select Sound 'soundName$'

To Formant (burg)... 0 5 5000 0.025 50

select Formant 'soundName$'

fmon='pointaa'-0.01

fmoff='pointaa'+0.01

avf1=Get mean... 1 fmon fmoff Hertz

sdf1=Get standard deviation... 1 fmon fmoff Hertz

avf2=Get mean... 2 fmon fmoff Hertz

sdf2=Get standard deviation... 2 fmon fmoff Hertz

avf3=Get mean... 3 fmon fmoff Hertz

sdf3=Get standard deviation... 3 fmon fmoff Hertz

f1high='avf1'+2*'sdf1'

f1low='avf1'-2*'sdf1'

f2high='avf2'+2*'sdf2'

f2low='avf2'-2*'sdf2'

f3high='avf3'+2*'sdf3'

f3low='avf3'-2*'sdf3'

aaf1= Get value at time... 1 pointaa Hertz Linear

if aaf1=undefined

aaf1=500

endif

if aaf1>'f1high' or aaf1<'f1low'

aaf1='avf1'

endif

aaf2= Get value at time... 2 pointaa Hertz Linear

if aaf2=undefined

aaf2=1500

endif

if aaf2>'f2high' or aaf2<'f2low'

aaf2='avf2'

endif

aaf3= Get value at time... 3 pointaa Hertz Linear

if aaf3=undefined

aaf3=2500

endif

if aaf3>'f3high' or aaf3<'f3low'

aaf3='avf3'

endif

print avf1 'avf1:0''tab$' sdf1 'sdf1:0''newline$'

print f1high 'f1high:0''tab$' f1low 'f1low:0''newline$'

print aaf1 'aaf1:0''newline$'

print avf2 'avf2:0''tab$' sdf2 'sdf2:0''newline$'

print f2high 'f2high:0''tab$' f2low 'f2low:0''newline$'

print aaf2 'aaf2:0''newline$'

print avf3 'avf3:0''tab$' sdf3 'sdf3:0''newline$'

print f3high 'f3high:0''tab$' f3low 'f3low:0''newline$'

print aaf3 'aaf3:0''newline$'

위의 스크립트를 실행하고 나면 다음과 같이 정보창에 인쇄된다.

avf1 274 sdf1 11

f1high 296 f1low 252

aaf1 276

avf2 2326 sdf2 56

f2high 2439 f2low 2214

aaf2 2301

avf3 3147 sdf3 22

f3high 3192 f3low 3102

aaf3 3128

이 모든 과정을 하나의 스크립트로 통합하여 다섯 개의 시간점에서 피치값, 강도값, 포먼트값을 정보창에 나타내려면 다음과 같다. 그림 창에는 포먼트의 위치를 확인하는데 가장 중요한 도움이 되는 스펙트로그램을 배경그림으로 함께 나타내게 한다.

<fivepointanalysis#.sk>

clearinfo

Erase all

Viewport... 0.5 7 0.5 6

soundName$=selected$("Sound")

select Sound 'soundName$'

length=Get duration

To Spectrogram... 0.005 5000 0.002 30 Gaussian

Paint... 0 0 0 0 100 yes 30 6 0 yes

select Sound 'soundName$'

To Pitch (ac)... 0.005 75 3 yes 0.03 0.45 0.01 0.35 0.14 500

Red

Draw... 0 0 0 400 no

select Sound 'soundName$'

To Intensity... 100 0.005

Lime

Draw... 0 0 30 110 no

select Sound 'soundName$'

To Formant (burg)... 0 5 5000 0.025 50

Navy

Speckle... 0 0 5000 30 no

select Pitch 'soundName$'

f0=0

i=0.02

while f0=0 and 'i'<'length'

f0=Get value at time... i Hertz Linear

if f0=undefined

f0=0

endif

i='i'+0.005

endwhile

onsettime='i'-0.005

while f0>0 and 'i'<'length'

f0=Get value at time... i Hertz Linear

if f0=undefined

f0=0

endif

i='i'+0.005

endwhile

offsettime='i'-0.01

syllableduration='offsettime'-'onsettime'

divider='syllableduration'/4

pointaa='onsettime'

pointbb='onsettime'+'divider'

pointcc='onsettime'+'divider'*2

pointdd='onsettime'+'divider'*3

pointee='offsettime'

select Pitch 'soundName$'

f0on='pointaa'-0.01

f0off='pointaa'+0.01

avf0=Get mean... f0on f0off Hertz

sdf0=Get standard deviation... f0on f0off Hertz

f0high='avf0'+3*'sdf0'

f0low='avf0'-3*'sdf0'

aaf0=Get value at time... pointaa Hertz Linear

if aaf0=undefined

aaf0=0

endif

if aaf0>'f0high' or aaf0<'f0low'

aaf0='avf0'

endif

select Intensity 'soundName$'

dbon='pointaa'-0.01

dboff='pointaa'+0.01

avdb=Get mean... dbon dboff

sddb=Get standard deviation... dbon dboff

dbhigh='avdb'+3*'sddb'

dblow='avdb'-3*'sddb'

aadb=Get value at time... pointaa Cubic

if aadb=undefined

aadb=0

endif

if aadb>'dbhigh' or aadb<'dblow'

aadb='avdb'

endif

select Formant 'soundName$'

fmon='pointaa'-0.01

fmoff='pointaa'+0.01

avf1=Get mean... 1 fmon fmoff Hertz

sdf1=Get standard deviation... 1 fmon fmoff Hertz

avf2=Get mean... 2 fmon fmoff Hertz

sdf2=Get standard deviation... 2 fmon fmoff Hertz

avf3=Get mean... 3 fmon fmoff Hertz

sdf3=Get standard deviation... 3 fmon fmoff Hertz

f1high='avf1'+2*'sdf1'

f1low='avf1'-2*'sdf1'

f2high='avf2'+2*'sdf2'

f2low='avf2'-2*'sdf2'

f3high='avf3'+2*'sdf3'

f3low='avf3'-2*'sdf3'

aaf1= Get value at time... 1 pointaa Hertz Linear

if aaf1=undefined

aaf1=500

endif

if aaf1>'f1high' or aaf1<'f1low'

aaf1='avf1'

endif

aaf2= Get value at time... 2 pointaa Hertz Linear

if aaf2=undefined

aaf2=1500

endif

if aaf2>'f2high' or aaf2<'f2low'

aaf2='avf2'

endif

aaf3= Get value at time... 3 pointaa Hertz Linear

if aaf3=undefined

aaf3=2500

endif

if aaf3>'f3high' or aaf3<'f3low'

aaf3='avf3'

endif

!point bb

select Pitch 'soundName$'

f0on='pointbb'-0.01

f0off='pointbb'+0.01

avf0=Get mean... f0on f0off Hertz

sdf0=Get standard deviation... f0on f0off Hertz

f0high='avf0'+3*'sdf0'

f0low='avf0'-3*'sdf0'

bbf0=Get value at time... pointbb Hertz Linear

if bbf0=undefined

bbf0=0

endif

if bbf0>'f0high' or bbf0<'f0low'

bbf0='avf0'

endif

select Intensity 'soundName$'

dbon='pointbb'-0.01

dboff='pointbb'+0.01

avdb=Get mean... dbon dboff

sddb=Get standard deviation... dbon dboff

dbhigh='avdb'+3*'sddb'

dblow='avdb'-3*'sddb'

bbdb=Get value at time... pointbb Cubic

if bbdb=undefined

bbdb=0

endif

if bbdb>'dbhigh' or bbdb<'dblow'

bbdb='avdb'

endif

select Formant 'soundName$'

fmon='pointbb'-0.01

fmoff='pointbb'+0.01

avf1=Get mean... 1 fmon fmoff Hertz

sdf1=Get standard deviation... 1 fmon fmoff Hertz

avf2=Get mean... 2 fmon fmoff Hertz

sdf2=Get standard deviation... 2 fmon fmoff Hertz

avf3=Get mean... 3 fmon fmoff Hertz

sdf3=Get standard deviation... 3 fmon fmoff Hertz

f1high='avf1'+2*'sdf1'

f1low='avf1'-2*'sdf1'

f2high='avf2'+2*'sdf2'

f2low='avf2'-2*'sdf2'

f3high='avf3'+2*'sdf3'

f3low='avf3'-2*'sdf3'

bbf1= Get value at time... 1 pointbb Hertz Linear

if bbf1=undefined

bbf1=500

endif

if bbf1>'f1high' or bbf1<'f1low'

bbf1='avf1'

endif

bbf2= Get value at time... 2 pointbb Hertz Linear

if bbf2=undefined

bbf2=1500

endif

if bbf2>'f2high' or bbf2<'f2low'

bbf2='avf2'

endif

bbf3= Get value at time... 3 pointbb Hertz Linear

if bbf3=undefined

bbf3=2500

endif

if bbf3>'f3high' or bbf3<'f3low'

bbf3='avf3'

endif

!point cc

select Pitch 'soundName$'

f0on='pointcc'-0.01

f0off='pointcc'+0.01

avf0=Get mean... f0on f0off Hertz

sdf0=Get standard deviation... f0on f0off Hertz

f0high='avf0'+3*'sdf0'

f0low='avf0'-3*'sdf0'

ccf0=Get value at time... pointcc Hertz Linear

if ccf0=undefined

ccf0=0

endif

if ccf0>'f0high' or ccf0<'f0low'

ccf0='avf0'

endif

select Intensity 'soundName$'

dbon='pointcc'-0.01

dboff='pointcc'+0.01

avdb=Get mean... dbon dboff

sddb=Get standard deviation... dbon dboff

dbhigh='avdb'+3*'sddb'

dblow='avdb'-3*'sddb'

ccdb=Get value at time... pointcc Cubic

if ccdb=undefined

ccdb=0

endif

if ccdb>'dbhigh' or ccdb<'dblow'

ccdb='avdb'

endif

select Formant 'soundName$'

fmon='pointcc'-0.01

fmoff='pointcc'+0.01

avf1=Get mean... 1 fmon fmoff Hertz

sdf1=Get standard deviation... 1 fmon fmoff Hertz

avf2=Get mean... 2 fmon fmoff Hertz

sdf2=Get standard deviation... 2 fmon fmoff Hertz

avf3=Get mean... 3 fmon fmoff Hertz

sdf3=Get standard deviation... 3 fmon fmoff Hertz

f1high='avf1'+2*'sdf1'

f1low='avf1'-2*'sdf1'

f2high='avf2'+2*'sdf2'

f2low='avf2'-2*'sdf2'

f3high='avf3'+2*'sdf3'

f3low='avf3'-2*'sdf3'

ccf1= Get value at time... 1 pointcc Hertz Linear

if ccf1=undefined

ccf1=500

endif

if ccf1>'f1high' or ccf1<'f1low'

ccf1='avf1'

endif

ccf2= Get value at time... 2 pointcc Hertz Linear

if ccf2=undefined

ccf2=1500

endif

if ccf2>'f2high' or ccf2<'f2low'

ccf2='avf2'

endif

ccf3= Get value at time... 3 pointcc Hertz Linear

if ccf3=undefined

ccf3=2500

endif

if ccf3>'f3high' or ccf3<'f3low'

ccf3='avf3'

endif

!point dd

select Pitch 'soundName$'

f0on='pointdd'-0.01

f0off='pointdd'+0.01

avf0=Get mean... f0on f0off Hertz

sdf0=Get standard deviation... f0on f0off Hertz

f0high='avf0'+3*'sdf0'

f0low='avf0'-3*'sdf0'

ddf0=Get value at time... pointdd Hertz Linear

if ddf0=undefined

ddf0=0

endif

if ddf0>'f0high' or ddf0<'f0low'

ddf0='avf0'

endif

select Intensity 'soundName$'

dbon='pointdd'-0.01

dboff='pointdd'+0.01

avdb=Get mean... dbon dboff

sddb=Get standard deviation... dbon dboff

dbhigh='avdb'+3*'sddb'

dblow='avdb'-3*'sddb'

dddb=Get value at time... pointdd Cubic

if dddb=undefined

dddb=0

endif

if dddb>'dbhigh' or dddb<'dblow'

dddb='avdb'

endif

select Formant 'soundName$'

fmon='pointdd'-0.01

fmoff='pointdd'+0.01

avf1=Get mean... 1 fmon fmoff Hertz

sdf1=Get standard deviation... 1 fmon fmoff Hertz

avf2=Get mean... 2 fmon fmoff Hertz

sdf2=Get standard deviation... 2 fmon fmoff Hertz

avf3=Get mean... 3 fmon fmoff Hertz

sdf3=Get standard deviation... 3 fmon fmoff Hertz

f1high='avf1'+2*'sdf1'

f1low='avf1'-2*'sdf1'

f2high='avf2'+2*'sdf2'

f2low='avf2'-2*'sdf2'

f3high='avf3'+2*'sdf3'

f3low='avf3'-2*'sdf3'

ddf1= Get value at time... 1 pointdd Hertz Linear

if ddf1=undefined

ddf1=500

endif

if ddf1>'f1high' or ddf1<'f1low'

ddf1='avf1'

endif

ddf2= Get value at time... 2 pointdd Hertz Linear

if ddf2=undefined

ddf2=1500

endif

if ddf2>'f2high' or ddf2<'f2low'

ddf2='avf2'

endif

ddf3= Get value at time... 3 pointdd Hertz Linear

if ddf3=undefined

ddf3=2500

endif

if ddf3>'f3high' or ddf3<'f3low'

ddf3='avf3'

endif

!point ee

select Pitch 'soundName$'

f0on='pointee'-0.01

f0off='pointee'+0.01

avf0=Get mean... f0on f0off Hertz

sdf0=Get standard deviation... f0on f0off Hertz

f0high='avf0'+3*'sdf0'

f0low='avf0'-3*'sdf0'

eef0=Get value at time... pointee Hertz Linear

if eef0=undefined

eef0=0

endif

if eef0>'f0high' or eef0<'f0low'

eef0='avf0'

endif

select Intensity 'soundName$'

dbon='pointee'-0.01

dboff='pointee'+0.01

avdb=Get mean... dbon dboff

sddb=Get standard deviation... dbon dboff

dbhigh='avdb'+3*'sddb'

dblow='avdb'-3*'sddb'

eedb=Get value at time... pointee Cubic

if eedb=undefined

eedb=0

endif

if eedb>'dbhigh' or eedb<'dblow'

eedb='avdb'

endif

select Formant 'soundName$'

fmon='pointee'-0.01

fmoff='pointee'+0.01

avf1=Get mean... 1 fmon fmoff Hertz

sdf1=Get standard deviation... 1 fmon fmoff Hertz

avf2=Get mean... 2 fmon fmoff Hertz

sdf2=Get standard deviation... 2 fmon fmoff Hertz

avf3=Get mean... 3 fmon fmoff Hertz

sdf3=Get standard deviation... 3 fmon fmoff Hertz

f1high='avf1'+2*'sdf1'

f1low='avf1'-2*'sdf1'

f2high='avf2'+2*'sdf2'

f2low='avf2'-2*'sdf2'

f3high='avf3'+2*'sdf3'

f3low='avf3'-2*'sdf3'

eef1= Get value at time... 1 pointee Hertz Linear

if eef1=undefined

eef1=500

endif

if eef1>'f1high' or eef1<'f1low'

eef1='avf1'

endif

eef2= Get value at time... 2 pointee Hertz Linear

if eef2=undefined

eef2=1500

endif

if eef2>'f2high' or eef2<'f2low'

eef2='avf2'

endif

eef3= Get value at time... 3 pointee Hertz Linear

if eef3=undefined

eef3=2500

endif

if eef3>'f3high' or eef3<'f3low'

eef3='avf3'

endif

select Pitch 'soundName$'

Remove

select Intensity 'soundName$'

Remove

select Formant 'soundName$'

Remove

select Spectrogram 'soundName$'

Remove

print Point:'tab$'aa'tab$'bb'tab$'cc'tab$'dd'tab$'ee'newline$'

print db:'tab$''aadb:0''tab$''bbdb:0''tab$''ccdb:0''tab$''dddb:0''tab$''eedb:0''newline$'

print f0:'tab$''aaf0:0''tab$''bbf0:0''tab$''ccf0:0''tab$''ddf0:0''tab$''eef0:0''newline$'

print F1:'tab$''aaf1:0''tab$''bbf1:0''tab$''ccf1:0''tab$''ddf1:0''tab$''eef1:0''newline$'

print F2:'tab$''aaf2:0''tab$''bbf2:0''tab$''ccf2:0''tab$''ddf2:0''tab$''eef2:0''newline$'

print F3:'tab$''aaf3:0''tab$''bbf3:0''tab$''ccf3:0''tab$''ddf3:0''tab$''eef3:0''newline$'

print 'newline$'

print Data:'tab$'db'tab$'f0'tab$'F1'tab$'F2'tab$'F3'newline$'

print aa'tab$''aadb:0''tab$''aaf0:0''tab$''aaf1:0''tab$''aaf2:0''tab$''aaf3:0''newline$'

print bb'tab$''bbdb:0''tab$''bbf0:0''tab$''bbf1:0''tab$''bbf2:0''tab$''bbf3:0''newline$'

print cc'tab$''ccdb:0''tab$''ccf0:0''tab$''ccf1:0''tab$''ccf2:0''tab$''ccf3:0''newline$'

print dd'tab$''dddb:0''tab$''ddf0:0''tab$''ddf1:0''tab$''ddf2:0''tab$''ddf3:0''newline$'

print ee'tab$''eedb:0''tab$''eef0:0''tab$''eef1:0''tab$''eef2:0''tab$''eef3:0''newline$'

위의 스크립트를 숫자음 '6'에 실행하면 그림창에 그림 3.4와 같이 그려진다.

그림 3.4 숫자음 6의 피치, 포먼트, 진폭, 스펙트로그램


위의 스크립트를 숫자음 '6'에 실행하면 다섯 개의 시간점에서 구해진 음향분석 결과가 다음과 같이 정보창에 출력된다.

Point: aa bb cc dd ee

db: 53 66 76 75 56

f0: 152 129 146 142 121

F1: 276 269 307 402 370

F2: 2301 2366 1941 1001 1260

F3: 3128 3223 2472 2718 2683

Data: db f0 F1 F2 F3

aa 53 152 276 2301 3128

bb 66 129 269 2366 3223

cc 76 146 307 1941 2472

dd 75 142 402 1001 2718

ee 56 121 370 1260 2683

첫 번째 표에 들어있는 데이터를 엑셀에 넣어서 그래프로 나타내면 다음과 같다. 엑셀로 파일을 보낼 때는 정보창에서 복사하여 바로 가져가야한다. 만약 이 파일을 아래한글로 가져온 뒤에 그것을 복사하여 다시 엑셀로 보내면 탭키가 모두 스페이스로 자동 변환되므로 엑셀에서 텍스트로 바꾸기를 해야 한다.

그림 3.5 엑셀을 이용한 피치, 포먼트, 진폭 그래프

3.3 음성구간 자동 분리하기

음성구간을 찾아낼 때는 강도값을 이용하여 평균과 표준편차를 구하여 시작부분에서 1표준편차이상이 되는 곳과 끝나는 부분에서 1표준편차이상이 되는 곳의 시간점을 구하여 잘라내면 음성구간만 선택하는 것이 된다. 실제 강도값은 각 음성파일을 제곱하여 음과 양의 수를 양의 값으로 만든 뒤 그 평균과 표준편차를 이용하면 된다. 만약에 모든 음성파일을 제곱하려면 공식란에 self^2를 하면 된다. 아래의 스크립트는 객체창에 불려진 음성파일의 강도곡선을 구하고 강도값의 평균과 표준편차를 구해 평균+(표준편차/5)를 문턱값으로 지정하여 처음에서 이 값이 되는 부분을 시작점으로 하고 끝에서 거꾸로 검색하여 이 값이 되는 지점을 끝점으로 하여 그 구간만 따로 잘라내어 trimmed라는 음성파일로 보여준다. 이 스크립트를 이용하여 음절에 해당하는 부분을 찾아내는데 사용할 수 있을 것이다. 더 많은 음절들을 분리하여 객체창에 별도로 나타내려면, 강도곡선에서 최대값 정점을 중심으로 올라가거나 내려가는 위치를 찾아 몇 개의 음절로 분리할 수 있을 것이다.

<dbtrim.sk>

name$=selected$("Sound")

totdur=Get duration

call intenser

call onseter

call offseter

call trim

call cleanall

procedure intenser

select Sound 'name$'

To Intensity... 100 0

dbmean=Get mean... 0 0

dbsd=Get standard deviation... 0 0

dbmax=Get maximum... 0 0 Parabolic

dbmin=Get minimum... 0 0 Parabolic

dbcut='dbmean'+('dbsd'/5)

finish='totdur'-0.04

endproc

procedure onseter

select Intensity 'name$'

timer=0.02

i=0

call db

while 'dbval'<'dbcut'

i='i'+1

timer='i'*0.005+0.01

call db

endwhile

onset='timer'-0.0075

endproc

procedure offseter

timer='totdur'-0.02

i=0

call db

while 'dbval'<'dbcut'

i='i'+1

timer='totdur'-('i'*0.005)

call db

endwhile

offset='timer'+0.0075

endproc

procedure db

dbval=Get value at time... 'timer' Cubic

if dbval=undefined

dbval=0

endif

endproc

procedure trim

select Sound 'name$'

Edit

editor Sound 'name$'

Select... 'onset' 'offset'

Extract selection

endeditor

Rename... trimmed

endproc

procedure cleanall

select Sound 'name$'

Remove

select Intensity 'name$'

Remove

select Sound trimmed

Remove

endproc

위의 스크립트를 숫자음 '6'에 적용하면 그림 3.6과 같이 선택된 부분이 trimmed라는 객체로 창에 나타난다.

3.4 음성변형에 관한 스크립트

프라트의 Manipulation기능은 사람의 음성의 특성 가운데 피치, 진폭, 속도의 세가지 초분절음 부분을 원음을 그대로 보존하면서 변형할 수 있는 훌륭한 기능을 가지고 있다. 영어교육에서 원어민의 발음을 따라하는 것보다 학생 자신의 발음을 듣고 따라하면 더욱 더 친근감이 있게 되고 자신의 발음에 문제가 되는 초음절음 부분을 변형하여 바르게 발음하도록 습관화시킬 수 있겠다.

그림 3.6 숫자음 6의 일부를 잘라서 나타내기

구체적으로, 학생의 영어발음을 문제가 있는 음절이나 단어부분을 찾아 속도를 늘리거나 줄여서 학습할 수 있도록 만들어 주는데 활용할 수 있다. 또한 임상적으로는 언어치료에 활용할 수 있다. 보통 너무 빠르거나 높은 음성으로 발성함으로써 후두에 결절이 생긴 환자의 목소리를 개선하기 위해서는 평소에 목소리를 보다 낮은 피치와 크기로 천천히 발음하도록 함으로써 상당히 개선시킬 수 있다. 음성을 조절하기 위해서는 환자 자신이 자신의 목소리가 너무 높다는 것을 평소에 늘 쓰는 발음들을 녹음한 다음 이를 다양하게 변형시켜 여러 번 연습하여 나쁜 습관을 고치고 자신의 귀로 피드백을 받도록 하는데 활용할 수 있다.

3.5 소리의 크기 줄이기

객체창에 불러온 음성신호의 진폭값을 Modify단추의 Formula...를 선택하여 self값을 임의의 값으로 곱하거나 나누어주면 강도값이 줄어지게 된다. 다음 스크립트는 객체창에 불러온 음성을 불러와 0.8, 0.6, 0.4를 곱하여 실제 80%, 60%, 40%로 크기를 줄이는 효과를 보여준다.

soundName$=selected$("Sound")

for i from 1 to 3

rate=1-'i'*0.2

newName$="'soundName$'"+"'i'"

select Sound 'soundName$'

Copy... 'newName$'

Formula... self*'rate'

Play

endfor

위의 스크립트를 숫자음 '6'에 실행한 뒤 원래의 음성과 세 개의 변형된 파일의 강도값을 측정하여 그래프로 그려보면 그림 3.7과 같다. 맨 위의 강도가 원래의 음성을 나타낸다.

그림 3.7 강도값 변형 그림

3.6 연속스펙트럼 그리기

스크립트를 이용하여 좁은대역의 스펙트럼을 연속으로 그려서, 음성의 음향특징이 어떻게 변화하는지 관찰할 수 있다. 다음 스크립트는 연속스펙트럼을 그림창에 나타내는 것이다. 실제 음성파형에서 스펙트럼을 구해보면 고주파 부분이 매우 낮은 진폭값을 가지게 된다. 이를 보상하기위해서는 고주파대역 강조(Pre-emphasize)를 해야 한다. 아래 스크립트에서는 500 Hz부터 강조한다.

<narrspecgraph.sk>

Erase all

name$=selected$("Sound")

select Sound 'name$'

Pre-emphasize (in-line)... 500

To Spectrogram... 0.029 5000 0.002 10 Gaussian

for k from 1 to 20

timer='k'*0.005

select Spectrogram 'name$'

To Spectrum (slice)... 'timer'

Viewport... 0 6 'k'*0.6 'k'*0.6+3

Viewport... 0 6 'k'*0.6 'k'*0.5+3

Draw... 0 0 30 110 no

Remove

endfor

숫자음 '6'에 위의 연속스펙트럼 그리기 스크립트를 실행하면 그림 3.8과 같이 나타난다.

그림 3.8 좁은대역 연속 스펙트럼 만들기


위의 스크립트에서 좁은대역의 스펙트로그램을 만드는 것은 다섯 번째 줄의 To Spectrogram... 0.029 5000 0.002 10 Gaussian이라는 표현 가운데 0.029라는 창의 크기이다. 이것을 0.007로 하면 그림 3.9와 같이 넓은대역의 스펙트로그램이 되고, 스펙트럼의 변화모양은 달라진다.

그림 3.9 넓은대역 연속스펙트럼

넓은대역의 스펙트럼은 5밀리초 마다 하나씩 구하여 스펙트럼으로 나타낸다면 매우 불안정한 모습을 보이게 된다. 다시 말해서, 넓은대역으로 스펙트럼을 분석한 자료를 근거로 일정한 규칙을 찾아 모델을 만들려면 매우 어려울 것이다.

3.8 음성의 재생속도 바꾸기

다음으로는 속도를 바꾸는 스크립트에 대해 알아본다. 한 음성의 속도를 변형하려면 먼저 객체창에 불러온 음성의 전체지속시간(dur)을 구한 뒤 이 값의 반을 durhalf에 저장하고 원래의 파일을 보존하기 위해서는 for 되풀이 구문 안에서 다른 이름으로 파일을 만들어야 한다. 이렇게 중간 지점값을 구하는 것은 다음과 같은 변형창에서 한 지점을 선택한 뒤 지속시간 비율을 조정해야하기 때문이다.

그림 3.10에서는 0.2525가 총지속시간의 반인 지점이 선택되어 있는데, Manipulation편집창의 Dur기본메뉴에서 그림 3.11과 같이 Add duration point라는 하위메뉴에 이 값이 입력되어야하고, Relative duration칸에 상대적인 비율을 입력해 주어야한다.

그림 3.10 변형 편집창의 커서 위치


아래의 스크립트에서는 변형할 음성파일의 이름을 새로 지정하여, Manipulation메뉴를 실행하고, 이를 1.1, 1.2, 1.3배의 순서로 늘린 다음, 재생하게 한다.

그림 3.11 속도변화 지점 지정하기

soundName$=selected$("Sound")

dur=Get duration

durhalf='dur'/2

for i from 1 to 3

rate=1+'i'*0.2

newName$="'soundName$'"+"'i'"

select Sound 'soundName$'

To Manipulation... 0.01 75 600

Rename... 'newName$'

Edit

editor Manipulation 'newName$'

Add duration point at... 'durhalf' 'rate'

Close

endeditor

Play (PSOLA)

select Manipulation 'newName$'

Remove

endfor

위의 스크립트를 실행한 뒤에 원래의 음성파일과 세 번째 만들어진 파일의 파형을 그려보면 그림 3.12와 같다. 원래의 음성파일의 총지속시간이0.505초였는데, 지속시간을 늘린 음성파일의 총 지속시간은 이 값이 1.6배인 0.808초로 확대되었다.

그림 3.12 숫자음 '6'의 지속시간 늘리기

3.8 음성의 높이 바꾸기

음성의 높이인 피치를 바꾸는 스크립트의 실행과정은 먼저, 음성을 객체창에 불러오고 이를 Manipulation메뉴를 클릭 하여 변형할 준비를 하고 새 이름을 지정한 다음, 여기서 피치계층만 따로 뽑아내어 원래의 값에 일정비율만큼 곱한 새 피치계층값을 대체하여 재생하면 된다.

soundName$=selected$("Sound")

for i from 1 to 3

rate=1-'i'*0.1

newName$="'soundName$'"+"'i'"

select Sound 'soundName$'

To Manipulation... 0.01 75 600

Rename... 'newName$'

Extract pitch tier

Rename... 'newName$'

Formula... self*'rate'

select Manipulation 'newName$'

plus PitchTier 'newName$'

Replace pitch tier

select Manipulation 'newName$'

Play (PSOLA)

select PitchTier 'newName$'

Remove

endfor

위의 스크립트를 실행하고 나면 그림 3.13과 같이 맨 위의 피치값이 차례로 일정비율로 내려가게 할 수 있다.

그림 3.13 피치 낮추기

3.9 음성의 피치, 크기, 속도를 모두 낮추기

위의 세 가지 음성변형과정을 동시에 진행하여 전반적으로 속도와, 크기와 높이를 내리는 파일로 만들려면 다음과 같은 스크립트를 만들면 된다. 여기서 pitchrate와 amprate, durrate는 각각의 변수를 낮추는 비율을 말한다. 낮추어가는 순서는 먼저 속도를 변형한 다음, 이 파일을 음성파일로 만든 뒤 피치계층값을 변형하고 마지막으로 소리의 크기를 줄인다. 이렇게 변형된 음성파일을 하드디스크에 저장하는 명령어는 Write to AIFC file... C:\Praat\'ampName$'인데 하드디스크 경로를 사용자의 컴퓨터의 경로에 맞게 지정하고 줄 맨 앞에 있는 !를 없애면 된다.

soundName$=selected$("Sound")

dur=Get duration

durhalf='dur'/2

for i from 1 to 3

pitchrate=1-'i'*0.1

durrate=1+'i'*0.2

amprate=1-'i'*0.2

pitchName$="'soundName$'"+"pitch"

durName$="'soundName$'"+"dur"

ampName$="'soundName$'"+"amp"+"'i'"

select Sound 'soundName$'

To Manipulation... 0.01 75 600

Rename... 'durName$'

Edit

editor Manipulation 'durName$'

Add duration point at... 'durhalf' 'durrate'

Publish resynthesis

Close

endeditor

Rename... 'pitchName$'

To Manipulation... 0.01 75 600

Rename... 'pitchName$'

Extract pitch tier

Rename... 'pitchName$'

Formula... self*'pitchrate'

select Manipulation 'pitchName$'

plus PitchTier 'pitchName$'

Replace pitch tier

select Manipulation 'pitchName$'

Edit

editor Manipulation 'pitchName$'

Publish resynthesis

Close

endeditor

Rename... 'ampName$'

Formula... self*'amprate'

Play

! Write to AIFC file... C:\Praat\kwon\'ampName$'

select Manipulation 'durName$'

Remove

select Manipulation 'pitchName$'

Remove

select Sound 'ampName$'

Remove

select Sound 'pitchName$'

Remove

select PitchTier 'pitchName$'

Remove

endfor

제 4 장 논문에 사용된 스크립트

4.1 남성의 숫자음 발성에 나타난 화자변이

이 논문에서는 남성이 발성한 숫자음의 발음에 대해 유성음 구간을 추적하고 20개의 상대적인 지점에서의 구간에 대한 피치, 강도, 포먼트값을 구하여 정보창에 출력하는 스크립트이다. 앞의 스크립트보다는 프로시져(procedure)를 많이 이용하여 간략하게 만들려고 해보았다. 객체창에 음성파일을 하나 불러올려두고, 아래의 스크립트를 불러와 실행시키면 된다. 만약 분석할 유성음 구간이 40밀리초 이하이면 불충분한 음성파형자료(Insufficient waveform data)라고 출력하고 멈춘다. 정보창에 출력된 음성분석 파라미터값을 엑셀에 보내어 수집해도 좋고, 만약 직접 파일로 저장하려면 아래 스크립트 가운데 다음 부분의 !를 없애면 컴퓨터 디스크에 파일이름.rs로 텍스트로 자동 저장된다.

! fileappend C:\Praat\'soundName$'.rs 'j''tab$''db:0''tab$''fm0:0''tab$''fm1:0''tab$''fm2:0''tab$''fm3:0''newline$'

! fileappend C:\Praat\'soundName$'.rs 'j''tab$''db:0''tab$''fm0:0''tab$''fm1:0''tab$''fm2:0''tab$''fm3:0''newline$'

논문은 http://hyomin.dongeui.ac.kr/~bgyang/malepercep.pdf을 확인하기 바란다.

<20pointanalysis#.sk>

call setting

call sylpoint

call analyzer

call remover

procedure sylpoint

select Pitch 'soundName$'

while f0=0 and 'timer'<'dur'

f0=Get value at time... timer Hertz Linear

call f00

timer='timer'+0.005

endwhile

onsetpnt='timer'-0.005

while f0>0 and 'timer'<'dur'

Get value at time... timer Hertz Linear

l f00

er='timer'+0.005

endwhile

offsetpnt='timer'-0.01

endproc

procedure f00

f0=Get value at time... timer Hertz Linear

if f0=undefined

f0=0

endif

endproc

procedure analyzer

syldur='offsetpnt'-'onsetpnt'

if syldur<0.04

print Insufficient wafeform data 'newline$'

else

sylratio='syldur'/20

for j from 1 to 19

timer='j'*'sylratio'+'onsetpnt'

call collecter

print 'j''tab$''db:0''tab$''fm0:0''tab$''fm1:0''tab$''fm2:0''tab$''fm3:0''newline$'

! fileappend C:\Praat\'soundName$'.rs 'j''tab$''db:0''tab$''fm0:0''tab$''fm1:0''tab$''fm2:0''tab$''fm3:0''newline$'

endfor

endif

endproc

procedure setting

soundName$=selected$("Sound")

select Sound 'soundName$'

dur=Get duration

finish='dur'-0.04

clearinfo

print Point'tab$'db'tab$'fm0'tab$'fm1'tab$'fm2'tab$'fm3'newline$'

! fileappend C:\Praat\'soundName$'.rs Point'tab$'db'tab$'fm0'tab$'fm1'tab$'fm2'tab$'fm3'newline$'

Erase all

Viewport... 0.5 7 0.5 6

To Spectrogram... 0.005 5000 0.002 30 Gaussian

Paint... 0 0 0 0 100 yes 30 6 0 yes

select Sound 'soundName$'

To Pitch (ac)... 0.005 75 3 yes 0.03 0.45 0.01 0.35 0.14 500

Red

Draw... 0 0 0 400 no

select Sound 'soundName$'

To Intensity... 100 0.005

Lime

Draw... 0 0 30 110 no

select Sound 'soundName$'

To Formant (burg)... 0 5 5000 0.025 50

Navy

Speckle... 0 0 5000 30 no

f0=0

timer=0.02

endproc

procedure collecter

call windower

select Pitch 'soundName$'

avf0=Get mean... timeron timeroff Hertz

sdf0=Get standard deviation... timeron timeroff Hertz

f0high='avf0'+3*'sdf0'

f0low='avf0'-3*'sdf0'

fm0=Get value at time... timer Hertz Linear

if fm0=undefined

fm0=0

endif

if fm0>'f0high' or fm0<'f0low'

fm0='avf0'

endif

select Intensity 'soundName$'

avdb=Get mean... timeron timeroff

sddb=Get standard deviation... timeron timeroff

dbhigh='avdb'+3*'sddb'

dblow='avdb'-3*'sddb'

db=Get value at time... timer Cubic

if db=undefined

db=0

endif

if db>'dbhigh' or db<'dblow'

db='avdb'

endif

select Formant 'soundName$'

avf1=Get mean... 1 timeron timeroff Hertz

sdf1=Get standard deviation... 1 timeron timeroff Hertz

avf2=Get mean... 2 timeron timeroff Hertz

sdf2=Get standard deviation... 2 timeron timeroff Hertz

avf3=Get mean... 3 timeron timeroff Hertz

sdf3=Get standard deviation... 3 timeron timeroff Hertz

f1high='avf1'+2*'sdf1'

f1low='avf1'-2*'sdf1'

f2high='avf2'+2*'sdf2'

f2low='avf2'-2*'sdf2'

f3high='avf3'+2*'sdf3'

f3low='avf3'-2*'sdf3'

fm1= Get value at time... 1 timer Hertz Linear

if fm1=undefined

fm1=500

endif

if fm1>'f1high' or fm1<'f1low'

fm1='avf1'

endif

fm2= Get value at time... 2 timer Hertz Linear

if fm2=undefined

fm2=1500

endif

if fm2>'f2high' or fm2<'f2low'

fm2='avf2'

endif

fm3= Get value at time... 3 timer Hertz Linear

if fm3=undefined

fm3=2500

endif

if fm3>'f3high' or fm3<'f3low'

fm3='avf3'

endif

endproc

procedure windower

timeron='timer'-0.01

timeroff='timer'+0.01

endproc

procedure remover

select Pitch 'soundName$'

Remove

select Intensity 'soundName$'

Remove

select Formant 'soundName$'

Remove

select Spectrogram 'soundName$'

Remove

endproc

위의 스크립트를 실행하면 앞의 다섯 개 지점의 값을 구하는 것과 마찬가지로 그림창에 인쇄되고, 숫자음 '6'에 대해서는 정보창에 다음과 같이 인쇄된다.

Point db fm0 fm1 fm2 fm3

1 61 147 302 2236 3327

2 64 131 272 2215 3248

3 65 130 269 2259 3148

4 65 128 266 2340 3256

5 66 129 269 2366 3223

6 67 132 275 2304 3114

7 69 137 285 2316 2930

8 72 141 295 2284 2736

9 74 144 301 2143 2517

10 76 146 307 1941 2472

11 76 147 317 1558 2534

12 75 147 342 1403 2642

13 74 146 372 1247 2667

14 75 144 395 1136 2716

15 75 142 402 1001 2718

16 76 139 399 968 2767

17 75 134 390 948 2832

18 73 127 366 905 2852

19 69 121 344 836 2850

4.2 두 개 이상의 음절에 대한 음향파라미터값 구하기

위의 스크립트에서는 한 음절로 된 숫자음의 강도, 피치, 포먼트 값을 구해준다. 만일 "아버지"와 같이 세음절로 된 경우에는 어떻게 해야 할까? 먼저 음절의 시작점과 끝점을 구하고 그 구간의 지속시간이 50밀리초 이상일 때는 분석(analyzer) 프로시져를 실행하고 그렇지 않으면 빠져나가도록 한다. 앞의 스크립트와는 다른 위치에 인쇄명령을 내려야하기 때문에 다음과 같이 제시하기로 한다.

<20pointsanalysis2syls.sk>

call setting

call sylpoint

call remover

procedure sylpoint

print Point'tab$'db'tab$'fm0'tab$'fm1'tab$'fm2'tab$'fm3'newline$'

! fileappend C:\Praat\'soundName$'.rs Point'tab$'db'tab$'fm0'tab$'fm1'tab$'fm2'tab$'fm3'newline$'

timer=0.02

p=1

f0=0

while 'timer'<'dur'

select Pitch 'soundName$'

while f0=0 and 'timer'<'dur'

f0=Get value at time... timer Hertz Linear

call f00

timer='timer'+0.005

endwhile

onsetpnt='timer'-0.005

while f0>0 and 'timer'<'dur'

f0=Get value at time... timer Hertz Linear

call f00

timer='timer'+0.005

endwhile

offsetpnt='timer'-0.01

syldur='offsetpnt'-'onsetpnt'

if syldur>0.05

print Syllable Number 'p''newline$'

sylratio='syldur'/20

for j from 1 to 20

timer='j'*'sylratio'+'onsetpnt'

call collecter

print 'j''tab$''db:0''tab$''fm0:0''tab$''fm1:0''tab$''fm2:0''tab$''fm3:0''newline$'

! fileappend C:\Praat\'soundName$'.rs 'j''tab$''db:0''tab$''fm0:0''tab$''fm1:0''tab$''fm2:0''tab$''fm3:0''newline$'

endfor

p='p'+1

endif

endwhile

endproc

procedure f00

f0=Get value at time... timer Hertz Linear

if f0=undefined

f0=0

endif

endproc

procedure setting

soundName$=selected$("Sound")

select Sound 'soundName$'

dur=Get duration

finish='dur'-0.04

clearinfo

Erase all

Viewport... 0.5 7 0.5 6

To Spectrogram... 0.005 5000 0.002 30 Gaussian

Paint... 0 0 0 0 100 yes 30 6 0 yes

select Sound 'soundName$'

To Pitch (ac)... 0.005 75 3 yes 0.03 0.45 0.01 0.35 0.14 500

Red

Draw... 0 0 0 400 no

select Sound 'soundName$'

To Intensity... 100 0.005

Lime

Draw... 0 0 30 110 no

select Sound 'soundName$'

To Formant (burg)... 0 5 5000 0.025 50

Navy

Speckle... 0 0 5000 30 no

endproc

procedure collecter

call windower

select Pitch 'soundName$'

avf0=Get mean... timeron timeroff Hertz

sdf0=Get standard deviation... timeron timeroff Hertz

f0high='avf0'+3*'sdf0'

f0low='avf0'-3*'sdf0'

fm0=Get value at time... timer Hertz Linear

if fm0=undefined

fm0=0

endif

if fm0>'f0high' or fm0<'f0low'

fm0='avf0'

endif

select Intensity 'soundName$'

avdb=Get mean... timeron timeroff

sddb=Get standard deviation... timeron timeroff

dbhigh='avdb'+3*'sddb'

dblow='avdb'-3*'sddb'

db=Get value at time... timer Cubic

if db=undefined

db=0

endif

if db>'dbhigh' or db<'dblow'

db='avdb'

endif

select Formant 'soundName$'

avf1=Get mean... 1 timeron timeroff Hertz

sdf1=Get standard deviation... 1 timeron timeroff Hertz

avf2=Get mean... 2 timeron timeroff Hertz

sdf2=Get standard deviation... 2 timeron timeroff Hertz

avf3=Get mean... 3 timeron timeroff Hertz

sdf3=Get standard deviation... 3 timeron timeroff Hertz

f1high='avf1'+2*'sdf1'

f1low='avf1'-2*'sdf1'

f2high='avf2'+2*'sdf2'

f2low='avf2'-2*'sdf2'

f3high='avf3'+2*'sdf3'

f3low='avf3'-2*'sdf3'

fm1= Get value at time... 1 timer Hertz Linear

if fm1=undefined

fm1=500

endif

if fm1>'f1high' or fm1<'f1low'

fm1='avf1'

endif

fm2= Get value at time... 2 timer Hertz Linear

if fm2=undefined

fm2=1500

endif

if fm2>'f2high' or fm2<'f2low'

fm2='avf2'

endif

fm3= Get value at time... 3 timer Hertz Linear

if fm3=undefined

fm3=2500

endif

if fm3>'f3high' or fm3<'f3low'

fm3='avf3'

endif

endproc

procedure windower

timeron='timer'-0.01

timeroff='timer'+0.01

endproc

procedure remover

select Pitch 'soundName$'

Remove

select Intensity 'soundName$'

Remove

select Formant 'soundName$'

Remove

select Spectrogram 'soundName$'

Remove

endproc

위의 스크립트를 "아버지"라는 단어에 실행하면 그림창에는 그림 4.1과 같이 인쇄된다.

그림 4.1 '아버지' 분석 결과창


정보창에는 다음과 같이 나타나게 된다.

Point db fm0 fm1 fm2 fm3

Syllable Number 1

1 65 153 761 1421 2859

2 70 146 767 1394 2832

3 73 136 785 1419 2822

4 74 134 798 1377 2781

5 76 130 793 1314 2699

6 76 128 807 1321 2749

7 76 127 801 1402 2778

8 77 126 783 1366 2721

9 77 126 784 1346 2698

10 77 126 792 1358 2734

11 77 126 790 1365 2751

12 77 127 787 1330 2712

13 77 127 781 1335 2715

14 77 127 763 1309 2702

15 77 128 743 1292 2693

16 77 128 721 1283 2699

17 76 128 718 1285 2699

18 76 128 710 1258 2696

19 75 127 685 1207 2699

20 72 126 642 1128 2683

Syllable Number 2

1 73 156 473 1175 2646

2 76 153 462 1191 2665

3 77 151 462 1205 2680

4 78 151 463 1205 2686

5 78 150 465 1205 2678

6 78 150 466 1205 2685

7 78 150 470 1208 2698

8 78 150 473 1208 2694

9 77 149 477 1207 2680

10 77 148 480 1212 2685

11 77 148 479 1214 2692

12 76 147 483 1232 2701

13 76 147 482 1238 2707

14 76 147 487 1273 2729

15 76 147 485 1301 2733

16 75 146 485 1344 2736

17 75 145 485 1426 2714

18 75 145 464 1498 2714

19 74 143 429 1580 2774

20 68 142 393 1606 2855

Syllable Number 3

1 69 133 344 2155 2933

2 70 131 341 2181 2960

3 69 128 354 2196 2940

4 69 124 358 2208 2939

5 70 121 354 2215 2931

6 70 119 354 2207 2948

7 70 117 351 2209 2938

8 69 114 351 2219 2929

9 69 112 348 2206 2941

10 68 110 348 2224 2963

11 67 108 349 2231 2955

12 67 104 349 2268 2968

13 66 102 351 2294 2970

14 66 100 348 2238 2935

15 65 98 351 2213 2979

16 65 95 351 2192 2946

17 64 93 354 2251 2950

18 62 92 356 2238 2982

19 60 92 327 2207 2941

20 57 91 204 2208 2964

이 세 개의 음절의 각 음향파라미터를 엑셀로 보내어 그림 4.2와 같이 그래프로 깔끔하게 나타낼 수 있다. x축과 y축의 주파수 표시나 시간점 표시는 그래프 속성을 조정하여 나타내면 된다.

그림 4.2 피치 포먼트 주파수 결과 보이기

실제 진폭값의 변화와 피치값은 포먼트 주파수에 비해 매우 낮기 때문에 임의로 진폭값을 15배 피치값을 12배하고 굵기는 5포인트로 하고 나머지 포먼트값을 나타내는 그래프는 2포인트로 지정하여 그래프로 나타내면 그림 4.3과 같이 그릴 수 있다. 주파수축의 숫자가 자릿수가 많기 때문에 이를 줄이려면 엑셀의 1/1000의 공식을 활용해 kHz로 나타낼 필요가 있다. 너무 많은 숫자나 글자가 있으면 보는 사람의 눈의 집중도도 낮아지게 되므로 가능하면 단순하고 강력한 인상을 줄 수 있는 그래프를 만들기 바란다.

그림 4.3 피치와 진폭값을 곱하여 나타낸 그림

4.3 라링고그라프 신호를 이용한 면적값과 변화율 비교

이 논문에서는 10초 정도의 합성음 '아'를 들으며 같은 피치로 약 5초간 모음을 발성하게 한 뒤 피험자의 성대에 부착한 전극으로 들어오는 신호를 영국에서 개발된 라링고그래프와 최근에 부산대학병원에서 개발한 라링고그라프에 입력하여 처리된 신호의 미세한 차이값을 비교하려고 했다. 구체적으로는 라링고그라프의 신호에서 나타난 성대의 접촉부분과 열린 부분의 강도값을 하나씩 더한 면적값의 비율을 구하여 비교했다. 원래의 논문은 http://hyomin.dongeui.ac.kr/ ~bgyang/200303laryn.PDF에 실려 있다. 아래 스크립트는 먼저 음성파일을 50에서 4,000 Hz까지 대역통과 시킨 다음 각 성문파형의 +/-기호가 반대로 나타났기 때문에 -self공식을 이용하여 바꾼 뒤에 부호가 바뀌는 지점을 찾아 양수로 된 지점까지의 면적값과 음수로 된 지점의 면적값을 구하여 성대의 여닫음의 비율값을 계산하고 이 지점 끼리 빼어서 지속시간을 구하여 피치값을 나타낸다.

<laryngo.sk>

clearinfo

number=1

filename$="lar"+"'number'"

filenamefull$="lar"+"'number'"+".wav"

Read from file... C:\MyDocuments\NormalData\'filenamefull$'

Filter (pass Hann band)... 50 4000 100

filenameband$="'filename$'"+"_band"

select Sound 'filenameband$'

Rename... 'filename$'

dur=Get duration

numsample=40000

samper=Get sample period

finish='dur'-0.04

call setting

call startingpoint

call endingpoint

call sylpoint

procedure setting

i=1

j=1

p=1

sumcontact=0

sumopen=0

endproc

procedure startingpoint

valindex=Get value at index... 'i'

if 'valindex'<0

while 'valindex'<0 and 'i'<'numsample'

i='i'+1

valindex=Get value at index... 'i'

endwhile

else

while 'valindex'>=0 and 'i'<'numsample'

i='i'+1

valindex=Get value at index... 'i'

endwhile

while 'valindex'<0 and 'i'<'numsample'

i='i'+1

valindex=Get value at index... 'i'

endwhile

endif

endproc

procedure endingpoint

j='numsample'

valindex=Get value at index... 'j'

if 'valindex'<0

while 'valindex'<0

j='j'-1

valindex=Get value at index... 'j'

endwhile

while 'valindex'>=0

j='j'-1

valindex=Get value at index... 'j'

endwhile

else

while 'valindex'>=0

j='j'-1

valindex=Get value at index... 'j'

endwhile

endif

endindex='j'+1

endproc

procedure sylpoint

while 'valindex'<0 and 'i'<'endindex'

i='i'+1

valindex=Get value at index... 'i'

endwhile

while 'i'<'endindex'

contactonset'p'='i'

while 'valindex'>0 and 'i'<'endindex'

sumcontact='sumcontact'+'valindex'

i='i'+1

valindex=Get value at index... 'i'

endwhile

cindex='i'-1

contactoffset'p'='cindex'

cvalindex=Get value at index... 'cindex'

openonset'p'='i'

while 'valindex'<=0 and 'i'<'endindex'

sumopen=abs('valindex')+'sumopen'

i='i'+1

valindex=Get value at index... 'i'

endwhile

oindex='i'-1

openoffset'p'='oindex'

ovalindex=Get value at index... 'oindex'

call analyzer

p='p'+1

sumcontact=0

sumopen=0

endwhile

endproc

procedure analyzer

copy contactonset'p' contactonsetpnt

copy contactoffset'p' contactoffsetpnt

copy openonset'p' openonsetpnt

copy openoffset'p' openoffsetpnt

pulsedur='openoffsetpnt'-'contactonsetpnt'

f0=1/('samper'*'pulsedur')

opendur='openoffsetpnt'-'openonsetpnt'

openratio=('opendur'/'p-0ㅔㅣ'sumopen'

fileappend C:\MyDocuments\NormalData\result

print 'p''tab$''f0:0''tab$''openratio:3''tab$''coratio:3''newline$'

endproc

4.4 좁은대역스펙트럼의 차이값과 상관계수값에 의한 비교

이 연구에서는 여성화자가 발음한 숫자음의 피치값과 포먼트값의 측정이 에러가 많아서, 이를 피하기 위해 좁은대역 스펙트럼 정보를 이용하여 개인별 숫자음의 특징을 찾아 모델로 정하고 화자내와 화자간의 값들을 비교하려 시도했다. 아래 스크립트는 예약함수의 일부가 수정되었음을 밝혀둔다. 논문은 http:// hyomin.dongeui.ac.kr/~bgyang/200209spiden.PDF에 실려 있다. 스크립트를 실행하기 전에 C:\Praat\Sounds라는 폴더에 21∼25까지 숫자음 '1'이라는 소리가 다섯 번 말한 것이 각각의 파일로 들어있다고 가정한다. !speaker$="bg"를 이용하면 화자의 이니셜로 된 폴더에 저장된 파일을 자동으로 불러오게 할 수 있다. 다음 스크립트는 직접 실행해 볼 수 있도록 '21'이란 음성파일을 하나만 불러와서 처리하는 과정을 보여준다. 두 번째 줄의 !for r from 21 to 25와 15 번째 줄의 !endfor의 첫머리에 나와 있는 ! 표시를 없애면 자동으로 하나씩 다섯 개의 파일을 불러와 스펙트럼 정보를 하드디스크에 저장해 준다. 스크립트의 개괄적인 실행과정을 설명하면 먼저, 불러온 음성 파일에 대한 피치를 구하고 피치값이 0이상인 시작점과 끝점을 구하여 지속시간을 구한 뒤 이를 20등분하여 처음과 끝부분을 제외한 각 시간점에 대한 좁은대역의 스펙트럼을 3,300 Hz까지 구한다. 좁은대역의 스펙트로그램은 0.029초의 분석구간으로 3,300 Hz까지 0.001초마다 20 Hz의 간격으로 가우시안 창을 씌어 처리된다. 이 때 스펙트럼 세부적인 정보 보다는 각 배음사이의 차이를 줄이기 위해 피치값에 가까운 150 Hz마다 인접 스펙트럼의 장기간 평균 스펙트럼값 (Long-term average spectrum)을 22개씩 구하여 하드디스크에 파일로 저장해준다.

<narrowspcsave.sk>

!speaker$="bg"

!for r from 21 to 25

r$="22"

Read from file... C:\Praat\Sounds\'r$'

soundName$=selected$("Sound")

spc$="'soundName$'"+".spc"

dur=Get duration

finish='dur'-0.04

duround=round('dur'*1000)

clearinfo

call setting

call sylpoint

call analyze

call removeall

!endfor

procedure sylpoint

select Pitch 'soundName$'

while 'f0'=0 and 'timer'<'finish'

f0=Get value at time... timer Hertz Linear

call f00

timer='timer'+0.005

endwhile

onsetpnt='timer'-0.005

while f0>0 and 'timer'<'finish'

f0=Get value at time... timer Hertz Linear

call f00

timer='timer'+0.005

endwhile

offsetpnt='timer'-0.01

endproc

procedure f00

f0=Get value at time... timer Hertz Linear

if f0=undefined

f0=0

endif

endproc

procedure analyze

syldur='offsetpnt'-'onsetpnt'

if 'syldur'>0.04

sylratio='syldur'/20

timer='sylratio'+'onsetpnt'

call loopone

for k from 2 to 19

timer='k'*'sylratio'+'onsetpnt'

call looptwo

endfor

select Matrix matemp

Write to short text file... C:\Praat\Sounds\'spc$'

select Matrix matemp

Remove

endif

endproc

procedure setting

i=1

j=1

k=1

p=1

q=1

x=1

mm=0

timer=0

f0=0

select Sound 'soundName$'

Filter (pre-emphasis)... 50

Rename... 'soundName$'

To Spectrogram... 0.029 3300 0.001 20 Gaussian

select Sound 'soundName$'

To Pitch (ac)... 0.005 75 3 yes 0.03 0.45 0.01 0.35 0.14 500

gf0mean=Get mean... 0 0 Hertz

gf0stdev=Get standard deviation... 0 0 Hertz

gf0high='gf0mean'+'gf0stdev'

gf0low='gf0mean'-'gf0stdev'

endproc

procedure pitcher

call window

select Pitch 'soundName$'

call avsdf0

call f00

if 'f0'>'f0high' or 'f0'<'f0low' or 'f0'>500 or 'f0'<70

f0='avf0'

endif

if 'f0'=undefined

f0=0

endif

if 'f0'>'gf0mean'+3*'gf0stdev'

f0='gf0mean'+randomInteger(3,0)

endif

f0=round('f0')

endproc

procedure avsdf0

call window

avf0=Get mean... avon avoff Hertz

sdf0=Get standard deviation... avon avoff Hertz

f0high='avf0'+3*'sdf0'

f0low='avf0'-3*'sdf0'

endproc

procedure loopone

select Spectrogram 'soundName$'

To Spectrum (slice)... timer

To Ltas... 150

To Matrix

Copy... matemp

call loopremove

endproc

procedure looptwo

select Spectrogram 'soundName$'

To Spectrum (slice)... timer

To Ltas... 150

To Matrix

Copy... k

select Matrix matemp

plus Matrix k

Merge (append rows)

select Matrix matemp

Remove

select Matrix matemp_k

Rename... matemp

select Matrix k

Remove

call loopremove

endproc

procedure loopremove

select Ltas 'soundName$'

Remove

select Spectrum 'soundName$'

Remove

select Matrix 'soundName$'

Remove

endproc

procedure removeall

select Pitch 'soundName$'

Remove

select Spectrogram 'soundName$'

Remove

select Sound 'soundName$'

Remove

endproc

이렇게 구해진 스펙트럼 정보파일인 21.spc를 살펴보면 다음과 같다.

File type = "ooTextFile short"

"Matrix"

0

3300

22

150

75

1

1

19

1

1

68.73555

82.301048

88.528564

75.542709

72.970444

<이하 생략>

이렇게 수집된 스펙트럼 정보의 모델을 만들기 위해서는 개인별로 다섯 번의 발음에 대한 각 시간점의 스펙트럼 정보의 평균을 구하여 하나의 파일로 저장한다. 다음 스크립트는 다섯 개의 *.spc파일을 불러와 평균값을 구해 하드디스크에 저장해준다.

<fivematrixave.sk>

for r from 21 to 25

name$="'r'"

Read from file... C:\Praat\Sounds\'name$'.spc

endfor

j=21

j2=j+1

j3=j+2

j4=j+3

j5=j+4

select Matrix 'j'

plus Matrix 'j2'

Merge (append rows)

plus Matrix 'j3'

Merge (append rows)

plus Matrix 'j4'

Merge (append rows)

plus Matrix 'j5'

Merge (append rows)

Rename... five

for k from 21 to 25

select Matrix 'k'

Remove

endfor

select Matrix 21_22

Remove

select Matrix 23_21_22

Remove

select Matrix 24_23_21_22

Remove

select Matrix five

for i from 1 to 22

for j from 1 to 19

j2=j+19

j3=j2+19

j4=j3+19

j5=j4+19

r1=Get value in cell... j i

r2=Get value in cell... j2 i

r3=Get value in cell... j3 i

r4=Get value in cell... j4 i

r5=Get value in cell... j5 i

ave=round((r1+r2+r3+r4+r5)/5)

Set value... j i 'ave'

endfor

endfor

Create Matrix... final 0 3300 22 150 75 1 1 19 1 1 0

for i from 1 to 22

for j from 1 to 19

select Matrix five

new=Get value in cell... j i

select Matrix final

Set value... j i 'new'

endfor

endfor

select Matrix five

Remove

select Matrix final

Write to short text file... C:\Praat\Sounds\'name$'.final

Remove

이렇게 모델을 만든 뒤 25.final로 된 행렬 파일을 다른 사람이 발성한 숫자음의 모델값 또는 같은 사람이 나중에 발성한 동일한 숫자음과 상호 비교하여 상관계수와 절대차이합을 구하면 된다. 여기서는 한 개의 모델과 동일한 사람이 발성한 숫자음을 비교하는 스크립트를 소개한다.

<matcorrdiff.sk>

clearinfo

Read from file... C:\Praat\Sounds\model.spc

Read from file... C:\Praat\Sounds\26.spc

mat1$="model"

mat2$="26"

select Matrix 'mat1$'

nocol=Get number of columns

norow=Get number of rows

totcol='nocol'*'norow'

select Matrix 'mat1$'

sumx=0

for c from 1 to 'nocol'

for r from 1 to 'norow'

xn=Get value in cell... 'r' 'c'

sumx='sumx'+'xn'

endfor

endfor

sumy=0

select Matrix 'mat2$'

for c from 1 to 'nocol'

for r from 1 to 'norow'

yn=Get value in cell... 'r' 'c'

sumy='sumy'+'yn'

endfor

endfor

select Matrix 'mat1$'

sumxx=0

for c from 1 to 'nocol'

for r from 1 to 'norow'

xn=Get value in cell... 'r' 'c'

sumxx='sumxx'+'xn'*'xn'

endfor

endfor

select Matrix 'mat2$'

sumyy=0

for c from 1 to 'nocol'

for r from 1 to 'norow'

yn=Get value in cell... 'r' 'c'

sumyy='sumyy'+'yn'*'yn'

endfor

endfor

sumxy=0

diffxy=0

for c from 1 to 'nocol'

for r from 1 to 'norow'

select Matrix 'mat1$'

xn=Get value in cell... 'r' 'c'

select Matrix 'mat2$'

yn=Get value in cell... 'r' 'c'

sumxy='sumxy'+'xn'*'yn'

diffxy='diffxy'+abs('xn'-'yn')

endfor

endfor

rxy=(('totcol'*'sumxy'-('sumx'*'sumy')))/(((('totcol'*'sumxx')-('sumx')^2))^0.5*(('totcol'*'sumyy'-('sumy')^2))^0.5)

print 'mat1$' vs 'mat2$' Coefficients 'rxy:4' AbsoluteDiffSum 'diffxy:0'

위의 스크립트를 실행하면 정보창에 다음과 같이 인쇄된다.

model vs 26 Coefficients 0.9060 AbsoluteDiffSum 1588

위의 결과는 숫자음 21에서 25번까지의 평균모델에 대해 26번의 음성은 상관계수가 0.9060이고 서로 일치하는 주파수대의 절대차이합이 1588 데시벨이라는 의미를 나타낸다.

4.5 대역별로 여과한 음성강도의 차이값과 상관계수에 의한 화자확인 연구

이 논문에서는 스펙트럼 정보보다는 안정적인 음성파형의 진폭값을 활용하기 위해 음성을 대역별로 여과한 뒤 구한 강도값 곡선을 일정한 개수로 나눈 뒤 각 시간점의 값들을 구하여 상관계수와 차이값을 비교하려 했다. 본문은 http://hyomin.dongeui.ac.kr/~bgyang/200306filter.PDF을 읽어보기 바란다. 음성분석은 "육백 칠십 팔"이라고 약 4초 이내에 다섯 번 발음한 것을 하드디스크에 저장한다. 하나씩 불러온 음성파일의 전체 강도값의 평균과 표준편차를 구하여 (평균+1/5표준편차)에 해당하는 강도의 문턱값을 구한다. 이 문턱값을 강도값 객체의 처음부터 찾아내어 시작점으로 지정하고, 끝부분에서 찾아내어 끝점으로 지정한다. 이렇게 하여 시작과 끝 부분의 묵음기간을 제외한 음성부분만 선택하여 객체창에 올린다. 이어서, 음성부분으로만 된 객체를 200 Hz에서 4,200 Hz사이를 800 Hz간격으로 다섯 개의 대역으로 여과한다. 여과된 다섯 개의 음성파형에 대한 강도값을 구하고 전체지속시간을 100등분한 상대적인 시간점의 강도값을 구한다. 이 때 강도가 일정수준이하(평균-1/5표준편차)에 해당하면 동일한 값을 부여한다. 한번 발음한 음성에서 5개의 여과된 100개의 시간점에서 구한 500개의 값들을 구하고 다음 번에 발음한 음성에서 구한 값의 상관계수와 절대차이합을 구한다.

다음 스크립트는 하드디스크에 숫자음 678을 다섯 번 발음한 파일(678_100, 678_148, 678_183, 678_187,678_236)이 있다고 가정하고 만들어진 것이다. 678 다음에 오는 숫자는 다른 숫자음과 뒤섞어서 발음하도록 요구했기 때문에 붙여진 것이다. 음성실험에서 연이어 같은 숫자음을 발음하게 하면 초분절음에서 변화가 많은 경우가 있으므로 이를 피하고 자연성을 살리기 위해 임의의 순서로 제시한다.

<dbcordiff.sk>

clearinfo

call readanalyze 678_100

call readanalyze 678_148

call readanalyze 678_183

call readanalyze 678_187

call readanalyze 678_236

call rdiff 678_100 678_148

call rdiff 678_100 678_183

call rdiff 678_100 678_187

call rdiff 678_100 678_236

call rdiff 678_148 678_183

call rdiff 678_148 678_187

call rdiff 678_148 678_236

call rdiff 678_183 678_187

call rdiff 678_183 678_236

call rdiff 678_187 678_236

select Matrix 678_100

Remove

select Matrix 678_148

Remove

select Matrix 678_183

Remove

select Matrix 678_187

Remove

select Matrix 678_236

Remove

procedure readanalyze fname$

Read from file... C:\Praat\Sounds\'fname$'

name$=selected$("Sound")

totdur=Get duration

call intenser

call onseter

call offseter

call trim

call filterit

call process

select Matrix matfinal

Rename... 'fname$'

Write to short text file... C:\Praat\Sounds\'fname$'.mat

call cleanall

endproc

procedure onseter

select Intensity 'name$'

timer=0.02

i=0

call db

while 'dbval'<'dbcut'

i='i'+1

timer='i'*0.005+0.01

call db

endwhile

onset='timer'-0.0075

endproc

procedure offseter

timer='totdur'-0.02

i=0

call db

while 'dbval'<'dbcut'

i='i'+1

timer='totdur'-('i'*0.005)

call db

endwhile

offset='timer'+0.0075

endproc

procedure intenser

select Sound 'name$'

To Intensity... 100 0

dbmean=Get mean... 0 0

dbsd=Get standard deviation... 0 0

dbmax=Get maximum... 0 0 Parabolic

dbmin=Get minimum... 0 0 Parabolic

dbcut='dbmean'+('dbsd'/5)

finish='totdur'-0.04

endproc

procedure db

dbval=Get value at time... 'timer' Cubic

if dbval=undefined

dbval=0

endif

endproc

procedure trim

select Sound 'name$'

Edit

editor Sound 'name$'

Select... 'onset' 'offset'

Extract selection

endeditor

Rename... trimmed

endproc

procedure filterit

select Sound trimmed

newdur=Get duration

for j from 1 to 5

band='j'*800

startband='band'-600

endband='band'+200

smoother=150

!smoother for female pitch level,

!for male it should be around 150 Hz for female around 200 Hz

filterhz$="filter"+"'band'"

select Sound trimmed

Filter (pass Hann band)... 'startband' 'endband' 'smoother'

Rename... filterold

Edit

editor Sound filterold

Select... 0 'newdur'

Extract selection

endeditor

Rename... 'filterhz$'

select Sound filterold

Remove

endfor

endproc

procedure process

!set k for any number of filterbank

Create simple Matrix... matfinal 5 100 0

for k from 1 to 5

band='k'*800

filterhz$="filter"+"'band'"

select Sound 'filterhz$'

To Intensity... 100 0

dbmean=Get mean... 0 0

dbsd=Get standard deviation... 0 0

dbmax=Get maximum... 0 0 Parabolic

dbmin=Get minimum... 0 0 Parabolic

dbcut='dbmean'-('dbsd'/5)

select Intensity 'filterhz$'

timestep='newdur'/100

oldtimepoint=0

for m from 1 to 100

select Intensity 'filterhz$'

timepoint=m*'timestep'+'oldtimepoint'

oldval=Get value at time... 'timepoint' Cubic

if oldval=undefined

oldval='dbcut'

endif

if oldval<'dbcut'

oldval='dbcut'

endif

select Matrix matfinal

Set value... 'k' 'm' 'oldval'

endfor

endfor

endproc

procedure cleanall

select Sound 'name$'

Remove

select Intensity 'name$'

Remove

select Sound trimmed

Remove

for n from 1 to 5

band='n'*800

filterhz$="filter"+"'band'"

select Sound 'filterhz$'

Remove

select Intensity 'filterhz$'

Remove

endfor

! select Matrix matfinal

! Remove

endproc

procedure rdiff mat1$ mat2$

nocol=500

select Matrix 'mat1$'

sumx=0

xn=0

for p from 1 to 5

for q from 1 to 100

xn=Get value in cell... 'p' 'q'

sumx='sumx'+'xn'

endfor

endfor

sumxx=0

xn=0

for p from 1 to 5

for q from 1 to 100

xn=Get value in cell... 'p' 'q'

sumxx='sumxx'+'xn'*'xn'

endfor

endfor

select Matrix 'mat2$'

sumy=0

yn=0

for p from 1 to 5

for q from 1 to 100

yn=Get value in cell... 'p' 'q'

sumy='sumy'+'yn'

endfor

endfor

sumyy=0

yn=0

for p from 1 to 5

for q from 1 to 100

yn=Get value in cell... 'p' 'q'

sumyy='sumyy'+'yn'*'yn'

endfor

endfor

sumxy=0

diffxy=0

xn=0

yn=0

for p from 1 to 5

for q from 1 to 100

select Matrix 'mat1$'

xn=Get value in cell... 'p' 'q'

select Matrix 'mat2$'

yn=Get value in cell... 'p' 'q'

sumxy='sumxy'+'xn'*'yn'

diffxy='diffxy'+abs('xn'-'yn')

endfor

endfor

rxy=(('nocol'*'sumxy'-('sumx'*'sumy')))/(((('nocol'*'sumxx')-('sumx')^2))^0.5*(('nocol'*'sumyy'-('sumy')^2))^0.5)

print 'mat1$'x'mat2$''tab$'R'tab$''rxy:4''tab$'DifSum 'diffxy:0''newline$'

fileappend C:\Praat\Sounds\comp.res 'mat1$'x'mat2$''tab$''rxy:4''tab$''diffxy:0''newline$'

endproc

위의 스크립트를 필자가 녹음한 음성에 실행하면 각각의 파일에 대한 mat 파일이 생기고 상관계수와 절대차이합의 결과는 정보창에 다음과 같이 나타나고 이를 하드디스크에 comp.res란 파일로 저장해준다.

678_100x678_148 R 0.8485 DifSum 1560

678_100x678_183 R 0.8798 DifSum 1381

678_100x678_187 R 0.9499 DifSum 1000

678_100x678_236 R 0.8570 DifSum 1528

678_148x678_183 R 0.9689 DifSum 711

678_148x678_187 R 0.8765 DifSum 1363

678_148x678_236 R 0.9454 DifSum 936

678_183x678_187 R 0.8785 DifSum 1354

678_183x678_236 R 0.9329 DifSum 1005

678_187x678_236 R 0.8799 DifSum 1354

일부 음성은 매우 높은 상관계수를 보이지만 일부는 낮다. 이렇게 분석한 파일을 모델로 만들어 화자들끼리 상호 비교하려면 먼저 2개의 행렬을 불러와 각 시간점에서의 평균값을 구하여 모델로 저장해야 한다. 다음 스크립트는 678_100.mat와 678_148.mat를 불러와 평균값을 ave100_148.matmo에 저장한다.

<twomatmodel.sk>

Read from file... C:\Praat\Sounds\678_100.mat

mat1$=" 678_100"

Read from file... C:\Praat\Sounds\678_148.mat

mat2$=" 678_148"

matname$="ave100_148"

Create simple Matrix... mattemp 5 100 0

call matmodel

call drawsave

procedure matmodel

for p from 1 to 5

for q from 1 to 100

select Matrix 'mat1$'

xn1=Get value in cell... 'p' 'q'

select Matrix 'mat2$'

xn2=Get value in cell... 'p' 'q'

xnave=('xn1'+'xn2')/2

select Matrix mattemp

Set value... 'p' 'q' 'xnave'

endfor

endfor

endproc

procedure drawsave

select Matrix 'mat1$'

Black

Draw rows... 0 0 0 0 0 0

Remove

select Matrix 'mat2$'

Blue

Draw rows... 0 0 0 0 0 0

Remove

select Matrix mattemp

Red

Draw rows... 0 0 0 0 0 0

Write to short text file... C:\Praat\Sounds\'matname$'.matmo

Remove

endproc

그림창에는, 처리한 값들이 올바른지를 확인할 수 있도록 파랑선으로 나타난 두 개의 강도값 평균에 해당하는 빨강선으로 그림 4.4와 같이 나타난다.

그림 4.4 여과된 음성의 강도값 곡선 평균 구하기

이어서 각 모델을 불러와 화자끼리 상호 비교하거나 화자내에서 비교하는 것은 다음 스크립트로 가능하다. 여기서는 100_148.matmo와 다음 발성한 숫자음에 대한 강도 곡선 세 개의 행렬파일 (678_183.mat, 678_187.mat, 678_236.mat)을 불러와 상관계수와 절대차이합을 정보창에 보여주는 스크립트를 보여준다. 앞서 제시한 파일이름 자동생성 기능을 이용하면 보다 더 많은 파일을 비교하고 결과만 하드디스크에 저장할 수 있으나 독자들의 이해를 돕기 위해 간단한 스크립트만 보이기로 한다.

<dbmodelcordif.sk>

Read from file... C:\Praat\Sounds\100_148.matmo

Rename... 11

Read from file... C:\Praat\Sounds\678_183.mat

Rename... 12

Read from file... C:\Praat\Sounds\678_187.mat

Rename... 13

Read from file... C:\Praat\Sounds\678_236.mat

Rename... 14

clearinfo

call rdiff 11 12

call rdiff 11 13

call rdiff 11 14

procedure rdiff mat1$ mat2$

nocol=1000

select Matrix 'mat1$'

sumx=0

xn=0

for p from 1 to 5

for q from 1 to 100

xn=Get value in cell... 'p' 'q'

sumx='sumx'+'xn'

endfor

endfor

sumxx=0

xn=0

for p from 1 to 5

for q from 1 to 100

xn=Get value in cell... 'p' 'q'

sumxx='sumxx'+'xn'*'xn'

endfor

endfor

select Matrix 'mat2$'

sumy=0

yn=0

for p from 1 to 5

for q from 1 to 100

yn=Get value in cell... 'p' 'q'

sumy='sumy'+'yn'

endfor

endfor

sumyy=0

yn=0

for p from 1 to 5

for q from 1 to 100

yn=Get value in cell... 'p' 'q'

sumyy='sumyy'+'yn'*'yn'

endfor

endfor

sumxy=0

diffxy=0

xn=0

yn=0

for p from 1 to 5

for q from 1 to 100

select Matrix 'mat1$'

xn=Get value in cell... 'p' 'q'

select Matrix 'mat2$'

yn=Get value in cell... 'p' 'q'

sumxy='sumxy'+'xn'*'yn'

diffxy='diffxy'+abs('xn'-'yn')

endfor

endfor

rxy=(('nocol'*'sumxy'-('sumx'*'sumy')))/(((('nocol'*'sumxx')-('sumx')^2))^0.5*(('nocol'*'sumyy'-('sumy')^2))^0.5)

print 'mat1$'x'mat2$''tab$'R'tab$''rxy:4''tab$'DifSum 'diffxy:0''newline$'

endproc

이 스크립트를 필자가 발성한 숫자음에 대해 실행하면 정보창에는 다음과 같이 나타난다.

11x12 R 0.9975 DifSum 807

11x13 R 0.9966 DifSum 971

11x14 R 0.9959 DifSum 1061

4.6 악성종양환자와 정상인이 발성한 모음의 좁은대역 스펙트럼값의 상관계수와 절대차이합 비교

이 논문에서 사용한 스크립트는 먼저 음성파일을 객체창에 불러오고 이를 아래의 스크립트를 열어 처리한 결과를 보여준다. 전체적인 처리과정은 다음과 같다. 먼저 윈도우즈 웨이브파일로 되어 있는 각 피험자의 목소리를 객체창에 불러와 편집창으로 연 뒤 "Extract selection" 기능을 이용해 모음별로 따로 이름을 붙여 객체창에 올린다. 모음의 시작과 끝부분 그리고 묵음구간 등에서는 스펙트럼 정보가 불규칙적으로 변하기 때문에 이 부분을 제거하고 안정된 모음구간만을 추출하기 위해, 각 모음별로 강도값을 구한 뒤 강도값의 평균과 표준편차를 구하여 평균값에 표준편차값의 1/4을 더한 값을 문턱값으로 정한다. 이어서, 강도값의 파일의 처음부터 강도값이 문턱값을 넘는 지점에서 50 ms 지난 시작점(onset)을 구하고, 강도값이 상승하다가 하강하면서 또 다른 문턱값을 지나는 시간점에서 50 ms 이전의 지점을 끝점(offset)으로 지정하여 시작점과 끝점사이의 음성을 잘라내어 객체창에 올린다. 이 음성을 29 ms의 창으로 처리된 좁은대역 스펙트로그램을 구했다. 그리고 객체창에 올려진 음성의 처음 50 ms를 제외한 지점부터 10 ms마다 각각의 지점에 해당하는 좁은대역 스펙트럼값을 16개 구하고 이를 데시벨값의 행렬로 변환한 뒤 순서대로 객체창에 올렸다. 따라서, 분석할 구간은 적어도 2.1초 이상의 긴 모음이 되어야한다. 만약 그보다 짧으면 뒷부분의 분석값은 상관계수가 1이고 절대차이합이 0이 되므로 주의해야한다. 마지막으로 환자와 정상인이 발성한 긴 모음의 인접한 행렬값의 상관계수와 절대차이합을 구하여 비교한다.

<canceranalysis#.sk>

clearinfo

name$=selected$("Sound")

totdur=Get duration

print 'name$''newline$'

call trim

call process

call rdiff

call cleanall

procedure trim

select Sound 'name$'

To Intensity... 100 0

dbmean=Get mean... 0 0

dbsd=Get standard deviation... 0 0

dbmax=Get maximum... 0 0 Parabolic

dbmin=Get minimum... 0 0 Parabolic

dbcut='dbmean'+('dbsd'/4)

select Intensity 'name$'

timer=0

i=0

call db

while 'dbval'<'dbcut'

i='i'+1

timer='i'*0.005

call db

endwhile

onset='timer'+0.05

timer=0

j=0

call db

while 'dbval'<'dbcut'

j='j'+1

timer='totdur'-('j'*0.005)

call db

endwhile

offset='timer'-0.05

select Sound 'name$'

Edit

editor Sound 'name$'

Select... 'onset' 'offset'

Extract selection

endeditor

Rename... trimmed

endproc

procedure db

dbval=Get value at time... 'timer' Cubic

if dbval=undefined

dbval=0

endif

endproc

procedure process

select Sound trimmed

syldur=Get duration

To Spectrogram... 0.029 4000 0.005 10 Gaussian

if 'syldur'>0.1

for k from 1 to 16

timer='k'*0.01+0.05

select Spectrogram trimmed

To Spectrum (slice)... 'timer'

To Ltas (1-to-1)

To Matrix

Rename... 'k'

select Spectrum trimmed

Remove

select Ltas trimmed

Remove

endfor

endif

endproc

procedure cleanall

select Intensity 'name$'

Remove

select Sound trimmed

Remove

select Spectrogram trimmed

Remove

for n from 1 to 16

select Matrix 'n'

Remove

endfor

endproc

procedure rdiff

for m from 1 to 15

n='m'+1

mat1$="'m'"

mat2$="'n'"

nocol=400

select Matrix 'mat1$'

timer=1

sumx=0

while 'timer'<'nocol'+1

xn=Get value in cell... 1 'timer'

sumx='sumx'+'xn'

timer='timer'+1

endwhile

select Matrix 'mat2$'

timer=1

sumy=0

while 'timer'<'nocol'+1

yn=Get value in cell... 1 'timer'

sumy='sumy'+'yn'

timer='timer'+1

endwhile

select Matrix 'mat1$'

timer=1

sumxx=0

while 'timer'<'nocol'+1

xn=Get value in cell... 1 'timer'

sumxx='sumxx'+'xn'*'xn'

timer='timer'+1

endwhile

select Matrix 'mat2$'

timer=1

sumyy=0

while 'timer'<'nocol'+1

yn=Get value in cell... 1 'timer'

sumyy='sumyy'+'yn'*'yn'

timer='timer'+1

endwhile

timer=1

sumxy=0

diffxy=0

while 'timer'<'nocol'+1

select Matrix 'mat1$'

xn=Get value in cell... 1 'timer'

select Matrix 'mat2$'

yn=Get value in cell... 1 'timer'

sumxy='sumxy'+'xn'*'yn'

diffxy='diffxy'+abs('xn'-'yn')

timer='timer'+1

endwhile

rxy=(('nocol'*'sumxy'-('sumx'*'sumy')))/(((('nocol'*'sumxx')-('sumx')^2))^0.5*(('nocol'*'sumyy'-('sumy')^2))^0.5)

print 'rxy:3''tab$''diffxy:0''newline$'

endfor

endproc

정상의 목소리를 가진 필자의 발음 '아'에 대한 상관계수와 절대차이합은 다음과 같다.

aaa.aifc

0.968 953

0.963 959

0.965 994

0.964 977

0.965 988

0.965 982

0.976 907

0.975 834

0.977 842

0.976 823

0.977 810

0.969 972

0.961 1060

0.970 899

0.967 897

상관계수는 대체로 안정된 값들이고 절대차이합도 차이가 많지 않다. 이에 반해 음성장애환자의 목소리를 처리해보면 낮은 상관계수가 나온다.

4.7 SenSynPPC에 입력할 합성용 텍스트 파일 작성

포먼트음성합성용 소프트웨어인 SenSynPPC1.0에 사용할 합성용 파라미터 추출스크립트이다. 아직까지 그래픽으로 합성할 수 있는 윈도우즈용 파일이 없어서 여기에 제시한다. SynthWorks나 Speech Station의 합성용 파일을 분석하여 프라트를 이용해 작성하는 방안도 찾아보기 바란다. 음성합성은 매우 복잡한 파라미터의 값들을 조정해야 하기 때문에 번거롭기도 하지만, 분석된 값들이 원래의 음성과 일치한다면 당연히 합성된 음성이 원래의 음성과 같아야한다. 이런 점에서 분석에 의한 합성연구가 매우 중요하다. 물론, 심리음향학 실험과 같은 미세한 변수 조절을 위해서는 보다 더 자연음에 가까운 합성방법을 이용해야한다. 프라트의 변환(Manipulation)기능을 이용하면 피치, 진폭, 속도 등을 다양하게 조절할 수 있다. 다음 스크립트를 참고하여 합성기에 활용하길 바란다.

<synthsense#.sk>

call setting

call drawall

call analyze

call closer

procedure setting

name$=selected$("Sound")

soundName$="'name$'"+".con"

dur=Get duration

finish='dur'-0.04

sr=Get sample rate

zcr=round('sr'/100)

duround=round('dur'*1000)

Erase all

Viewport... 0.5 8 1 8

call createcon

i=1

timer=0

avon=0

avoff=0

f0=0

db=0

dbcut=0

fricvalue=0

endproc

procedure drawall

select Sound 'name$'

To Spectrogram... 0.005 4000 0.002 20 Gaussian

Rename... spectro

Paint... 0 0 0 0 100 yes 40 6 0 yes

select Sound 'name$'

To Formant (sl)... 0.005 5 5500 0.025 40

Speckle... 0 0 4000 40 no

Rename... sl

select Sound 'name$'

To Formant (burg)... 0.005 5 5500 0.025 40

Rename... burg

select Sound 'name$'

To Pitch (ac)... 0.005 75 3 yes 0.03 0.45 0.01 0.35 0.14 500

Rename... pitch

Draw... 0 0 0 500 no

gf0mean=Get mean... 0 0 Hertz

gf0stdev=Get standard deviation... 0 0 Hertz

gf0high='gf0mean'+3*'gf0stdev'

select Sound 'name$'

To Intensity... 100 0.005

mini=Get minimum... 0 0 Parabolic

mindb='mini'*0.795

!3db higher than the minimum 0.75*1.06=0.795

Rename... amp

Draw... 0 0 0 0 no

endproc

procedure analyze

while 'timer'<'finish' and 'avoff'<'finish'

timer='i'*0.005+0.04

timepoint=round('timer'*1000)

call pitcher

call intenser

if 'f0'>0

call vowel

else

call consonant

endif

call writedisk

i='i'+1

endwhile

endproc

procedure window

avrange=0.0075

avon='timer'-'avrange'

avoff='timer'+'avrange'

endproc

procedure pitcher

select Pitch pitch

call avsdf0

f0=Get value at time... timer Hertz Linear

call f00

if 'f0'>'f0high'

!or 'f0'<'f0low'

f0='avf0'

endif

if 'f0'>'gf0high'

f0='gf0mean'+randomInteger(2,0)

endif

call f00

f0=round('f0'*10)

endproc

procedure f00

if f0=undefined

f0=0

endif

endproc

procedure avsdf0

call window

avf0=Get mean... avon avoff Hertz

sdf0=Get standard deviation... avon avoff Hertz

if avf0=undefined

avf0=0

endif

if sdf0=undefined

sdf0=0

endif

f0high='avf0'+'sdf0'

! f0low='avf0'-'sdf0'

endproc

procedure intenser

select Intensity amp

call avsddb

db=Get value at time... timer Cubic

if 'db'>'dbhigh'

db='avdb'

endif

db=round('db'*0.75)

if 'db'>67

db=67

endif

ab='db'

endproc

procedure avsddb

call window

avdb=Get mean... avon avoff

sddb=Get standard deviation... avon avoff

dbhigh='avdb'+3*'sddb'

endproc

procedurevowel

select Formant burg

call formanter

call zerofrication

endproc

procedure zerofrication

a2f=0

a3f=0

a4f=0

a5f=0

a6f=0

ah=0

ab=0

af=0

endproc

procedure consonant

select Formant burg

call formanter

call zerocrossing

if 'db'<'mindb'

db=0

call zerofrication

endif

endproc

procedure zerocrossing

select Sound 'name$'

j=0

af=0

fricvalue=Get value at time... 0.5 Sinc70

while 'j'<'zcr' and 'timer'<'finish'

if 'fricvalue'>0

while 'fricvalue'>0 and 'j'<'zcr' and 'timer'<'finish'

j='j'+1

fricpoint=0.0001*'j' +'timer'-0.01

fricvalue=Get value at time... 0.5 Sinc70

endwhile

else

while 'fricvalue'<=0 and 'j'<'zcr' and 'timer'<'finish'

j='j'+1

fricpoint=0.0001*'j' +'timer'-0.01

fricvalue=Get value at time... 0.5 Sinc70

endwhile

endif

af='af'+1

endwhile

if 'af'<0 or 'af'=undefined

af=0

endif

ah=round('af')

if 'ah'>52

ah=52

endif

af=round(('db'+'ah')/2)+8

if 'af'>52

af=52

endif

endproc

procedure formanter

call window

call avsdfm

call formantrim

call bandwidther

endproc

procedure bandwidther

bw1sum=0

bw2sum=0

bw3sum=0

bw4sum=0

bw5sum=0

for q from 1 to 7

timerbw='timer'+q*0.005-0.015

bw1= Get bandwidth at time... 1 timerbw Hertz Linear

bw2= Get bandwidth at time... 2 timerbw Hertz Linear

bw3= Get bandwidth at time... 3 timerbw Hertz Linear

bw4= Get bandwidth at time... 4 timerbw Hertz Linear

bw5= Get bandwidth at time... 5 timerbw Hertz Linear

if bw1=undefined

bw1=0

endif

if bw2=undefined

bw2=0

endif

if bw3=undefined

bw3=0

endif

if bw4=undefined

bw4=0

endif

if bw5=undefined

bw5=0

endif

call matrix

endfor

for r from 1 to 7

bw1sum='bw1sum'+bw1'r'

bw2sum='bw2sum'+bw2'r'

bw3sum='bw3sum'+bw3'r'

bw4sum='bw4sum'+bw4'r'

bw5sum='bw5sum'+bw5'r'

endfor

b1='bw1sum'/7

b2='bw2sum'/7

b3='bw3sum'/7

b4='bw4sum'/7

b5='bw5sum'/7

a2f=round(52-('b2'/40))

a3f=round(52-('b3'/40))

a4f=round(52-('b4'/40))

a5f=round(52-('b5'/40))

a6f=0

if 'a2f'<0 ora2f=undefined

a2f=0

endif

if 'a3f'<0 ora3f=undefined

a3f=0

endif

if 'a4f'<0 ora4f=undefined

a4f=0

endif

if 'a5f'<0 ora5f=undefined

a5f=0

endif

b1=round('b1')

b2=round('b2')

b3=round('b3')

b4=round('b4')

b5=330

b6=400

endproc

procedure matrix

bw1'q'='bw1'

bw2'q'='bw2'

bw3'q'='bw3'

bw4'q'='bw4'

bw5'q'='bw5'

endproc

procedure avsdfm

avfm1=Get mean... 1 avon avoff Hertz

sdfm1=Get standard deviation... 1 avon avoff Hertz

avfm2=Get mean... 2 avon avoff Hertz

sdfm2=Get standard deviation... 2 avon avoff Hertz

avfm3=Get mean... 3 avon avoff Hertz

sdfm3=Get standard deviation... 3 avon avoff Hertz

avfm4=Get mean... 4 avon avoff Hertz

sdfm4=Get standard deviation... 4 avon avoff Hertz

if avfm1=undefined

avfm1=500

endif

if avfm2=undefined

avfm2=1500

endif

if avfm3=undefined

avfm3=2500

endif

if avfm4=undefined

avfm4=3300

endif

if sdfm1=undefined

sdfm1=500

endif

if sdfm2=undefined

sdfm2=1500

endif

if sdfm3=undefined

sdfm3=2500

endif

if sdfm4=undefined

sdfm4=3300

endif

fm1high='avfm1'+'sdfm1'

fm1low='avfm1'-'sdfm1'

fm2high='avfm2'+'sdfm2'

fm2low='avfm2'-'sdfm2'

fm3high='avfm3'+'sdfm3'

fm3low='avfm3'-'sdfm3'

fm4high='avfm4'+'sdfm4'

fm4low='avfm4'-'sdfm4'

endproc

procedure formantrim

fm1=Get value at time... 1 timer Hertz Linear

fm2=Get value at time... 2 timer Hertz Linear

fm3=Get value at time... 3 timer Hertz Linear

fm4=Get value at time... 4 timer Hertz Linear

if fm1=undefined

fm1=500

endif

if fm2=undefined

fm2=1500

endif

if fm3=undefined

fm3=2500

endif

if fm4=undefined

fm4=3300

endif

if 'fm1'>'fm1high' or 'fm1'<'fm1low'

fm1='avfm1'

endif

if 'fm2'>'fm2high' or 'fm2'<'fm2low'

fm2='avfm2'

endif

if 'fm3'>'fm3high' or 'fm3'<'fm3low'

fm3='avfm3'

endif

if 'fm4'>'fm4high' or 'fm4'<'fm4low'

fm4='avfm4'

endif

if ('fm4'+400)>3900

fm4=3900

endif

if 'fm3'+350>'fm4'

fm3='fm3'-350

endif

if ('fm2'+330)>'fm3'

fm2='fm2'-330

endif

if ('fm1'+300)>'fm2'

fm1='fm1'-300

endif

if 'fm1'<250

fm1=250

endif

if 'fm2'<800

fm2=800

endif

if 'fm3'<1500

fm3=1500

endif

if 'fm4'<2500

fm4=2500

endif

if 'fm1'>800

fm1=800

endif

if 'fm2'>2500

fm2=2500

endif

if 'fm3'>3300

fm3=3300

endif

if 'fm4'>3600

fm4=3600

endif

fm1=round('fm1')

fm2=round('fm2')

fm3=round('fm3')

fm4=round('fm4')

fm5=4400

fm6=4990

endproc

procedure closer

select Pitch pitch

Remove

select Spectrogram spectro

Remove

select Intensity amp

Remove

select Formant sl

Remove

select Formant burg

Remove

Viewport... 9 9.001 9.001 9.002

finalline='timepoint'+5

fileappend C:\Praat\'soundName$' 'finalline''tab$'0'tab$'0'tab$'0'tab$'0'tab$''fm1''tab$''b1''tab$''fm2''tab$''b2''tab$''fm3''tab$''b3''tab$''fm4''tab$''b4''tab$'0'tab$'0'tab$'0'tab$'0'tab$'0'tab$'0'newline$'

endproc

procedure writedisk

fileappend C:\Praat\'soundName$' 'timepoint''tab$''f0''tab$''db''tab$''ah''tab$''af''tab$''fm1''tab$''b1''tab$''fm2''tab$''b2''tab$''fm3''tab$''b3''tab$''fm4''tab$''b4''tab$''a2f''tab$''a3f''tab$''a4f''tab$''a5f''tab$''a6f''tab$''ab''newline$'

endproc

procedure createcon

fileappend C:\Praat\'soundName$' Synthesis specification for file: 'soundName$''newline$'

fileappend C:\Praat\'soundName$' 'newline$'

fileappend C:\Praat\'soundName$' KLSYN88 Version 1.0 D.H. Klatt 1-Jan-01'newline$'

fileappend C:\Praat\'soundName$' 'newline$'

fileappend C:\Praat\'soundName$' 'newline$'

fileappend C:\Praat\'soundName$' Total number of waveform samples = 10000'newline$'

fileappend C:\Praat\'soundName$' 'newline$'

fileappend C:\Praat\'soundName$' 'newline$'

fileappend C:\Praat\'soundName$' CURRENT CONFIGURATION:'newline$'

fileappend C:\Praat\'soundName$' 60 parameters'newline$'

fileappend C:\Praat\'soundName$' 'newline$'

fileappend C:\Praat\'soundName$' SYM V/C MIN VAL MAX DESCRIPTION'newline$'

fileappend C:\Praat\'soundName$' ---------------------------------------------------------------------------'newline$'

fileappend C:\Praat\'soundName$' DU C 30 'duround' 5000 Duration of the utterance, in msec'newline$'

fileappend C:\Praat\'soundName$' UI C 1 5 20 Update interval for parameter reset, in msec'newline$'

fileappend C:\Praat\'soundName$' SR C 5000 20000 20000 Output sampling rate, in samples/sec'newline$'

fileappend C:\Praat\'soundName$' NF C 1 6 6 Number of formants in cascade branch'newline$'

fileappend C:\Praat\'soundName$' SS C 1 2 3 Source switch (1=impulse, 2=natural, 3=LF model)'newline$'

fileappend C:\Praat\'soundName$' RS C 1 8 8191 Random seed (initial value of random # generator)'newline$'

fileappend C:\Praat\'soundName$' SB C 0 1 1 Same noise burst, reset RS if AF=AH=0, 0=no,1=yes'newline$'

fileappend C:\Praat\'soundName$' CP C 0 0 1 0=Cascade, 1=Parallel tract excitation by AV'newline$'

fileappend C:\Praat\'soundName$' OS C 0 0 20 Output selector (0=normal,1=voicing source,...)'newline$'

fileappend C:\Praat\'soundName$' GV C 0 60 80 Overall gain scale factor for AV, in dB'newline$'

fileappend C:\Praat\'soundName$' GH C 0 60 80 Overall gain scale factor for AH, in dB'newline$'

fileappend C:\Praat\'soundName$' GF C 0 60 80 Overall gain scale factor for AF, in dB'newline$'

fileappend C:\Praat\'soundName$' F0 V 0 0 5000 Fundamental frequency, in tenths of a Hz'newline$'

fileappend C:\Praat\'soundName$' AV V 0 45 80 Amplitude of voicing, in dB'newline$'

fileappend C:\Praat\'soundName$' OQ v 10 50 99 Open quotient (voicing open-time/period), in %'newline$'

fileappend C:\Praat\'soundName$' SQ v 100 200 500 Speed quotient (rise/fall time, LF model), in %'newline$'

fileappend C:\Praat\'soundName$' TL v 0 0 41 Extra tilt of voicing spectrum, dB down @ 3 kHz'newline$'

fileappend C:\Praat\'soundName$' FL v 0 0 100 Flutter (random fluct in f0), in % of maximum'newline$'

fileappend C:\Praat\'soundName$' DI v 0 0 100 Diplophonia (alt periods closer), in % of max'newline$'

fileappend C:\Praat\'soundName$' AH V 0 0 80 Amplitude of aspiration, in dB'newline$'

fileappend C:\Praat\'soundName$' AF V 0 0 80 Amplitude of frication, in dB'newline$'

fileappend C:\Praat\'soundName$' F1 V 180 500 1300 Frequency of 1st formant, in Hz'newline$'

fileappend C:\Praat\'soundName$' B1 V 30 80 1000 Bandwidth of 1st formant, in Hz'newline$'

fileappend C:\Praat\'soundName$' DF1 v 0 0 100 Change in F1 during open portion of period, in Hz'newline$'

fileappend C:\Praat\'soundName$' DB1 v 0 0 400 Change in B1 during open portion of period, in Hz'newline$'

fileappend C:\Praat\'soundName$' F2 V 550 1500 3000 Frequency of 2nd formant, in Hz'newline$'

fileappend C:\Praat\'soundName$' B2 V 40 120 1000 Bandwidth of 2nd formant, in Hz'newline$'

fileappend C:\Praat\'soundName$' F3 V 1200 2500 4800 Frequency of 3rd formant, in Hz'newline$'

fileappend C:\Praat\'soundName$' B3 V 60 140 1000 Bandwidth of 3rd formant, in Hz'newline$'

fileappend C:\Praat\'soundName$' F4 V 2400 3500 4990 Frequency of 4th formant, in Hz'newline$'

fileappend C:\Praat\'soundName$' B4 V 100 160 1000 Bandwidth of 4th formant, in Hz'newline$'

fileappend C:\Praat\'soundName$' F5 v 3000 4300 4990 Frequency of 5th formant, in Hz'newline$'

fileappend C:\Praat\'soundName$' B5 v 100 180 1500 Bandwidth of 5th formant, in Hz'newline$'

fileappend C:\Praat\'soundName$' F6 v 3000 4800 4990 Frequency of 6th formant (applies if NF=6), in Hz'newline$'

fileappend C:\Praat\'soundName$' B6 v 100 200 4000 Bandwidth of 6th formant (applies if NF=6), in Hz'newline$'

fileappend C:\Praat\'soundName$' FNP v 180 280 500 Frequency of nasal pole, in Hz'newline$'

fileappend C:\Praat\'soundName$' BNP v 40 90 1000 Bandwidth of nasal pole, in Hz'newline$'

fileappend C:\Praat\'soundName$' FNZ v 180 280 800 Frequency of nasal zero, in Hz'newline$'

fileappend C:\Praat\'soundName$' BNZ v 40 90 1000 Bandwidth of nasal zero, in Hz'newline$'

fileappend C:\Praat\'soundName$' FTP v 300 2150 3000 Frequency of tracheal pole, in Hz'newline$'

fileappend C:\Praat\'soundName$' BTP v 40 180 1000 Bandwidth of tracheal pole, in Hz'newline$'

fileappend C:\Praat\'soundName$' FTZ v 300 2150 3000 Frequency of tracheal zero, in Hz'newline$'

fileappend C:\Praat\'soundName$' BTZ v 40 180 2000 Bandwidth of tracheal zero, in Hz'newline$'

fileappend C:\Praat\'soundName$' A2F V 0 0 80 Amp of fric-excited parallel 2nd formant, in dB'newline$'

fileappend C:\Praat\'soundName$' A3F V 0 0 80 Amp of fric-excited parallel 3rd formant, in dB'newline$'

fileappend C:\Praat\'soundName$' A4F V 0 0 80 Amp of fric-excited parallel 4th formant, in dB'newline$'

fileappend C:\Praat\'soundName$' A5F V 0 0 80 Amp of fric-excited parallel 5th formant, in dB'newline$'

fileappend C:\Praat\'soundName$' A6F V 0 0 80 Amp of fric-excited parallel 6th formant, in dB'newline$'

fileappend C:\Praat\'soundName$' AB V 0 0 80 Amp of fric-excited parallel bypass path, in dB'newline$'

fileappend C:\Praat\'soundName$' B2F v 40 250 1000 Bw of fric-excited parallel 2nd formant, in Hz'newline$'

fileappend C:\Praat\'soundName$' B3F v 60 300 1000 Bw of fric-excited parallel 3rd formant, in Hz'newline$'

fileappend C:\Praat\'soundName$' B4F v 100 320 1000 Bw of fric-excited parallel 4th formant, in Hz'newline$'

fileappend C:\Praat\'soundName$' B5F v 100 360 1500 Bw of fric-excited parallel 5th formant, in Hz'newline$'

fileappend C:\Praat\'soundName$' B6F v 100 1500 4000 Bw of fric-excited parallel 6th formant, in Hz'newline$'

fileappend C:\Praat\'soundName$' ANV v 0 0 80 Amp of voice-excited parallel nasal form., in dB'newline$'

fileappend C:\Praat\'soundName$' A1V v 0 60 80 Amp of voice-excited parallel 1st formant, in dB'newline$'

fileappend C:\Praat\'soundName$' A2V v 0 60 80 Amp of voice-excited parallel 2nd formant, in dB'newline$'

fileappend C:\Praat\'soundName$' A3V v 0 60 80 Amp of voice-excited parallel 3rd formant, in dB'newline$'

fileappend C:\Praat\'soundName$' A4V v 0 60 80 Amp of voice-excited parallel 4th formant, in dB'newline$'

fileappend C:\Praat\'soundName$' ATV v 0 0 80 Amp of voice-excited par tracheal formant, in dB'newline$'

fileappend C:\Praat\'soundName$' 'newline$'

fileappend C:\Praat\'soundName$' 'newline$'

fileappend C:\Praat\'soundName$' varied Parameters:'newline$'

fileappend C:\Praat\'soundName$' time F0 AV AH AF F1 B1 F2 B2 F3 B3 F4 B4 A2F A3F A4F A5F A6F AB 'newline$'

endproc

위의 스크립트로 숫자음 "6"을 분석하면 다음과 같은 합성용 텍스트 파일이 생성한다. 0.5초의 짧은 발음이지만, 5밀리초 마다 분석한 97개 지점의 파라미터들을 구하느라 매우 긴 파일이 되었다. 이 파일을 매킨토시의 SenSynPPC를 열어 File기본메뉴의 Import하위메뉴를 클릭 하여 불러들인 뒤 스페이스 키를 누르면 원래의 숫자음과 거의 비슷한 발음을 들을 수 있다. 매킨토시의 SenSynPPC로 옮길 때는 윈도우즈의 Carriage Return키라는 특수문자가 있는 텍스트 파일을 그대로 읽어 들이면 프로그램이 중단되고 컴퓨터가 꼼짝하지 않는다. 따라서, 매킨토시에서 열 때는 반드시 마이크로소프트 워드에서 텍스트파일로 저장하고 매킨토시의 워드에서 연 뒤 다시 한번 텍스트파일로 저장하여 열어야만 된다. 왜냐하면, 매킨토시에서는 텍스트의 줄 끝에 Carriage Return키라는 특수문자 대신에 Return키를 사용하기 때문이다.

Synthesis specification for file: 6.con

KLSYN88 Version 1.0 D.H. Klatt 1-Jan-01

Total number of waveform samples = 10000

CURRENT CONFIGURATION:

60 parameters

SYM V/C MIN VAL MAX DESCRIPTION

------------------------------------------------------------------

DU C 30 505 5000 Duration of the utterance, in msec

UI C 1 5 20 Update interval for parameter reset, in msec

SR C 5000 20000 20000 Output sampling rate, in samples/sec

NF C 1 6 6 Number of formants in cascade branch

SS C 1 2 3 Source switch (1=impulse, 2=natural, 3=LF model)

RS C 1 8 8191 Random seed (initial value of random # generator)

SB C 0 1 1 Same noise burst, reset RS if AF=AH=0, 0=no,1=yes

CP C 0 0 1 0=Cascade, 1=Parallel tract excitation by AV

OS C 0 0 20 Output selector (0=normal,1=voicing source,...)

GV C 0 60 80 Overall gain scale factor for AV, in dB

GH C 0 60 80 Overall gain scale factor for AH, in dB

GF C 0 60 80 Overall gain scale factor for AF, in dB

F0 V 0 0 5000 Fundamental frequency, in tenths of a Hz

AV V 0 45 80 Amplitude of voicing, in dB

OQ v 10 50 99 Open quotient (voicing open-time/period), in %

SQ v 100 200 500 Speed quotient (rise/fall time, LF model), in %

TL v 0 0 41 Extra tilt of voicing spectrum, dB down @ 3 kHz

FL v 0 0 100 Flutter (random fluct in f0), in % of maximum

DI v 0 0 100 Diplophonia (alt periods closer), in % of max

AH V 0 0 80 Amplitude of aspiration, in dB

AF V 0 0 80 Amplitude of frication, in dB

F1 V 180 500 1300 Frequency of 1st formant, in Hz

B1 V 30 80 1000 Bandwidth of 1st formant, in Hz

DF1 v 0 0 100 Change in F1 during open portion of period, in Hz

DB1 v 0 0 400 Change in B1 during open portion of period, in Hz

F2 V 550 1500 3000 Frequency of 2nd formant, in Hz

B2 V 40 120 1000 Bandwidth of 2nd formant, in Hz

F3 V 1200 2500 4800 Frequency of 3rd formant, in Hz

B3 V 60 140 1000 Bandwidth of 3rd formant, in Hz

F4 V 2400 3500 4990 Frequency of 4th formant, in Hz

B4 V 100 160 1000 Bandwidth of 4th formant, in Hz

F5 v 3000 4300 4990 Frequency of 5th formant, in Hz

B5 v 100 180 1500 Bandwidth of 5th formant, in Hz

F6 v 3000 4800 4990 Frequency of 6th formant (applies if NF=6), in Hz

B6 v 100 200 4000 Bandwidth of 6th formant (applies if NF=6), in Hz

FNP v 180 280 500 Frequency of nasal pole, in Hz

BNP v 40 90 1000 Bandwidth of nasal pole, in Hz

FNZ v 180 280 800 Frequency of nasal zero, in Hz

BNZ v 40 90 1000 Bandwidth of nasal zero, in Hz

FTP v 300 2150 3000 Frequency of tracheal pole, in Hz

BTP v 40 180 1000 Bandwidth of tracheal pole, in Hz

FTZ v 300 2150 3000 Frequency of tracheal zero, in Hz

BTZ v 40 180 2000 Bandwidth of tracheal zero, in Hz

A2F V 0 0 80 Amp of fric-excited parallel 2nd formant, in dB

A3F V 0 0 80 Amp of fric-excited parallel 3rd formant, in dB

A4F V 0 0 80 Amp of fric-excited parallel 4th formant, in dB

A5F V 0 0 80 Amp of fric-excited parallel 5th formant, in dB

A6F V 0 0 80 Amp of fric-excited parallel 6th formant, in dB

AB V 0 0 80 Amp of fric-excited parallel bypass path, in dB

B2F v 40 250 1000 Bw of fric-excited parallel 2nd formant, in Hz

B3F v 60 300 1000 Bw of fric-excited parallel 3rd formant, in Hz

B4F v 100 320 1000 Bw of fric-excited parallel 4th formant, in Hz

B5F v 100 360 1500 Bw of fric-excited parallel 5th formant, in Hz

B6F v 100 1500 4000 Bw of fric-excited parallel 6th formant, in Hz

ANV v 0 0 80 Amp of voice-excited parallel nasal form., in dB

A1V v 0 60 80 Amp of voice-excited parallel 1st formant, in dB

A2V v 0 60 80 Amp of voice-excited parallel 2nd formant, in dB

A3V v 0 60 80 Amp of voice-excited parallel 3rd formant, in dB

A4V v 0 60 80 Amp of voice-excited parallel 4th formant, in dB

ATV v 0 0 80 Amp of voice-excited par tracheal formant, in dB

varied Parameters:

time F0 AV AH AF F1 B1 F2 B2 F3 B3 F4 B4 A2F A3F A4F A5F A6F AB

45 0 27 1 22 250 436 2500 212 3300 829 3600 549 47 31 38 42 0 27

50 0 32 1 25 264 395 2466 194 3197 776 3600 661 47 33 35 42 0 32

55 0 37 1 27 269 153 2322 188 3118 652 3600 803 47 36 32 41 0 37

60 1519 40 0 0 275 67 2282 183 3096 517 3600 944 0 0 0 0 0 0

65 1519 42 0 0 285 53 2261 173 3102 532 3600 982 0 0 0 0 0 0

70 1515 44 0 0 299 47 2236 155 3181 565 3600 1064 0 0 0 0 0 0

75 1497 45 0 0 299 44 2220 144 3300 587 3600 983 0 0 0 0 0 0

80 1433 46 0 0 294 42 2209 139 3300 594 3600 983 0 0 0 0 0 0

85 1377 47 0 0 282 41 2188 137 3002 595 3480 1005 0 0 0 0 0 0

90 1331 47 0 0 274 40 2193 136 3300 586 3600 987 0 0 0 0 0 0

95 1303 48 0 0 270 39 2193 142 3209 577 3600 962 0 0 0 0 0 0

100 1302 48 0 0 270 38 2196 136 3100 505 3600 1039 0 0 0 0 0 0

105 1302 48 0 0 270 38 2212 134 3092 483 3600 1064 0 0 0 0 0 0

110 1300 48 0 0 269 38 2229 142 3095 478 3600 1065 0 0 0 0 0 0

115 1295 49 0 0 268 38 2257 156 3134 486 3600 1060 0 0 0 0 0 0

120 1289 49 0 0 267 39 2312 170 3220 500 3600 1045 0 0 0 0 0 0

125 1285 49 0 0 266 40 2315 182 3232 523 3600 1039 0 0 0 0 0 0

130 1283 49 0 0 266 40 2307 184 3227 544 3600 1036 0 0 0 0 0 0

135 1282 49 0 0 266 40 2316 186 3204 546 3600 1028 0 0 0 0 0 0

140 1284 49 0 0 267 40 2332 188 3196 540 3600 1030 0 0 0 0 0 0

145 1287 49 0 0 269 39 2333 184 3192 520 3600 1038 0 0 0 0 0 0

150 1293 50 0 0 269 39 2326 181 3194 495 3600 1048 0 0 0 0 0 0

155 1302 50 0 0 271 39 2304 177 3175 467 3600 1056 0 0 0 0 0 0

160 1315 50 0 0 274 38 2287 167 3083 434 3600 1074 0 0 0 0 0 0

165 1329 51 0 0 276 38 2267 162 3007 403 3600 1111 0 0 0 0 0 0

170 1341 51 0 0 279 38 2261 163 2945 364 3600 1153 0 0 0 0 0 0

175 1361 51 0 0 283 38 2277 165 2890 325 3600 1181 0 0 0 0 0 0

180 1376 52 0 0 285 37 2298 161 2866 298 3600 1202 0 0 0 0 0 0

185 1388 53 0 0 288 36 2303 151 2812 278 3600 1219 0 0 0 0 0 0

190 1402 53 0 0 292 35 2300 151 2742 255 3600 1240 0 0 0 0 0 0

195 1410 54 0 0 294 34 2267 155 2696 230 3600 1253 0 0 0 0 0 0

200 1415 55 0 0 294 33 2229 153 2649 207 3600 1250 0 0 0 0 0 0

205 1424 55 0 0 296 31 2199 147 2568 191 3600 1251 0 0 0 0 0 0

210 1436 55 0 0 300 30 2147 141 2491 185 3600 1271 0 0 0 0 0 0

215 1447 56 0 0 301 30 2090 145 2466 184 3600 1296 0 0 0 0 0 0

220 1453 56 0 0 303 31 2045 149 2439 183 3600 1321 0 0 0 0 0 0

225 1457 57 0 0 305 32 1975 143 2438 191 3600 1355 0 0 0 0 0 0

230 1462 57 0 0 306 34 1927 135 2435 203 3600 1385 0 0 0 0 0 0

235 1468 57 0 0 308 36 1832 127 2431 213 3600 1419 0 0 0 0 0 0

240 1472 57 0 0 311 38 1687 118 2435 222 3600 1457 0 0 0 0 0 0

245 1473 57 0 0 314 42 1571 110 2474 227 3600 1499 0 0 0 0 0 0

250 1473 57 0 0 316 46 1500 101 2519 231 3600 1518 0 0 0 0 0 0

255 1475 57 0 0 321 50 1452 92 2550 235 3600 1534 0 0 0 0 0 0

260 1476 56 0 0 331 54 1414 83 2586 242 3600 1561 0 0 0 0 0 0

265 1472 56 0 0 340 58 1377 78 2611 250 3600 1580 0 0 0 0 0 0

270 1466 56 0 0 347 61 1321 77 2611 257 3600 1576 0 0 0 0 0 0

275 1462 56 0 0 357 63 1284 78 2614 265 3600 1565 0 0 0 0 0 0

280 1460 55 0 0 367 63 1239 75 2624 269 3600 1538 0 0 0 0 0 0

285 1458 55 0 0 372 61 1197 71 2632 274 3600 1542 0 0 0 0 0 0

290 1454 55 0 0 377 59 1161 72 2641 278 3600 1550 0 0 0 0 0 0

295 1445 56 0 0 387 56 1143 73 2662 273 3600 1515 0 0 0 0 0 0

300 1437 56 0 0 392 53 1105 70 2680 264 3600 1491 0 0 0 0 0 0

305 1433 56 0 0 393 50 1080 66 2689 258 3600 1491 0 0 0 0 0 0

310 1429 56 0 0 395 47 1034 63 2686 257 3600 1489 0 0 0 0 0 0

315 1423 56 0 0 397 45 989 61 2679 257 3600 1482 0 0 0 0 0 0

320 1417 57 0 0 397 43 977 58 2680 260 3600 1459 0 0 0 0 0 0

325 1410 57 0 0 397 41 973 54 2689 269 3600 1437 0 0 0 0 0 0

330 1399 57 0 0 396 38 965 51 2710 277 3600 1424 0 0 0 0 0 0

335 1385 57 0 0 394 37 952 50 2744 284 3600 1412 0 0 0 0 0 0

340 1370 57 0 0 394 36 946 52 2756 293 3600 1408 0 0 0 0 0 0

345 1353 56 0 0 391 36 942 55 2772 293 3600 1444 0 0 0 0 0 0

350 1336 56 0 0 385 37 938 58 2795 290 3600 1275 0 0 0 0 0 0

355 1318 56 0 0 383 40 932 62 2805 294 3600 1119 0 0 0 0 0 0

360 1298 56 0 0 378 44 918 65 2814 291 3600 960 0 0 0 0 0 0

365 1276 55 0 0 366 48 900 71 2827 284 3600 803 0 0 0 0 0 0

370 1253 54 0 0 357 68 891 108 2835 296 3600 650 0 0 0 0 0 0

375 1231 54 0 0 348 88 880 398 2841 346 3600 509 0 0 0 0 0 0

380 1213 53 0 0 340 98 855 682 2846 391 3600 333 0 0 0 0 0 0

385 1206 51 0 0 342 105 822 825 2826 450 3600 335 0 0 0 0 0 0

390 1209 49 0 0 359 137 822 892 2721 490 3600 331 0 0 0 0 0 0

395 1211 46 0 0 250 228 800 960 2740 482 3600 474 0 0 0 0 0 0

400 1209 42 0 0 381 321 1495 1052 2828 727 3600 463 0 0 0 0 0 0

405 0 37 1 27 361 411 2175 1049 2892 835 3600 462 26 31 40 30 0 37

410 0 30 1 24 351 498 2131 788 3019 783 3600 528 32 32 39 36 0 30

415 0 23 1 20 800 663 2500 554 3300 1107 3600 497 38 24 40 43 0 23

420 0 15 1 16 800 741 2500 460 3300 1348 3600 497 40 18 40 49 0 15

425 0 9 1 13 800 819 2500 473 3300 1835 3600 504 40 6 39 45 0 9

430 0 6 1 12 800 857 2500 433 3300 1863 3600 493 41 5 40 45 0 6

435 0 4 1 11 800 913 2410 361 3300 1620 3600 686 43 12 35 45 0 4

440 0 3 1 10 800 999 2373 485 3226 1493 3600 671 40 15 35 40 0 3

445 0 4 1 11 800 1106 2500 789 3300 1503 3600 565 32 14 38 40 0 4

450 0 4 1 11 800 1087 2500 814 3300 1308 3600 555 32 19 38 40 0 4

455 0 3 1 10 800 1088 2500 902 3300 1019 3600 545 29 27 38 40 0 3

460 0 1 1 9 361 1107 2441 951 2929 613 3600 498 28 37 40 47 0 1

465 0 0 0 0 361 1107 2441 951 2929 613 3600 498 0 0 0 0 0 0

참고문헌

양병곤. (2000). "Praat에 의한 억양 분석 방법". 동의논집 32, pp. 29-39.

양병곤. (2000). "Praat에 의한 숫자음 음향적 분석법", 음성과학 제 7권 6호, pp. 127-137.

양병곤. (2001). "남성의 숫자음 발성에 나타난 화자변이". 음성과학 제 8권 3호, pp. 93-104.

양병곤. (2002). "좁은대역 스펙트럼의 차이값과 상관계수에 의한 화자확인 연구" 음성과학

제 9권 3호, pp. 3-16.

양병곤. (2003). "대역별로 여과한 음성 강도의 차이값과 상관계수에 의한 화자확인 연구",

음성과학 제 10권 2호, pp. 249-258.

양병곤. (2003) "악성종양환자와 정상인이 발성한 모음의 좁은대역 스펙트럼값의 상관계수와

절대차이합 비교. 음성과학 10권 4호. pp. 189-200.

Boersma, P. (1993). "Accurate short-term analysis of the fundamental

frequency and the harmonics-to-noise ratio of a sampled sound",

Proceedings of the Institute of Phonetic Sciences of the University

of Amsterdam 17: 97-110.

저자 소개

양 병곤 (현 동의대학교 영어영문학과 교수)

부산대학교 영어영문학과 문학사, 문학석사

미국 텍사스오스틴 주립대학 음성학박사

박사학위 논문: Development of Vowel Normalization Procedures:

English and Korean

저서·역서

Development of vowel normalization procedures: English and

Korean. 1991. 서울: 한신문화사 <전자파일>

한국어 이중모음의 음향학적 연구, 1993. 부산: 진영문화사

<전자파일>

음성학 입문, 1993. 부산: 진영문화사

음성언어의 이해(공역), 1995. 서울: 한신문화사

실험음성학 논문집 I, 1998. 부산: 진영문화사

Signalyze를 이용한 음성 분석법, 1998. 부산: 진영문화사<전자파일>

음성학과 음운론, 공역자: 구희산, 고도흥, 김기호, 안상철, 1998.

서울: 한신문화사

음성과학, 공역자: 김기호, 고도흥, 구희산. 2000. 서울: 한국문화사

음성과학용어번역사전. 구희산 외 공편. 2001. 서울:한국문화사.

음성 및 언어 분석기기 활용법. 고도흥 외 공편. 2001. 서울:

한국문화사.

프라트를 이용한 음성 분석의 이론과 실제, 2003. 부산: 진영출판사.

학술논문 전자파일

Http://www.deu.ac.kr/~bgyang/kpapers.htm

이 책 원문 전자파일

Http://www.deu.ac.kr/~bgyang/praat/praatscript.pdf







Praat Script를 이용한 음성분석과 변형

=========================================

발행인 양 병곤

인 쇄 만수출판사(출판등록 제카11-17호)

Tel: (051) 513-4042, 2662

E-mail: mansu4042@korea.com

발행일 2004년 2월 19일

책 값 11,000원

=========================================

연락처 614-714

부산광역시 부산진구 엄광로 995

동의대학교 영어영문학과

양 병 곤 교수

Tel: (051) 890-1227

HP: 018-577-7636

Fax: (051) 890-1222

Http://www.deu.ac.kr/~bgyang

E-mail: bgyang@deu.ac.kr

Copyright Ⱓ 2004 양병곤

※이 책의 내용을 저자의 허락 없이 판매용으로 출판하는 것은 법으로 금지되어 있습니다. 단, 개인의 학술 연구용이나 강의용으로 인쇄하여 사용하실 수 있습니다.