Blob Blame History Raw
<?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="guitar-tuner.c" xml:lang="ko">

  <info>
    <title type="text">기타 조율기(C)</title>
    <link type="guide" xref="c#examples"/>

    <desc>GTK+와 지스트리머를 간단한 그놈용 기타 조율기 프로그램을 만들어보겠습니다. 인터페이스 디자이너 사용법을 나타냅니다.</desc>

    <revision pkgversion="0.1" version="0.1" date="2010-12-02" status="review"/>
    <credit type="author">
      <name>그놈 문서 프로젝트</name>
      <email its:translate="no">gnome-doc-list@gnome.org</email>
    </credit>
    <credit type="author">
      <name>Johannes Schmid</name>
      <email its:translate="no">jhs@gnome.org</email>
    </credit>
    <credit type="editor">
      <name>Marta Maria Casetti</name>
      <email its:translate="no">mmcasetti@gmail.com</email>
      <years>2013</years>
    </credit>
  
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
      <mal:name>조성호</mal:name>
      <mal:email>shcho@gnome.org</mal:email>
      <mal:years>2017</mal:years>
    </mal:credit>
  </info>

<title>기타 조율기</title>

<synopsis>
  <p>이 지침서에서, 기타 조율에 사용할 수 있는 음색을 재생하는 프로그램을 만들겠습니다. 다음 내용을 배워나갑니다:</p>
  <list>
    <item><p>안주타에서 기본 프로젝트 설정</p></item>
    <item><p>안주타 사용자 인터페이스 디자이너에서 간단한 GUI 만들기</p></item>
    <item><p>지스트리머를 사용하여 소리 재생하기</p></item>
  </list>
  <p>이 지침을 따라갈 수 있으려면 다음이 필요합니다:</p>
  <list>
    <item><p><link xref="getting-ready">안주타 IDE</link> 설치 사본</p></item>
    <item><p>C 프로그래밍 언어 기본 지식</p></item>
  </list>
</synopsis>

<media type="image" mime="image/png" src="media/guitar-tuner.png"/>

<section id="anjuta">
  <title>안주타에서 프로젝트 만들기</title>
  <p>코딩을 시작하기 전에 안주타에서 새 프로젝트를 설정해야합니다. 이 프로그램은 빌드에 필요한 모든 파일을 만들고 그 다음 코드를 실행합니다. 또한 이 모든 상태를 유지 관리하는데 쓸만합니다.</p>
  <steps>
    <item>
    <p>안주타를 시작하고 <guiseq><gui>파일</gui><gui>새로 만들기</gui><gui>프로젝트</gui></guiseq> 를 눌러 프로젝트 마법사를 여십시오.</p>
    </item>
    <item>
    <p><gui>C</gui> 탭에서 <gui>GTK+ (단순)</gui>를 선택하고, <gui>계속</gui>을 누른 다음, 나타난 페이지에서 몇가지 자세한 내용을 입력하십시오. 프로젝트 이름과 디렉터리에 <file>guitar-tuner</file>를 입력하십시오.</p>
   	</item>
    <item>
    <p><gui>외부 패키지 설정</gui>을 <gui>켬</gui>으로 설정했는지 확인하십시오. 다음 페이지의 목록에서 <em>gstreamer-0.10</em>를 선택하여 프로젝트에 지스트리머 라이브러리를 넣으십시오.</p>
    </item>
    <item>
    <p><gui>적용</gui>을 누르면 프로젝트를 만들어줍니다. <gui>프로젝트</gui>나 <gui>파일</gui>탭에서 <file>src/main.c</file> 파일을 여십시오. 다음 줄로 시작하는 일부 코드를 볼 수 있어야합니다:</p>
    <code mime="text/x-csrc">
#include &lt;config.h&gt;
#include &lt;gtk/gtk.h&gt;</code>
    </item>
  </steps>
</section>

<section id="build">
  <title>첫 코드 작성</title>
  <p>C는 장황하게 하나하나 다 따지고 들어가야 하는 언어니, 좀 많은 코드가 들어가 있는 파일에 놀라지 않으셔도 됩니다. 대부분은 서식 코드입니다. 이 코드에서는 사용자 인터페이스 설명 파일에서 (빈) 창을 불러와 열고 화면에 나타냅니다. 자세한 내용은 아래에 있습니다. 기본을 이미 알고 있다면 이 부분은 건너뛰십시오:</p>

  <list>
  <item>
    <p>상단의 <code>#include</code> 세 줄은 <code>config</code>(쓸만한 autoconf 빌드 정의),  <code>gtk</code>(사용자 인터페이스), <code>gi18n</code>(국제화) 라이브러리입니다. 이 라이브러리의 함수를 나머지 코드에서 사용하겠습니다.</p>
   </item>
   <item>
    <p><code>create_window</code> 함수는 GtkBuilder 파일(<file>src/guitar-tuner.ui</file> 위 몇 줄 지정)을 열어 새 창을 만들고, 시그널을 연결한 다음, 창에 띄웁니다. GtkBuilder 파일에는 사용자 인터페이스 설명 정보와 구성요소 모두가 들어있습니다. GtkBuilder 사용자 인터페이스를 설계할 때 안주타 편집기를 사용할 수 있습니다.</p>
    <p>시그널 연결은 단추를 누르거나 어떤 동작을 취할 때 처리할 일을 정의하는 방식입니다. 여기서 창을 닫을 때 <code>destroy</code> 함수를 호출(하고 앱을 끝내기)합니다.</p>
   </item>
   <item>
    <p><code>main</code> 함수는 C 프로그램을 시작할 때 기본으로 실행하는 함수입니다. 이 함수에서 몇가지 함수를 호출하여 설정하고 프로그램을 실행합니다. <code>gtk_main</code> 함수는 사용자 인터페이스를 실행하고 사용자 반응(마우스 단추 누름, 키보드 키 누름)대기를 시작하는 GTK 메인 루프 시작 함수입니다.</p>
   </item>
   <item>
    <p><code>ENABLE_NLS</code> 상태 정의는 프로그램을 번역하는 프레임워크 <code>gettext</code>를 설정합니다. 이 함수는 프로그램을 실행할 때 번역 도구가 프로그램을 어떻게 다뤄야 하는지를 설정합니다.</p>
   </item>
  </list>

  <p>이 코드를 사용할 준비가 됐으니 <guiseq><gui>빌드</gui><gui>프로젝트 빌드</gui></guiseq>(또는 <keyseq><key>Shift</key><key>F7</key></keyseq> 키 누름)를 눌러 코드를 컴파일할 수 있습니다.</p>
  <p>디버깅 빌드 설정이 나타나는 다음 창에서 <gui>실행</gui> 을 누르십시오. 처음 빌드할 때 한번만 하면 됩니다.</p>
</section>

<section id="ui">
  <title>사용자 인터페이스 만들기</title>
  <p>사용자 인터페이스(UI) 설명은 GtkBuilder 파일에 있습니다. 사용자 인터페이스를 편집하려면 <file>src/guitar_tuner.ui</file> 파일을 여십시오. 이 과정에서 바로 인터페이스 디자이너로 넘어갑니다. 설계 창은 가운데에 있고 위젯과 위젯 속성은 왼편에, 사용할 수 있는 위젯은 오른편에 있습니다.</p>
  <p>GTK+의 모든 UI 배치는 상자와 표로 구성합니다. 가로 방향 <gui>GtkButtonBox</gui>를 여기서 사용하여 각 기타 줄에 해당하는 여섯 개의 <gui>GtkButtons</gui> 단추를 넣어보겠습니다.</p>

<media type="image" mime="image/png" src="media/guitar-tuner-glade.png"/>

  <steps>
   <item>
   <p>우측 <gui>팔레트</gui>의 <gui>컨테이너</gui> 섹션에서 <gui>GtkButtonBox</gui> 를 선택하여 창에 가져다 높으십시오. <gui>속성</gui> 창에서 구성 요소 수를 6(기타 줄 6개)으로 설정하고, 방향은 세로(vertical)로 설정하십시오.</p>
   </item>
   <item>
    <p>이제 팔레트에서 <gui>GtkButton</gui> 를 선택하고 상자의 처음 부분에 가져다 놓으십시오.</p>
   </item>
   <item>
    <p>단추를 선택한 상태에서 <gui>위젯</gui> 탭의 <gui>레이블</gui> 속성을 <gui>E</gui>로 바꾸십시오. 기타의 낮은 E 줄을 의미합니다.</p>
    </item>
    <item>
     <p><gui>시그널</gui> 탭(<gui>위젯</gui> 탭에 있음)으로 옮겨가서 단추의 <code>clicked</code> 시그널을 찾아보십시오. 이 시그널을 사용자가 단추를 눌렀을 때 호출할 시그널 핸들러에 연결할 수 있습니다. 이렇게 하려면, 시그널을 누르고 <gui>핸들러</gui> 칸에 <code>on_button_clicked</code>를 입력하신 다음 <key>Return</key>키를 누르십시오.</p>
    </item>
    <item>
    <p>다른 단추에 대해서도 그 다음 줄 이름 <em>A</em>, <em>D</em>, <em>G</em>, <em>B</em>, <em>e</em>를 추가하여 위 단계를 반복하십시오.</p>
    </item>
    <item>
    <p>UI 디자인을 저장(<guiseq><gui>파일</gui><gui>저장</gui></guiseq> 누름)하시고 열어둔 상태로 두십시오.</p>
    </item>
  </steps>
</section>

<section id="signal">
  <title>시그널 핸들러 만들기</title>
  <p>UI 디자이너에서 모든 단추를 누르면 동일한 <gui>on_button_clicked</gui> 함수를 호출하도록 할 수 있습니다. 이 함수를 소스 파일에 추가해야합니다.</p>
  <p>이렇게 하려면, 사용자 인터페이스 파일을 열어둔 상태에서 <file>main.c</file> 파일을 여십시오. 시그널 이름을 설정하는데 사용한 <gui>시그널</gui> 탭으로 옮겨가십시오. 이제 <gui>clicked</gui> 시그널을 설정한 줄로 가서, 이 항목을 소스 파일의 함수 바깥에 끌어다 놓으십시오. 그러면 다음 코드가 소스 파일에 들어갑니다:</p>
<code mime="text/x-csrc">
void on_button_clicked (GtkWidget* button, gpointer user_data)
{

}</code>
  <p>이 시그널 핸들러는 함수로 호출하는 <code>GtkWidget</code>(이 경우 항상 <code>GtkButton</code>)의 포인터, 그리고 여러분이 정의할 수 있지만 여기서는 활용하지 않을 "사용자 데이터" 포인터를 인자로 두고 있습니다(<code>gtk_builder_connect_signals</code>를 호출하여 사용자 데이터를 설정할 수 있습니다. 보통 시그널 핸들러 내에서 접근할 데이터 구조의 포인터를 전달할 때 사용합니다).</p>
  <p>이제 소리를 내는 코드를 작성하는 동안 시그널 핸들러를 비워두겠습니다.</p>
</section>

<section id="gstreamer">
  <title>지스트리머 파이프라인</title>
  <p>지스트리머는 그놈 멀티미디어 프레임워크입니다. 동영상 오디오 웹캠 스트림 같은걸 재생, 녹음/녹화, 처리할 때 지스트리머를 사용할 수 있습니다. 여기서는 단일 주파수 음색을 만들 때 사용하겠습니다.</p>
  <p>개념적으로 지스트리머 동작은 다음과 같습니다. (우선) <em>source</em>에서  <em>sink</em>(출력)으로 내보낼 수많은 처리 요소가 들어간 <em>파이프라인</em>을 만듭니다. source는 그림 파일, 동영상, 음악 파일일 수 있으며, 출력 대상은 위젯 또는 사운드 카드가 될 수 있습니다.</p>
  <p>source와 sink 사이에서 다양한 필터와 변환 프로그램을 적용하여 효과를 처리하거나, 형식을 변환하는 등을 할 수 있습니다. 각 파이프라인 구성 요소에는 동작을 바꿀 수 있는 속성이 있습니다.</p>
  <media type="image" mime="image/png" src="media/guitar-tuner-pipeline.png">
    <p>지스트리머 파이프라인 예제입니다.</p>
  </media>
</section>

<section id="pipeline">
  <title>파이프라인 구성</title>
  <p>여기 단순 예제에서는 <code>audiotestsrc</code> 라는 음 재생기 소스를 사용하고 기본 시스템 사운드 장치 <code>autoaudiosink</code>로 출력을 내보내겠습니다. 우리는 여기서 음 재생기 주파수를 설정해야합니다.  <code>audiotestsrc</code>의 <code>freq</code> 속성을 사용하면 됩니다.</p>

  <p>다음 줄을 <file>main.c</file>에 <code>#include &lt;gtk/gtk.h&gt;</code> 줄 바로 밑에 넣으십시오:</p>
  <code mime="text/x-csrc">#include &lt;gst/gst.h&gt;</code>
  <p>여기에 지스트리머 라이브러리가 들어있습니다. 아래 줄을 추가해서 지스트리머를 초기화해야합니다. <code>main</code>  함수의 <code>gtk_init</code> 함수 호출 위에 다음 코드를 넣으십시오:</p>
  <code>gst_init (&amp;argc, &amp;argv);</code>
  <p>다음, 아래의 함수를 <file>main.c</file> 함수의 위에서 만들어 비워둔 <code>on_button_clicked</code> 함수에 복사해넣으십시오:</p>
  <code mime="text/x-csrc">static void
play_sound (gdouble frequency)
{
	GstElement *source, *sink;
	GstElement *pipeline;

	pipeline = gst_pipeline_new ("note");
	source   = gst_element_factory_make ("audiotestsrc",
	                                     "source");
	sink     = gst_element_factory_make ("autoaudiosink",
	                                     "output");

	/* set frequency */
	g_object_set (source, "freq", frequency, NULL);

	gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
	gst_element_link (source, sink);

	gst_element_set_state (pipeline, GST_STATE_PLAYING);

	/* stop it after 500ms */
	g_timeout_add (LENGTH, (GSourceFunc) pipeline_stop, pipeline);
}</code>

  <steps>
    <item>
    <p>처음 다섯줄에서는 source와 sink 지스트리머 구성 요소(<code>GstElement</code>), 파이프라인 구성 요소(source와 sink의 컨테이너로 활용)를 만듭니다. 파이프라인 이름은 "note"라고 지어둡니다. source는 "source"로 이름 붙이고 <code>audiotestsrc</code>로 설정합니다. sink는 "output"으로 이름 붙이고 <code>autoaudiosink</code> sink로 설정합니다(기본은 사운드 카드 출력).</p>
    </item>
    <item>
    <p><code>g_object_set</code> 호출로 source 구성 요소의 <code>freq</code> 속성 값을 <code>play_sound</code> 함수에 인자로 전달할 <code>frequency</code> 로 설정합니다. 이 변수는 헤르쯔 단위의 음 주파수일 뿐입니다. 쓸만한 주파수는 나중에 설정하겠습니다.</p>
    </item>
    <item>
    <p><code>gst_bin_add_many</code>는 파이프 라인에 source와 sink를 둡니다. 파이프라인은 다른 지스트리머 구성 요소 여러가지를 둘 수 있는 <code>GstBin</code> 입니다. 보통 여러분은 <code>gst_bin_add_many</code>에 더 많은 인자를 넣어 파이프라인에 더 많은 구성요소를 추가할 수 있습니다.</p>
    </item>
    <item>
    <p>다음, 구성 요소 각각을 연결하여 <code>source</code>(음) 출력을 <code>sink</code> (사운드 카드 출력) 입력으로 보낼 때 <code>gst_element_link</code> 함수를 사용합니다. 그 다음 <code>gst_element_set_state</code> 함수로 파이프라인 상태를 재생(<code>GST_STATE_PLAYING</code>)으로 두어 음을 재생합니다.</p>
    </item>
  </steps>

</section>

<section id="stop">
  <title>재생 정지</title>
  <p>음을 무한정 지겹게 재생하고 싶지는 않기 때문에 <code>play_sound</code> 함수에서 <code>g_timeout_add</code> 함수를 호출합니다. 이 함수에서 음 재생을 멈출 제한 시간을 설정합니다.  <code>pipeline_stop</code> 함수를 호출하기 전에 <code>LENGTH</code> 밀리초 동안 기다리며, <code>pipeline_stop</code>함수에서 <code>FALSE</code> 값을 반환하기 전에는 함수 호출을 지속합니다.</p>
  <p>이제 <code>g_timeout_add</code> 함수에서 호출할 <code>pipeline_stop</code> 함수를 작성하겠습니다. 다음 코드를 <code>play_sound</code> <em>상단</em>에 넣으십시오:</p>
  <code mime="text/x-csrc">
#define LENGTH 500 /* Length of playing in ms */

static gboolean
pipeline_stop (GstElement* pipeline)
{
	gst_element_set_state (pipeline, GST_STATE_NULL);
	g_object_unref (pipeline);

	return FALSE;
}</code>
  <p><code>gst_element_set_state</code> 함수 호출로 파이프라인 재생을 멈추며, <code>g_object_unref</code> 함수로 파이프라인 참조를 해제하고 파이프라인 자체를 파괴한 다음, 할당한 메모리 공간을 놓아줍니다.</p>
</section>

<section id="tones">
  <title>음색 정의</title>
  <p>사용자가 단추를 눌렀을 때 올바른 소리를 재생하고자합니다. 우선 다음과 같이 (<file>main.c</file> 상단에) 정의한 기타 6현의 주파수를 알아야합니다:</p>
  <code mime="text/x-csrc">
/* Frequencies of the strings */
#define NOTE_E 329.63
#define NOTE_A 440
#define NOTE_D 587.33
#define NOTE_G 783.99
#define NOTE_B 987.77
#define NOTE_e 1318.5</code>
  <p>이제 이전에 정의한 시그널 핸들러 <code>on_button_clicked</code> 에 내용을 추가할 차례입니다. 모든 단추에 각기 다른 시그널 핸들러를 연결할 수 있지만, 같은 코드를 여러번 반복할 수 있습니다. 대신, 어떤 단추를 눌렀는지 확인할 용도로 단추 레이블을 활용할 수 있습니다:</p>
  <code mime="text/x-csrc">
/* Callback for the buttons */
void on_button_clicked (GtkButton* button,
                        gpointer user_data)
{
	const gchar* text = gtk_button_get_label (button);

	if (g_str_equal (text, _("E")))
	    play_sound (NOTE_E);
	else if (g_str_equal (text, _("A")))
	    play_sound (NOTE_A);
	else if (g_str_equal (text, _("G")))
	    play_sound (NOTE_G);
	else if (g_str_equal (text, _("D")))
	    play_sound (NOTE_D);
	else if (g_str_equal (text, _("B")))
	    play_sound (NOTE_B);
	else if (g_str_equal (text, _("e")))
	    play_sound (NOTE_e);
}
</code>
  <p>누른 <code>GtkButton</code>의 포인터를 <code>on_button_clicked</code>의 인자(<code>button</code>)로 전달합니다. 단추의 글자는 <code>gtk_button_get_label</code> 함수로 가져올 수 있습니다.</p>
  <p><code>g_str_equal</code> 함수로 이 글자를 비교한 후, 음에 맞는 주파수로 <code>play_sound</code> 함수를 호출합니다. 이 절차로 음을 재생합니다. 이제 동작하는 기타 조율기가 만들어졌군요!</p>
</section>

<section id="run">
  <title>프로그램 빌드 및 실행</title>
  <p>모든 코드를 실행할 준비가 됐습니다. <guiseq><gui>빌드</gui><gui>프로젝트 빌드</gui></guiseq>를 눌러 프로젝트 전체를 다시 빌드하고, <guiseq><gui>실행</gui><gui>실행</gui></guiseq>을 눌러 프로그램을 시작하십시오.</p>
  <p>아직 끝내지 않았다면 나타난 대화상자에서 <file>Debug/src/guitar-tuner</file>  프로그램을 선택하십시오. 마지막으로 <gui>Run</gui>를 눌러 만든 프로그램을 즐기시죠!</p>
</section>

<section id="impl">
 <title>참조 구현체</title>
 <p>지침서를 따라하는 실행하는 과정에 문제가 있다면, <link href="guitar-tuner/guitar-tuner.c">참조 코드</link>와 여러분의 코드를 비교해보십시오.</p>
</section>

<section id="next">
  <title>다음 단계</title>
  <p>여기 간단한 시험 프로그램에 여러분이 추가로 넣을 수 있는 몇가지 아이디어가 있습니다:</p>
  <list>
   <item>
   <p>프로그램에 음 재생 자동 주기 기능 넣기.</p>
   </item>
   <item>
   <p>프로그램에 실제 기타 현을 퉁겼을 때의 음을 녹음하여 재생하기.</p>
   <p>이 동작을 구현하려면 음악 파일을 불러와서 재생할 수 있도록 지스트리머 파이프라인을 좀 더 복잡하게 설정해야합니다. 녹음 음원의 파일 형식에 따른<link href="http://gstreamer.freedesktop.org/documentation/plugins.html">decoder와 demuxer</link> 지스트리머 구성 요소를 선택해야 할 수도 있습니다. 예를 들자면 MP3는 Ogg Vorbis 파일과는 다른 구성 요소를 활용합니다.</p>
   <p>좀 더 복잡한 식으로 구성 요소를 연결해야 할 수도 있습니다. <link href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/section-intro-basics-pads.html">pads</link>와 같이 우리가 지침서에서 다룰 수 없는 <link href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/chapter-intro-basics.html">지스트리머 개념</link>이 들어갈 수도 있습니다. 쓸만한 <cmd>gst-inspect</cmd>  명령을 찾아볼 수도 있습니다.</p>
   </item>
   <item>
   <p>사용자 연주 음을 자동으로 분석.</p>
   <p>마이크를 연결하고 <link href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-good-plugins/html/gst-plugins-good-plugins-autoaudiosrc.html">input source</link>로 음을 녹음할 수 있습니다. 아마도 <link href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-good-plugins/html/gst-plugins-good-plugins-plugin-spectrum.html">스펙트럼 분석</link> 같은 것으로 어떤 음을 재생했는지 알 수 있겠죠?</p>
   </item>
  </list>
</section>

</page>