# 기타 조율기(Python)

GTK+와 지스트리머를 간단한 그놈용 기타 조율기 프로그램을 만들어보겠습니다. 인터페이스 디자이너 사용법을 나타냅니다.
그놈 문서 프로젝트
gnome-doc-list@gnome.org
Johannes Schmid
jhs@gnome.org
Marta Maria Casetti
mmcasetti@gmail.com 2013
Marta Maria Casetti
mmcasetti@gmail.com 2013
조성호
shcho@gnome.org 2017-2019.

# 기타 조율기

      이 지침서에서, 기타 조율에 사용할 수 있는 음색을 재생하는 프로그램을 만들겠습니다. 다음 내용을 배워나갑니다:

        안주타에서 기본 프로젝트 설정
        안주타 사용자 인터페이스 디자이너에서 간단한 GUI 만들기
        지스트리머를 사용하여 소리 재생하기

      이 지침을 따라갈 수 있으려면 다음이 필요합니다:

        안주타 IDE 설치 사본
        파이썬 프로그래밍 언어 기본 지식

# 안주타에서 프로젝트 만들기

코딩을 시작하기 전에 안주타에서 새 프로젝트를 설정해야합니다. 이 프로그램은 빌드에 필요한 모든 파일을 만들고 그 다음 코드를 실행합니다. 또한 이 모든 상태를 유지 관리하는데 쓸만합니다.

안주타를 시작하고 파일새로 만들기프로젝트 를 눌러 프로젝트 마법사를 여십시오.

파이썬 탭에서 PyGTK (automake)를 선택하고 계속을 누르신 다음 몇가지 페이지에서 세부 내용을 채워나가십시오. 프로젝트 이름과 디렉터리 이름을 guitar-tuner로 정하십시오.

적용을 누르면 프로젝트를 만들어줍니다. 프로젝트나 파일탭에서 src/guitar_tuner.py 파일을 여십시오. 다음 줄로 시작하는 코드가 나타납니다:

from gi.repository import Gtk, GdkPixbuf, Gdk import os, sys

# 첫 코드 실행

이 파일의 대부분의 코드는 코드 서식입니다. 사용자 인터페이스 설명 파일에서 (빈)창을 불러오고 보여줍니다. 더 자세한 내용은 아래에 있습니다. 기본을 알고 계신다면 이 부분은 건너 뛰십시오:

상단의 `import` 줄은 파이썬에 사용자 인터페이스와 시스템 라이브러리가 필요함을 알리는 내용이 들어갑니다.

프로그램의 주 클래스가 될 클래스를 선언합니다. `__init__` 메서드에서는 GtkBuilder 파일(src/guitar-tuner.ui)에서 메인 창을 불러오고 시그널을 연결합니다.

시그널을 연결하는건 단추를 누르거나 어떤 일이 일어나면 동작이 일어나게 하는 방편입니다. 여기서 `destroy` 메서드는 창을 닫을 때 호출(하고 프로그램을 끝내기)합니다.

`main`은 파이썬 프로그램을 시작할 때 기본으로 시작합니다. 메인 클래스의 인스턴스를 만들고 창을 띄우는 메인 루프를 시작합니다.

이 코드를 사용할 준비가 되었으니 실행실행을 눌러 프로그램을 실행할 수 있습니다.

# 사용자 인터페이스 만들기

사용자 인터페이스(UI) 설명은 GtkBuilder 파일에 있습니다. 사용자 인터페이스를 편집하려면 src/guitar_tuner.ui 파일을 여십시오. 이 파일을 열면 인터페이스 디자이너로 이동합니다. 디자인 창은 가운데에 있고, 위젯과 위젯 속성은 오른편에, 쓸 수 있는 위젯의 팔레트는 왼편에 있습니다.

GTK+의 모든 UI 배치는 상자와 표로 구성합니다. 가로 방향 GtkButtonBox를 여기서 사용하여 각 기타 줄에 해당하는 여섯 개의 GtkButtons 단추를 넣어보겠습니다.

우측 팔레트의 컨테이너 섹션에서 GtkButtonBox 를 선택하여 창에 가져다 높으십시오. 속성 창에서 구성 요소 수를 6(기타 줄 6개)으로 설정하고, 방향은 세로(vertical)로 설정하십시오.

이제 팔레트에서 GtkButton 를 선택하고 상자의 처음 부분에 가져다 놓으십시오.

단추를 선택한 상태에서 위젯 탭의 레이블 속성을 E로 바꾸십시오. 기타의 낮은 E 줄을 의미합니다.

시그널 탭(위젯 탭에 있음)으로 옮겨가서 단추의 `clicked` 시그널을 찾아보십시오. 이 시그널을 사용자가 단추를 눌렀을 때 호출할 시그널 핸들러에 연결할 수 있습니다. 이렇게 하려면, 시그널을 누르고 핸들러 칸에 `on_button_clicked`를 입력하신 다음 Return키를 누르십시오.

다른 단추에 대해서도 그 다음 줄 이름 A, D, G, B, e를 추가하여 위 단계를 반복하십시오.

UI 디자인을 저장(파일저장 누름)하시고 열어둔 상태로 두십시오.

# 시그널 핸들러 작성

UI 디자이너에서 모든 단추를 누르면 동일한 on_button_clicked 함수를 호출하도록 할 수 있습니다. 이 함수를 소스 파일에 추가해야합니다.

진행하려면 사용자 인터페이스 파일을 열어둔 상태에서 guitar_tuner.py 파일을 여십시오. 앞에서 시그널 이름을 설정한 시그널 탭으로 가십시오. 이제 clicked 시그널 줄로 가서 소스 파일의 클래스에 이 시그널을 끌어다 넣으십시오. 소스 파일에 다음 코드가 들어갑니다:

def on_button_clicked (self, button):

이 시그널 핸들러에는 파이썬 클래스 포인터와 함수를 호출하는 `Gtk.Button` 인자가 있습니다.

이제 소리를 내는 코드를 작성하는 동안 시그널 핸들러를 비워두겠습니다.

# 지스트리머 파이프라인

지스트리머는 그놈 멀티미디어 프레임워크입니다. 동영상 오디오 웹캠 스트림 같은걸 재생, 녹음/녹화, 처리할 때 지스트리머를 사용할 수 있습니다. 여기서는 단일 주파수 음색을 만들 때 사용하겠습니다.

개념적으로 지스트리머 동작은 다음과 같습니다. (우선) source에서 sink(출력)으로 내보낼 수많은 처리 요소가 들어간 파이프라인을 만듭니다. source는 그림 파일, 동영상, 음악 파일일 수 있으며, 출력 대상은 위젯 또는 사운드 카드가 될 수 있습니다.

source와 sink 사이에서 다양한 필터와 변환 프로그램을 적용하여 효과를 처리하거나, 형식을 변환하는 등을 할 수 있습니다. 각 파이프라인 구성 요소에는 동작을 바꿀 수 있는 속성이 있습니다.

지스트리머 파이프라인 예제입니다.

# 파이프라인 구성

여기 단순 예제에서는 `audiotestsrc` 라는 음 재생기 소스를 사용하고 기본 시스템 사운드 장치 `autoaudiosink`로 출력을 내보내겠습니다. 우리는 여기서 음 재생기 주파수를 설정해야합니다. `audiotestsrc`의 `freq` 속성을 사용하면 됩니다.

guitar_tuner.py 파일에 import 줄을 다음과 같이 바꾸십시오:

from gi.repository import Gtk, Gst, GObject

`Gst`에는 지스트리머 라이브러리가 들어있습니다. `app = GUI()` 줄 위에 추가한 이 호출과 `main()` 메서드 안의 코드로 지스트리머 속성을 초기화해야합니다:

Gst.init_check(sys.argv)

그 다음 guitar_tuner.py의 클래스 어딘가에 다음 함수 코드를 복사하십시오:

def play_sound(self, frequency): pipeline = Gst.Pipeline(name='note') source = Gst.ElementFactory.make('audiotestsrc', 'src') sink = Gst.ElementFactory.make('autoaudiosink', 'output')

source.set_property('freq', frequency) pipeline.add(source) pipeline.add(sink) source.link(sink) pipeline.set_state(Gst.State.PLAYING)

GObject.timeout_add(self.LENGTH, self.pipeline_stop, pipeline)

처음 세 줄에서는 source와 sink 지스트리머 구성 요소, 파이프라인 구성 요소(source와 sink의 컨테이너로 활용)를 만듭니다. 파이프라인 이름은 "note"라고 지어둡니다. source는 "source"로 이름 붙이고 `audiotestsrc`로 설정합니다. sink는 "output"으로 이름 붙이고 `autoaudiosink` sink로 설정합니다(기본은 사운드 카드 출력).

`source.set_property` 호출에서는 source 구성 요소의 `freq` 속성에 `play_sound` 함수의 인자로 전달한 `frequency` 값을 설정합니다. 이 값은 헤르쯔 단위의 음 주파수입니다. 쓸만한 주파수는 나중에 정의하겠습니다.

다음 두 줄에서는 source 구성 요소와 sink 구성 요소를 파이프라인에 두는 `pipeline.add` 함수를 호출합니다. 파이프라인에는 여러 지스트리머 구성 요소를 넣을 수 있습니다. 보통 `add` 메서드를 반복적으로 호출하여 파이프라인에 원하는 만큼 구성 요소를 넣을 수 있습니다.

다음 `pipeline.set_state` 함수는 파이프라인 상태를 재생 상태(`Gst.State.PLAYING`)로 설정하여 음 재생을 시작할 때 사용합니다.

# 재생 정지

음을 짜증나게 무한정 재생하고 싶진 않기에 `play_sound` 함수에서 마지막으로 할 일은 `GObject.timeout_add` 함수를 호출하는 일입니다. 이 함수는 음 재생을 멈출 제한 시간을 설정합니다. `pipeline_stop` 함수를 호출하기 전 `LENGTH` 밀리초동안 기다리고 `pipeline_stop` 함수에서 `False`를 반환하기 전까지 계속 호출합니다.

이제 `GObject.timeout_add` 함수에서 호출할 `pipeline_stop` 함수를 작성하겠습니다. 다음 코드를 `play_sound` 함수 상단에 넣으십시오:

def pipeline_stop(self, pipeline): pipeline.set_state(Gst.State.NULL) return False

클래스 안에 `LENGTH` 상수를 정의해야 하므로, 메인 클래스 시작 부분에 다음 코드를 추가하겠습니다:

LENGTH = 500

`pipeline.set_state` 함수를 호출하면 파이프라인 재생을 멈춥니다.

# 음색 정의

사용자가 단추를 누르면 올바른 음을 나게 해보겠습니다. 우선 (메인 클래스 시작 부분) 딕셔너리에 정의한 기타 각 여섯줄의 주파수를 알아내어 기타 줄에 이름에 쉽게 대응할 수 있어야합니다:

# Frequencies of the strings frequencies = { 'E': 329.63, 'A': 440, 'D': 587.33, 'G': 783.99, 'B': 987.77, 'e': 1318.5 }

이제 이전에 정의한 시그널 핸들러 `on_button_clicked` 에 내용을 추가할 차례입니다. 모든 단추에 각기 다른 시그널 핸들러를 연결할 수 있지만, 같은 코드를 여러번 반복할 수 있습니다. 대신, 어떤 단추를 눌렀는지 확인할 용도로 단추 레이블을 활용할 수 있습니다:

def on_button_clicked(self, button): label = button.get_child() text = label.get_label()

self.play_sound (self.frequencies[text])

누른 단추는 `on_button_clicked` 함수에 인자(`button`)로 전달합니다. `button.get_child` 함수로 단추 레이블 객체를 가져올 수 있고, 해당 레이블 객체에서 `label.get_label`을 사용하여 텍스트를 가져올 수 있습니다.

레이블 텍스트는 딕셔너리의 키로 사용하며 음에 해당하는 적당한 주파수로 `play_sound`를 호출합니다. 이 코드로 음을 재생합니다. 이렇게 해서 동작하는 기타 조율 프로그램을 만듭니다!

# 프로그램 실행

모든 코드를 실행할 준비를 마쳤습니다. 실행실행을 눌러 프로그램을 시작하시고 즐기세요!

# 참조 구현체

지침서를 따라하는 실행하는 과정에 문제가 있다면, 참조 코드와 여러분의 코드를 비교해보십시오.

# 다음 단계

여기 간단한 시험 프로그램에 여러분이 추가로 넣을 수 있는 몇가지 아이디어가 있습니다:

프로그램에 음 재생 자동 주기 기능 넣기.

프로그램에 실제 기타 현을 퉁겼을 때의 음을 녹음하여 재생하기.

이 동작을 구현하려면 음악 파일을 불러와서 재생할 수 있도록 지스트리머 파이프라인을 좀 더 복잡하게 설정해야합니다. 녹음 음원의 파일 형식에 따른decoder와 demuxer 지스트리머 구성 요소를 선택해야 할 수도 있습니다. 예를 들자면 MP3는 Ogg Vorbis 파일과는 다른 구성 요소를 활용합니다.

좀 더 복잡한 식으로 구성 요소를 연결해야 할 수도 있습니다. pads와 같이 우리가 지침서에서 다룰 수 없는 지스트리머 개념이 들어갈 수도 있습니다. 쓸만한 gst-inspect 명령을 찾아볼 수도 있습니다.

사용자 연주 음을 자동으로 분석.

마이크를 연결하고 input source로 음을 녹음할 수 있습니다. 아마도 스펙트럼 분석 같은 것으로 어떤 음을 재생했는지 알 수 있겠죠?