วันอาทิตย์ที่ 26 มิถุนายน พ.ศ. 2554

การเขียนวิทยานิพนธ์ ม.ข. ด้วย LaTeX - การสร้างหน้าปกและปกใน

การสร้างส่วนปกของวิทยานิพนธ์ แบ่งออกเป็น 3 ส่วนคือ
  1. ปกหน้า ประกอบด้วยตรามหาวิทยาลัย ชื่อวิทยานิพนธ์
  2. ปกใน ภาษาไทยและภาษาอังกฤษ มีรายละเอียดเพิ่มเติมเกี่ยวกับวิทยานิพนธ์
  3. ใบรับรอง ระบุชื่อคณะกรรมการสอบวิทยานิพนธ์ ส่วนให้คณบดีของคณะต้นสังกัด และคณบดีบัณฑิตศึกษาลงนาม
เพื่อดำเนินการในส่วนนี้ได้สะดวก จะต้องมีส่วนที่ศูนย์ คือการกำหนดค่าตัวแปรที่เกี่ยวข้องกับวิทยานิพนธ์ต่าง ๆ เช่นชื่อวิทยานิพนธ์ ชื่อผู้แต่ง หลักสูตร ฯลฯ จะขออธิบายโดยเริ่มจากส่วนที่ศูนย์ก่อน

กำหนดตัวแปรที่สำคัญ
% - Thesis Information
\newcommand*{\titleth}[1]{\def\@titleth{#1}}      % Thesis Title in Thau
\newcommand*{\authorth}[1]{\def\@authorth{#1}}    % Author name with title in Thai
\newcommand*{\authortha}[1]{\def\@authortha{#1}}  % Author name without title in Thai
\newcommand*{\authora}[1]{\def\@authora{#1}}      % Author name with title in English
\newcommand*{\yearth}[1]{\def\@yearth{#1}}        % Academic Year in B.E.
\newcommand*{\degreeth}[1]{\def\@degreeth{#1}}    % Degree in Thai
\newcommand*{\advisorth}[1]{\def\@advisorth{#1}}  % Advisor name in Thai

\newcommand*{\yearen}[1]{\def\@yearen{#1}}        % Academic year in A.D.
\newcommand*{\degree}[1]{\def\@degree{#1}}        % Degree in English
\newcommand*{\advisoren}[1]{\def\@advisoren{#1}}  % Advisor name in English

\newcommand*{\committeechair}[1]{\def\@committeechair{#1}}   % Committee chair name
\newcommand*{\firstcommittee}[1]{\def\@firstcommittee{#1}}   % Committee name
\newcommand*{\secondcommittee}[1]{\def\@secondcommittee{#1}} % Committee name
\newcommand*{\deanofgs}[1]{\def\@deanofgs{#1}}               % Dean of Graduate Schoold
\newcommand*{\deanofen}[1]{\def\@deanofen{#1}}               % Dean of Host Faculty (Need to change to more proper name)

หน้าปก
จะต้องวางตราสัญลักษณ์มหาวิทยาลัยขอนแก่นไว้ตรงกลางหน้า ต่ำจากนั้นลงมาก็จะเป็นชื่อวิทยานิพนธ์ภาษาไทย (ตัวหนา) และภาษาอังกฤษ (ตัวหนาและเป็นตัวใหญ่ทั้งหมด) ตามลำดับ จากนั้นเว้นระยะไป 6 ซ.ม. จึงจะเป็นชื่อผู้แต่งไม่มีคำนำหน้า (ตัวหนา) เว้นระยะไปอีก 6.9 ซ.ม. ก็จะเป็นการประกาศวุฒิ มหาวิทยาลัย และปีการศึกษา ซึ่งส่วนของวุฒิและปีการศึกษานั้นจะรับมาจากตัวแปรข้างบน ส่วนชื่อมหาวิทยาลัยขอนแก่นนั้นจะฝังลงไปในคลาสเลย สำหรับตัวเลขระยะที่ระบุในส่วนนี้ได้จากการวัดระยะตัวอย่างวิทยานิพนธ์จริง ฝังระยะคงที่นี้ไว้ในคลาสเลยเช่นเดียวกัน แต่ว่าน่าจะปรับปรุงได้ในอนาคต
% - Front Cover
\begin{titlepage}
\begin{ċenter}
 \begin{figure}
   \begin{ċenter}
  \IfFileExists{kkuNew.eps}{\includegraphics[scale =0.1]{kkuNew.eps}}{File kkuNew.eps is not found.}
     \end{ċenter}
 \end{figure}
\end{ċenter}
\begin{ċenter}
{\large \textbf{\MakeUppercase{\@titleth}}} \\
{\large \textbf{\MakeUppercase{\@title}}}
\end{ċenter}
\vspace{6cm}
\begin{ċenter}
{\large \textbf{\MakeUppercase{\@authorth}}}
\end{ċenter}
\vspace{6.9cm}
\begin{ċenter}
{\large \textbf{วิทยานิพนธ์ปริญญา\@degreeth \\ มหาวิทยาลัยขอนแก่น} \\
\textbf{พ.ศ. \@yearth}}
\end{ċenter}
\end{titlepage}%

ปกใน
ปกในมีสองส่วนย่อยคือปกในภาษาไทยและปกในภาษาอังกฤษ ซึ่งทั้งสองส่วนจะมีโครงสร้างคล้าย ๆ กันคือ ชื่อวิทยานิพนธ์อยู่กลางหน้าด้านบน (ตัวหนา) เว้นระยะ 9 ซ.ม. จะเป็นชื่อผู้แต่งมีคำนำหน้า (ตัวหนา) และเว้นระยะอีก 9 ซ.ม. ก็จะเป็นการประกาศว่าวิทยานิพนธ์นี้เป็นส่วนหนึ่งของหลักสูตรอะไร สาขาอะไร ในมหาวิทยาลัยขอนแก่น ในส่วนนี้ผมนึกชื่อตัวแปรที่จะใช้บรรจุสาขาวิชาไม่ออก เลยเขียน hard code ลงไปในคลาสเลย ควรได้รับการปรับปรุงเพื่อให้สามารถส่งชื่อสาขาวิชาผ่านตัวแปรได้ ในค่าระยะคงที่ที่ใช้ในคลาสมาจาการวัดจริงจากตัวอย่างวิทยานิพนธ์เช่นเดียวกัน
% Title page in Thai
\begin{titlepage}
\thispagestyle{empty}
\begin{ċenter}
{\large \textbf{\MakeUppercase{\@titleth}}}
\end{ċenter}
\vspace{9cm}
\begin{ċenter}
{\large \textbf{\@authorth}}
\end{ċenter}
\vspace{9cm}
\begin{ċenter}
\textbf{วิทยานิพนธ์นี้เป็นส่วนหนึ่งของการศึกษาตามหลักสูตรปริญญา\@degreeth}\\
\textbf{สาขาวิชาวิศวกรรมไฟฟ้า}\\
\textbf{บัณฑิตวิทยาลัย มหาวิทยาลัยขอนแก่น}\\
\textbf{พ.ศ. \@yearth}
\end{ċenter}
\end{titlepage}

% Title page in English
\begin{titlepage}
\thispagestyle{empty}
\begin{ċenter}
{\large \textbf{\MakeUppercase{\@title}}}
\end{ċenter}
\vspace{9cm}
\begin{ċenter}
{\large \textbf{\MakeUppercase{\@author}}}
\end{ċenter}
\vspace{8.7cm}
\begin{ċenter}
\textbf{\MakeUppercase{A thesis submitted in partial fulfillment of the requirements}}\\
\textbf{\MakeUppercase{for the degree of \@degree}}\\
\textbf{\MakeUppercase{in Electrical Engineering}}\\
\textbf{\MakeUppercase{Graduate School Khon Kaen University}}\\
\textbf{\MakeUppercase{\@yearen}}
\end{ċenter}
\end{titlepage}

ใบรับรอง
ในหน้านี้จะประกอบด้วยตราสัญลักษณ์มหาวิทยาลัยขอนแก่นตรงกลางหน้าด้านบน ต่ำลงมาจะเป็นคำประกาศใบรับรองวิทยานิพนธ์ ตรงจุดนี้ผมใช้การใส่ข้อมูลตรง ๆ ลงไปในคลาส ไม่ผ่านตัวแปรซึ่งควรแก้ไข ต่ำลงมา 1 ซ.ม. จะเป็นชื่อวิทยานิพนธ์ ต่ำลงมาอีก 1 ซ.ม. จะเป็นชื่อผู้เขียน (มีคำนำหน้า) ต่ำลงมาอีก 1 ซ.ม. จะเป็นรายชื่อกรรมการสอบวิทยานิพนธ์ เว้นระยะลงมา 2 ซ.ม. เป็นชื่ออาจารย์ที่ปรึกษา หลังจากนั้นจะเป็นส่วนที่จะให้คณบดีคณะต้นสังกัด และคณบดีบัณฑิตวิทยาลัยลงนาม
% Certificate page
\begin{titlepage}
\thispagestyle{empty}
\begin{ċenter}
 %\vspace{2.5cm}
 \begin{figure}
   \begin{ċenter}
  \IfFileExists{kkuNew.eps}{\includegraphics[scale =0.1]{kkuNew.eps}}{File kkuNew.eps is not found.}
     \end{ċenter}
 \end{figure}
\end{ċenter}
\begin{ċenter}
\textbf{ใบรับรองวิทยานิพนธ์}\\
\textbf{มหาวิทยาลัยขอนแก่น}\\
\textbf{หลักสูตร}\\
\textbf{วิศวกรรมศาสตรมหาบัณฑิต}\\
\textbf{สาขาวิชาวิศวกรรมไฟฟ้า}
\end{ċenter}
\vspace{1cm}
\begin{flushleft}
\textbf{ชื่อวิทยานิพนธ์}: \hspace{2em} \@titleth \\
\vspace{1cm}
\textbf{ชื่อผู้ทำวิทยานิพนธ์}: \hspace{2em} \@authorth \\
\vspace{1cm}
\begin{tabular}{@{}lll}
\textbf{คณะกรรมการสอบวิทยานิพนธ์} & \@committeechair  & ประธานกรรมการ \\
                               & \@firstcommittee & กรรมการ \\
                               & \@secondcommittee  & กรรมการ
\end{tabular}
\end{flushleft}
\vspace{2cm}
\textbf{อาจารย์ที่ปรึกษาวิทยานิพนธ์:}\\
\begin{ċenter}
% \makebox with zero width is free from center environment
% this is very handy for signature line.
% Could be useful for official memo (Thailand) too.
\makebox[6cm][l]{\dotfill{}}\makebox[0pt][l]{ อาจารย์ที่ปรึกษา}\\
(\@advisorth)
\end{ċenter}
\vspace{1cm}
\begin{ċenter}
\begin{tabular}{ccc}
\dotfill{}&&\dotfill{}\\
 (\@deanofgs)&&(\@deanofen)\\
คณบดีบัณฑิตวิทยาลัย && คณบดีคณะวิศวกรรมศาสตร์ \\
\end{tabular}
\end{ċenter}
\vspace{1cm}
\begin{ċenter}
ลิขสิทธิ์ของมหาวิทยาลัยขอนแก่น
\end{ċenter}
\end{titlepage}

นำคำสั่งทุกคำสั่งที่ตั้งแต่ส่วนที่ใช้สร้างปกจนถึงส่วนใบรับรองบรรจุไว้ในส่วนสร้างคำสั่ง \maketitle
\renewcommand\maketitle{
% Commands that create covers and certificate page described earlier
}
หมายความว่าคำสั่งทั้งหมดที่ใช้สร้างปกที่อธิบายไว้ข้างต้น จะต้องอยู่ระหว่าง { และ } ของคำสั่ง \renewcommand\maketitle นั่นเอง

วันเสาร์ที่ 25 มิถุนายน พ.ศ. 2554

การเขียนวิทยานิพนธ์ ม.ข. ด้วย LaTeX - ความเป็นมาและการสร้างคลาส

ความเป็นมา
เรื่องการเขียนวิทยานิพนธ์ ม.ข. ด้วย LaTeX นี่เริ่มเมื่อประมาณปีที่แล้ว คือหลังจากที่ได้ศึกษาเอกสารที่เกี่ยวข้องมาบ้าง (เคยบันทึกไว้ที่นี่) ก็เกิดความอหังการ คิดว่าเราน่าจะทำได้เหมือนกัน จึงคุยกับนักศึกษาปริญญาโทที่อยู่ในความดูแล (คุณอดิเทพ กงจันทร์) ว่ามาช่วยกันทำคลาส LaTeX สำหรับวิทยานิพนธ์กันดีไหม แล้วจะได้ใช้คลาสนี้เขียนวิทยานิพนธ์ส่งเขาไปเลย ไม่ต้องใช้ MS-Word คุณอดิเทพตกลง (เคยคุยกันเล่น ๆ ช่วงใกล้เส้นตายส่งงานว่าคิดถูกหรือคิดผิดก็ไม่รู้ :p)

พวกเราก็เลยร่วมกันพัฒนาคลาสสำหรับวิทยานิพนธ์ ม.ข. นี้ร่วมกันมา โดยเริ่มต้นจากตัวอย่างวิทยานิพนธ์ของ (รอชื่อ - สกุลจริงอยู่) อดีตนักศึกษาระดับบัณฑิตศึกษาของภาควิชาคณิตศาสตร์ คณะวิทยาศาสตร์มหาวิทยาลัยขอนแก่น ซึ่งใช้ LaTeX เขียนวิทยานิพนธ์ภาษาอังกฤษแบบ Hard Code คือไม่ได้สร้างเป็นคลาส และไม่ได้ใช้ภาษาไทย

ก็ช่วยกันทำมาเรื่อย ๆ ตั้งแต่เมื่อราว ๆ เดือนพฤศจิกายน 2553 เป็นต้นมา บัดนี้วิทยานิพนธ์ของคุณอดิเทพก็ส่งไปแล้วโดยใช้คลาสที่ช่วยกันเขียนช่วยกันแก้นี่แหละ แม้ว่าคลาสจะยังไม่สมบูรณ์และยังมีส่วนที่ยังปรับปรุงได้อีกมาก แต่ก็ถือว่าใช้ประโยชน์ได้แล้ว จึงถึงเวลาที่จะนำมาเผยแพร่ให้เป็นประโยชน์และให้ชุมชนช่วยกันพัฒนาต่อไป

ในการนี้ได้รับคำแนะนำจากคุณเทพพิทักษ์ในกิจกรรมโสเหล่ครั้งที่ 12 ของ KKLUG ว่าน่าจะอัพโหลดต้นฉบับไว้ที่โฮสต์ที่ไหนสักที่หนึ่ง เพื่อที่ทุก ๆ คนจะได้ร่วมกันพัฒนาต่อไปได้โดยง่าย จึงได้อัพโหลดต้นฉบับคลาสไว้ที่ sourceforge.net ซึ่งหากผู้อ่านท่านใดสนใจก็ขอให้ดาวน์โหลดต้นฉบับโปรแกรมได้และหากติดปัญหาหรือมีข้อเสนอแนะใด ๆ (น่าจะมีเยอะอยู่เพราะโปรแกรมยังไม่มีตัวอย่างและไม่มีคู่มือ) ก็สามารถติดต่อผู้เขียนได้ที่ห้องทำงานครับ

ในส่วนของบล๊อกก็จะทยอยอธิบายการทำงานของโปรแกรมไปทีละส่วน ๆ เช่นก่อนหน้านี้เคยเขียนไปแล้วหนหนึ่งคือเรื่องการสร้างสารบัญ (เป็นอีกเรื่องหนึ่งที่ได้รับคำแนะนำจากโสเหล่ว่าน่าจะพัฒนาได้อีก)

การสร้างคลาส
เนื่องจากคลาสค่อนข้างใหญ่ มีการกำหนดค่าต่าง ๆ มากมายจึงขอนำมาเสนอทีละส่วน โดยจะนำการสร้างคล้าสจากเล็กไปหาใหญ่ทีละขั้น ๆ เริ่มที่การสร้างส่วนที่จำเป็นสำหรับคลาสเป็นอันดับแรก ส่วนประกอบที่สำคัญของคลาสประกอบด้วย
  • ส่วนหัวที่จำเป็นและการประกาศคลาสที่กำลังสร้างอยู่
  • หากมีคลาสต้นแบบให้ LoadClass ต้นแบบขึ้นมา หากเราไม่เพิ่มหรือแก้ไขการตั้งค่าในส่วนใด ส่วนนั้นก็จะใช้ค่าตั้งจากคลาสต้นแบบ
  • ระบุขนาดกระดาษ
  • ระบุขนาดและแบบอักษร
ซึ่งได้ลงคอมเมนต์ไว้ในโค้ดแล้วว่าส่วนใดเป็นส่วนใดดังนี้
\NeedsTeXFormat{LaTeX2e} % ส่วนหัวที่จำเป็นสำหรับคลาส
\ProvidesPackage{kkuthesis}[2010/11/09 Khon Kaen University Thesis Class] % ชื่อคลาสและรายละเอียด

% ใช้คลาส report เป็นต้นแบบ
\LoadClass[a4paper,oneside,openbib]{report} 

% ใช้ภาษาไทย
\RequirePackage[english,thai]{babel} 
\RequirePackage{thswitch}

% ใช้ตั้งค่าหน้ากระดาษ
\RequirePackage{geometry}

% ใช้เพิ่มรูปภาพ
\RequirePackage{graphicx}

% ตั้งค่าหน้ากระดาษ
\geometry{top=1.5in,bottom=1in,left=1.5in,right=1in,headsep=0.8in}

% ตั้งค่าแบบอักษร อันที่จริงน่าจะใช้ kinnari ได้
% จะใช้แบบอักษรอังศณา จะต้องติดตั้งแบบอักษรอังศณาให้ระบบ LaTeX เสียก่อน 
\def\thairmdefault{angsa}
\usefont{LTH}{angsa}{m}{n}
\fontsize{14pt}{17pt}
\selectfont

เก็บแฟ้มนี้ไว้ในชื่อ kkuthesis.cls เวลาเรียกใช้ก็สามารถเรียกใช้คลาสนี้แทน report ได้ทันที ถึงจุดนี้สิ่งที่เราทำก็มีเพียงการตั้งค่าหน้ากระดาษและแบบอักษรเท่านั้น ในคราวต่อไปจะนำเสนอส่วนที่ใช้สร้างปก ทั้งปกนอกและปกใน ทั้งภาษาไทยและภาษาอังกฤษต่อไป

วันศุกร์ที่ 27 พฤษภาคม พ.ศ. 2554

เครื่องมือช่วยพล๊อตกราฟ

ช่วงหลายปีที่ผ่านมาผมทดลองใช้โปรแกรมสำหรับวิเคราะห์และประมวลสัญญาณแทน Matlab สลับไปสลับมาระหว่าง Octave กับ Scilab จุดด้อยของ 2 โปรแกรมนี้สำหรับคนที่คุ้นเคยกับ Matlab ก็คือการพล๊อตกราฟ กล่าวคือมันไม่ค่อยสะดวกสำหรับคนที่ชินกับระบบพล๊อตของ Matlab

หลังจากสำรวจรายการแพคเกจของ wheezy เกี่ยวกับการพล๊อตแล้วก็พบแพคเกจชื่อ plotdrop ซึ่งมีรายละเอียดน่าสนใจดังนี้ (จากรายละเอียดของแพคเกจ)
PlotDrop is designed for quick simple visualisation of 2D data series.
It is intended to be used in tandem with an external filesystem browser
such as GNOME's nautilus or KDE's konqueror. Files containing data are added
by dragging them from the browser to the file list.
อันที่จริงมีแพคเกจที่เกี่ยวกับ Data Visualization อีกเยอะเลยครับ แต่ตัวนี้มีลูกเล่นน้อยที่สุดทำให้รู้สึกว่าเรียนรู้ได้ง่ายที่สุด ก็เลยเลือกมาลองก่อน เราสามารถติดตั้งได้ทันทีโดย
# sudo apt-get install plotdrop
หากเป็นเครื่องของผมซึ่งเป็น wheezy แพคเกจนี้จะไปอยู่ในเมนูรูปภาพ (Graphic) ครับ เมื่อเรียกโปรแกรมนี้จากเมนูเราจะเห็นหน้าต่างแบบนี้
สิ่งที่เราต้องทำก็คือเอาข้อมูลให้โปรแกรมนี้ไป ข้อมูลจะต้องเป็น
  1. แฟ้มข้อความ เข้ารหัสแบบใดก็น่าจะได้ แต่ที่ผมใช้อยู่และไม่มีปัญหาคือ UTF-8
  2. ข้อมูลแยกหลัก (Column) กล่าวคือ ข้อมูล ก. อยู่หลัก 1 ข้อมูล ข. อยู่หลัก 2 ... อย่างนี้เรื่อยไป
  3. จำนวนแถว (Row) น่าจะต้องเท่ากัน ผมยังไม่เคยลองว่าถ้าจำนวนแถวไม่เท่ากันจะเกิดอะไรขึ้น
เราเรียกการจัดข้อมูลแบบนี้ว่า Delimated File และใน Octave เรามีคำสั่งที่ใช้จัดเตรียมชุดข้อมูลเพื่อพล็อตแบบนี้โดยใช้คำสั่ง dlmwrite ครับ เช่นถ้าเราต้องการพล็อตแกน x เป็นความถี่ในเวคเตอร์ f ขนาด 100x1 และแกน y เป็นความหนาแน่นสเปคตรัมกำลัง (Power Spectrum Density) P ขนาด 100x1 เช่นกัน เราจะใช้คำสั่ง dlmwrite สร้างแฟ้มข้อมูลที่ใช้กับ plotdrop ได้ดังนี้
octave> dlmwrite('mydlmfile.dlm',[f P]," ");
นี้หมายความว่า เราส่งข้อมูล f และ P ไปในเมตริกซ์เดียวกัน ส่งเข้าไปในแฟ้มข้อความธรรมดาชื่อ mydlmfile.dlm โดยที่ระหว่างข้อมูล f และ P จะคั่นด้วย Space (" ") เช่นถ้า
octave> f = [0 10 20 30]';
octave> P = [12 15 10 5]';
หน้าตาของแฟ้มข้อมูล mydlmfile.dlm จะเป็น
0 12
10 15
20 10
30 50
เราสามารถลากแฟ้มนี้ไปวางในพื้นที่ว่างในรูปข้างบนได้เลย หรือจะเรียกใช้คำสั่ง Series => Add File ... ก็ได้ เมื่อเราส่งข้อมูลให้ plotdrop ได้แล้ว เราสามารถ
  • เติมหัวเรื่อง ฉลากแกน x และฉลากแกน y ได้ในแท็ป Caption (แท็ปที่ 1)
  • เปลี่ยนขอบเขตของ x และ y ได้ในแท็ป Limits (แท็ปที่ 2)
  • เปลี่ยนหน้าตาการแสดงผลเช่น เป็นลอการิธึมในแกน x เป็นลอการิธึมในแกน y มีกริด ไม่มีกริด ฯลฯ ได้ในแท็ป Appreance (แท็ปที่ 3)
  • เพิ่มคำสั่งอื่น ๆ ในในแท็ปที่ 4 ผมยังไม่รู้ว่ามีคำสั่งพิเศษอะไรที่ใช้ได้บ้าง ตอนนี้ยังไม่จำเป็นเลยไม่ได้สนใจ
เมื่อเราเตรียมข้อมูลใน plotdrop แล้ว เราสามารถพล็อตกราฟดูได้ทันที หากเราพอใจและต้องการจะนำกราฟไปใช้ในเอกสารอื่น ๆ สามารถเก็บพล็อตลงแฟ้มได้โดย Plot => Plot to File ... ซึ่งผู้ใช้สามารถเลือกรูปแบบของแฟ้มส่งออกได้หลากหลายเช่น EPS PS LaTeX SVG PNG และอื่น ๆ สำหรับผมถ้าจะเอามาใช้กับ LibreOffice ผมก็ใช้แฟ้ม PNG นี่แหละครับ ง่ายดี

ผมพบว่าโปรแกรม plotdrop ตัวนี้ใช้ง่ายดี ช่วยให้ผมพล็อตกราฟจาก Octave เพื่อไปใช้ต่อในงานเอกสารอื่น ๆ ได้ง่าย เราสามารถเติม Caption ต่าง ๆ ได้สะดวก พล็อตดูได้ก่อน ถ้าชอบค่อยจัดลงแฟ้ม อย่างไรก็ตาม จากการทดลองใช้พบว่าในส่วนของ Caption ต่าง ๆ ยังไม่รองรับภาษาไทยครับ หากกรอกภาษาไทยลงไป เวลาพล็อตผมจะเห็นเป็นตัวเหลื่ยม ๆ แบบนี้ [] ทุกตัวอักษรไป ถ้ารองรับภาษาไทยด้วยคงจะดี

หากใครใช้แล้วมีเทคนิคอะไรจะมาแบ่งกัน ก็อย่าลืมมาบอกกันนะครับ

วันเสาร์ที่ 14 พฤษภาคม พ.ศ. 2554

แนวคิดใหม่ (ใหม่สำหรับผม) สำหรับโปรแกรมเกี่ยวกับดนตรีไทย

ผมเคยมีแนวคิด (ผมไม่ใช่คนแรกที่คิด) ที่จะพัฒนาโปรแกรมที่สามารถช่วยงานนักดนตรีไทย ให้ประพันธ์เพลงไทยได้สะดวกขึ้นดังแสดงไว้ที่ ห้องทำงาน ในตอนนั้นความรู้ภาษาไพธอนก็มีนิดเดียว ความเข้าใจเรื่องเทคโนโลยีคอมพิวเตอร์ในงานดนตรีก็มีไม่มาก

หลังจากที่ได้รู้จักกับ Chuck ที่นำเสนอไว้ในบล๊อกก่อนหน้านี้ ก็พบว่าการเขียนโค้ดไพธอนใหม่เพื่อรับผิดชอบงานทั้งหมดตั้งแต่การเขียนเพลงไปจนถึงบรรเลงเพลงดูจะเป็นงานซ้ำซ้อน (Rebuilding the wheel) โดยเฉพาะการเขียนโค้ดไพธอนให้บรรเลงเพลงได้หลาย ๆ เสียงพร้อมกัน (Concerent Programming) ซึ่งเคยมีคนทำแล้วด้วยซ้ำโดยใช้ภาษาจาวา

เมื่อใตร่ตรองดูแล้วพบว่าปัจจุบันเรามีเทคโนโลยีที่จัดการเรื่องเหล่านี้อยู่แล้ว นั่นก็คือเทคโนโลยี MIDI หมายความว่า หากเราแปลงให้เพลงไทยที่จะประพันธ์โดยใช้โน้ตไทยให้กลายเป็นแฟ้ม MIDI ได้ เราสามารถมอบหมายให้ระบบสังเคราะห์เสียง MIDI รับผิดชอบการสร้างเสียงต่าง ๆ ไม่ว่าจะเป็นเสียงสั้น เสียงยาว เสียงพร้อมกันแบบใด ๆ ก็ตาม สิ่งที่ต้องทำก็คือการสร้างระบบสังเคราะห์เสียงดนตรีไทยในระบบ MIDI ขึ้นมานั่นเอง

ในส่วนของระบบสังเคราะห์เสียงดนตรีไทยในระบบ MIDI นั้นเข้าใจว่ามีคนทำเผยแพร่อยู่มากในรูปแบบของ Soundfont จะไม่กล่าวถึงในที่นี้ แต่จะกล่าวถึงการแปลงโน้ตเพลงไทยเป็นแฟ้ม MIDI โดยใช้ไพธอนแปลงให้อยู่ในรูปโน้ต ABC และแปลงจากโน้ต ABC เป็น MIDI ในที่สุดดังนี้

*.tmn => *.abc => *.mid

นามสกุล TMN นั้นย่อมาจาก Thai Music Notation ซึ่งจะเป็นแฟ้มข้อความธรรมดาแต่มีรูปแบบการบันทึกโน้ตตามมาตรฐานของนักดนตรีไทยดังรูป
 บรรทัดแรกคือชื่อเพลง โน้ตเพลงจะเป็นแบบ 2 บรรทัดโดยให้บรรทัดแรกเป็นโน้ตสำหรับมือซ้ายและบรรทัดที่สองเป็นโน้ตสำหรับมือขวาแต่ละบรรทัดเพลงจะมี 8 ห้อง แต่ละห้องคั่นด้วยเครื่องหมาย | และเว้นหนึ่งบรรทัดเมื่อจะขึ้นบรรทัดเพลงใหม่ บันทึกแฟ้มด้วยรหัส UTF-8

ส่วนแฟ้ม ABC ก็เป็นการบันทึกโน้ตเพลงด้วยตัวอักษรเช่นเดียวกัน แต่เป็นอักษรภาษาอังกฤษ โดยให้ C = เสียงโด D = เสียงเร เรียงกันไป ระบบนี้สามารถปรับความยาวเสียงได้ รองรับเสียง # และเสียง b และเทคนิคทางดนตรีสากลอื่น ๆ เกือบครบถ้วน รายละเอียดของระบบการบันทึกโน้ตเพลงด้วยตัวอักษร ABC นี้เรียกว่า ABC Notation ตัวอย่างของแฟ้ม ABC แสดงดังรูป
ในระบบ ABC สัญลักษณ์ | หมายถึงการกั้นห้องเช่นเดียวกัน สัญลักษณ์ z หมายถึงไม่มีเสียง หากมีตัวโน้ตสองตัวอยู่ในกรอบเดียวกันเช่น [AB] หมายความว่าให้บรรเลงโน้ต ลา และ ที พร้อม ๆ กัน

ระบบการจดบันทึกเสียงดนตรีไทยของเรามีความซับซ้อนน้อยกว่า คือไม่ระบุเทคนิคการบรรเลง (เบา - ดัง) ไม่มีครึ่งเสียง # หรือ b ความยาวเสียงของแต่ละโน้ตเท่ากันหมดคือเท่ากับหนึ่งโน้ตตัวดำ (1 จังหวะ) และแต่ละห้องจะมี 4 จังหวะตายตัวเสมอ หากมีการพลิกแพลงเป็นลูกเล่นแบบใด ๆ ลูกเล่นเหล่านี้นักดนตรีมักจะเรียนกับครูโดยตรง เรียกว่าต่อเพลง หรือไม่เช่นนั้นก็พัฒนาแนวทางของตนเองขึ้นมาแบบด้นสด (Improvise) แต่จะไม่มีระบบการจดบันทึกที่เป็นมาตรฐานเดียวกัน ดังนั้นการแปลงแฟ้ม TMN ไปเป็น ABC จึงทำได้ง่าย

พื้นฐานที่ใช้คือสร้าง Empty List ขึ้นมา แล้วให้ไพธอนอ่านแฟ้ม TMN ไปทีละบรรทัด ในแต่ละบรรทัดเมื่อพบตัวอักษรก็เทียบอักษรไทยเข้ากับอักษรอังกฤษ เช่นเทียบ "ด" เป็น "C" เป็นต้น ถ้าหากตัวอักษรมีตัวเปลี่ยนขั้นเสียง เช่น ดํ จะให้หมายถึงเสียง โดสูง หรือ "c" ในระบบ ABC และ ดฺ จะให้หมายถึงเสียง โดต่ำ หรือ "C," ในระบบ ABC ดำเนินการเช่นเดียวกันกับโน้ตเพลงบรรทัดที่สอง

L1 = [];
 for i in range(len(line1)):
  if line1[i]=='|':
   L1.append('|');

  if line1[i]==':':
   L1.append(':');

  if line1[i]=='-':
   L1.append('z');

  if line1[i]==u'ด':
   if line1[i+1]==u'\u0e4d':
    L1.append('c');
   elif line1[i+1]==u'\u0e3a':
    L1.append('C,');
   else:
    L1.append('C'); 

เมื่อได้ List L1 สำหรับบรรทัดที่หนึ่งและ L2 สำหรับบรรทัดที่สองมาแล้วก็นำ List ทั้งสองมาเทียบกัน หากในจังหวะเสียงเดียวกันมีโน้ตทั้งสองบรรทัด ก็ให้บรรเลงโน้ตทั้งสองตัวพร้อมกัน ถ้ามีเพียงโน้ตตัวเดียวก็บรรเลงตัวเดียว ถ้าไม่มีโน้ตทั้งคู่ ก็ให้เงียบเสีย

L = [];
 for i in range(len(L1)):
  if L1[i]=='|':
   L.append('|');
  elif L1[i]==':':
   L.append(':');
  elif L1[i]=='z' and L2[i]=='z':
   L.append('z');
  elif L1[i]=='z' or L2[i]=='z':
   if L1[i]=='z':
    L.append(L2[i]);
   else:
    L.append(L1[i]);

  else:
   L.append('['+L1[i]+L2[i]+']');



นี่คือการแปลงโน้ตอักษรไทยไปเป็นโน้ตอักษรภาษาอังกฤษในระบบ ABC ผมตั้งชื่อโปรแกรมนี้ว่า tmn2abc (Thai Music Notation to ABC) เรียกใช้ดังนึ้

# python tmn2abc test.tmn test.abc

หลังจากนี้เราสามารถใช้เครื่องมือที่มีอยู่แล้วคือโปรแกรม abc2midi แปลงจากแฟ้ม ABC นี้ให้เป็น MIDI ได้ทันที

# abc2midi test.abc -o test.mid

สิ่งที่ต้องการจะทำเพิ่มเติมคือ
  1. รองรับระบบโน้ตบรรทัดเดียว สำหรับโน้ตซอ โน้ตขลุ่ย ฯลฯ
  2. เพิ่มการระบุชั้นเพลง คือ หนึ่งชั้น สองชั้น สามชั้น
  3. เพิ่มส่วนกำหนดเครื่องดนตรี แต่เรื่องนี้ต้องศึกษามาตรฐาน MIDI เกี่ยวกับการกำหนดช่องสัญญาณและโปรแกรมเพิ่มเติม
ก่อนหน้านี้เคยเขียนโปรแกรมนี้ไว้แล้ว แต่ตอนสำรองข้อมูลก่อนลงระบบใหม่เมื่อตอนทดสอบ Ubuntu ไม่สมบูรณ์ โปรแกรมทั้งชุดจึงหายไปหมด ตอนนี้เขียนใหม่แล้วเลยอัพโหลดไว้เสียเลย ท่านใดสนใจสามารถดูต้นฉบับโปรแกรมได้ sourceforge.net ครับ หากมีปัญหาหรือข้อแนะนำใด ๆ หากจะทิ้ง Comment ไว้ที่ Blog นี้ได้ก็จะขอขอบคุณล่วงหน้าครับ

วันเสาร์ที่ 23 เมษายน พ.ศ. 2554

ฆ้อง MIDI ด้วย Chuck

แนวคิดหนึ่งที่อยากทำมานานก็คือพัฒนาโปรแกรมที่ช่วยให้นักดนตรีไทยประพันธ์เพลงได้สะดวกขึ้น ทางหนึ่งที่ทำได้ก็คือเขียนโปรแกรมรับข้อมูล MIDI จากคีย์บอร์ด แล้วสังเคราะห์เสียงตามคำสั่ง

Chuck มีความสามารถในการสื่อสารกับเครื่องดนตรีอิเล็กทรอนิกส์ทาง MIDI โดยใน Chuck จะมีคลาส MIDI ในตัว การเรียกใช้ความสามารถทาง MIDI ใน Chuck ทำได้ดังตัวอย่าง (จาก Official Chuck Tutorial)

MidiIn min;
MidiMsg msg;

// open midi receiver, exit on fail
if ( !min.open(0) ) me.exit(); 

while( true )
{
    // wait on midi event
    min => now;

    // receive midimsg(s)
    while( min.recv( msg ) )
    {
        // print content
     <<< msg.data1, msg.data2, msg.data3 >>>;
    }
}

จากการทดลองพบว่า
  • msg.data1 คือข้อมูล Channel และคำสั่ง MIDI อื่น ๆ เช่น Note-On, Note-Off
  • msg.data2 คือขั้นเสียง
  • msg.data3 คือความดัง (Velociy)
เราสามารถใช้ msg.data# มาควบคุมการสังเคราะห์เสียงของ Chuck ที่เราทำไว้เมื่อคราวก่อนได้ดังนี้

MidiIn min;
MidiMsg msg;
min.open(0) => int AmIOpen;

if(!AmIOpen)
{
 <<< "Can not Open MIDI Input Port" >>>;
 me.exit();
}else
{
 while(true)
 {
  min => now;
  while(min.recv(msg))
  {
   <<< msg.data1,msg.data2,msg.data3,"MIDI Message">>>;
   if(msg.data3!=0)
   {
    if(msg.data2==59)
    {
     Machine.add("gong01.ck");
    }
    if(msg.data2==60)
    {
     Machine.add("gong02.ck");
    }
   }
  }
 }
}

เราใช้ msg.data# เป็นเงื่อนไขให้ Chuck เพิ่ง shred ของฆ้องแต่ละลูกเข้าไปใน Chuck ได้ด้วยคำสั่ง

Machine.add("gong01.ck");

เมื่อ gong01.ck gong02.ck ... เป็นสคริปต์สังเคราะห์เสียงฆ้องแต่ละลูก แต่นี่หมายความว่าที่เครื่องคอมพิวเตอร์จะต้องรัน Chuck อยู่แล้วด้วยคำสั่ง

# chuck --loop

ด้วยวิธีนี้ Chuck จะเป็นคนจัดการเรื่องการสังเคราะห์เสียงหลาย ๆ เสียงพร้อม ๆ กันได้เอง เราไม่ต้องเขียนโปรแกรมขึ้นมาใหม่เลย นั่นหมายความว่าหากเราสามารถสร้างสคริปต์สังเคราะห์เสียงเครื่องดนตรีไทยชนิดต่าง ๆ ได้ ชุดโปรแกรมชุดนี้ก็สามารถรับสัญญาณ MIDI มาตรฐานจากโปรแกรมทั่ว ๆ ไปและสร้างเสียงดนตรีไทยทั้งวงได้ทันที

วันพฤหัสบดีที่ 21 เมษายน พ.ศ. 2554

การสังเคราะห์เสียงด้วย Chuck

ก่อนหน้านี้ได้ลองใช้ Puredata (pd) สังเคราะห์สัญญาณ Decay Sinusoid ซึ่งมีลักษณะเสียงคล้ายเสียงฆ้อง ตั้งใจว่าจะใช้สังเคราะห์เสียงดนตรีไทย แต่ว่าการใช้งาน Python ร่วมกับ Puredata แม้ว่าจะทำได้ แต่ดูเหมือนว่าจะทำได้ยาก เนื่องจากมีเอกสารกำกับน้อย น่าจะเหมาะกับคนที่ใช้ Python จนคล่องแคล่วแล้วมากกว่า

ผมก็เลยกลับมาพิจารณา Chuck อย่างจริงจังอีกครั้งหนึ่งหลังจากที่ได้เอาคู่มือมาพลิกผ่าน ๆ เมื่อหลายเดือนก่อนพบว่าน่าจะสามารถใช้งานร่วมกับ Python ได้ง่ายกว่า

Chuck คืออะไร
Chuck คือ Real-Time Audio Programming Language สำหรับงานสังเคราะห์และเรียบเรียงเสียงสังเคราะห์ โปรแกรมที่เขียนด้วย Chuck จะรันใน Chuck Virtual Machine ที่มีความสามารถในการรันหลาย ๆ โปรแกรม (Shred) ได้พร้อม ๆ กัน และแต่ละ Shred ก็สามารถสื่อสารเพื่อประสานงานกันได้ ท่านที่สนใจสามารถอ่านรายละเอียดเพิ่มเติมได้ที่ http://chuck.cs.princeton.edu/ และ http://kijjaz.exteen.com/20070702/entry (ภาษาไทย)

ตัวอย่างสคริปต์ที่รันใน Chuck

SinOsc s => dac;
440 => s.freq;
0.5 => s.gain;
2::second => now;

สคริปต์ข้างต้นนี้จะกระทำ 2 สิ่งคือ ต่อไซนูซอยด์ออสซิลเลเตอร์ (s) เข้ากับซาวด์การ์ด (dac) ตั้งค่าความถี่และขนาดสัญญาณเป็น 440 เฮิรทซ์และ 0.5 ตามลำดับ จากนั้นให้เวลาในสคริปต์เดินหน้าไป 2 วินาทีส่งผลให้เกิดเสียงขึ้น 2 วินาที

เรื่องเวลานี่ทีแรกผมไม่เข้าใจ แต่ถ้าเราเปรียบเทียบกับการเดินหน้าเส้นเทปไป 2 วินาทีก็จะเข้าใจง่ายขึ้น สัญญาณเสียงนั้นอยู่ในเทปอยู่แล้ว แต่ถ้าเส้นเทปไม่เดินผ่านหัวเทปก็จะไม่เกิดเสียงขึ้น

หลังจากเขียนสคริปต์เสร็จแล้วก็บันทึกไว้ในแฟ้มชื่อ foo.ck ก็ได้ (ตามขั้นตอนใน Tutorial เป๊ะ ๆ) ถ้าจะให้ Chuck ทำงานก็เรียกคำสั่ง

# chuck foo.ck

ก็จะได้ยินเสียงไซนูซอยด์ดังออกมาจากลำโพง

นอกจากนี้โปรแกรม Chuck ยังมี Built-in ฟังก์ชันและออบเจกต์ที่ใช้ประมวลผลสัญญาณเสียงอีกมากมาย ที่ใช้บ่อย ๆ ก็คงจะเป็นพวกตัวกรองต่าง ๆ ในงานที่ผมใช้สังเคราะห์เสียง Decay Sinusoid ที่มีเสียงคล้ายเสียงฆ้องนั้น เมื่อพิจารณาแล้วสามารถใช้ตัวกรองแบบ Bi-Quad ได้ การใช้ตัวกรอง Bi-Quad ใน Chuck สามารถทำได้ดังนี้

Impulse i => BiQuad f => dac;
0.000 => f.b0;
0.04128430 => f.b1;
0.000 => f.b2;
1.0000 => f.a0; 
-1.99824581 => f.a1;
0.99995098 => f.a2;

0.3 => i.next;
5::second => now;

ในสคริปต์นี้
  • บรรทัดแรกจะเรียกใช้ออบเจกต์อิมพัลส์และเชื่อมต่ออิมพัลส์เข้ากับตัวกรอง Bi-Quad และต่อเอาต์พุตจาก Bi-Quad เข้ากับซาวด์การ์ดของเรา 
  • บรรทัดที่ 2 - 7 ระบุค่า Coefficient ของตัวกรองทั้ง 6 ตัว 
  • บรรทัดที่ 8 ระบุขนาดของอิมพัลส์ที่จะส่งเข้าตัวกรอง
  • บรรทัดที่ 9 ระบุช่วงเวลาที่จะให้ Chuck ส่งเสียงออกมา
นี่คือเสียงสังเคราะห์ของฆ้องวงเล็กลูกแรก ผมบันทึกแฟ้มเป็น gong01.ck ถ้าต้องการให้ Chuck สร้างเสียงฆ้องลูกนี้ก็เรียกใช้คำสั่ง

# chuck gong01.ck

ก็จะได้ยินเสียงคล้าย ๆ เสียงฆ้องดังออกมา

จากที่ทดลองพบว่าการใช้ Chuck นั้นง่ายพอ ๆ กับ puredata แต่ว่าถ้าคิดถึงการเชื่อมต่อกับโปรแกรมอื่น ๆ เพื่อให้ทำงานร่วมกันหลังฉากโดยไม่ต้องให้ผู้ใช้งงกับหน้าต่างมาก ๆ โปรแกรม Chuck ดูเหมือนจะเป็นทางเลือกที่ดีกว่า ต่อไปนี้ก็จะลองใช้ Chuck เพื่อสังเคราะห์เสียงอื่น ๆ ต่อไปดู

วันอังคารที่ 5 เมษายน พ.ศ. 2554

ติดตั้งเครื่องพิมพ์ Canon LBP3050 บน Debian (wheezy)

[ T_T สุดท้ายก็ไม่สามารถพิมพ์ภาพได้ครับ นอกจากนี้เมื่อตอนทดสอบยังไม่ได้ทดสอบกับภาษาไทย พอทดสอบกับภาษาไทยก็ยิ่งแย่ ตัวหนังสือตีกันไปหมด ตอนนี้ยกธงขาวแล้ว แฟนจะเหน็บก็ต้องยอมแล้วล่ะ]

ที่บ้านมีเครื่องพิมพ์อยู่เครื่องหนึ่งคือ Canon LBP3050 เป็นของแฟน พอจัดห้องทำงานที่บ้านใหม่แฟนก็ยกเครื่องพิมพ์เครื่องนี้ให้ แต่ว่าเวลาเอามาใช้กับเครื่องคอมพ์ของผมดันพิมพ์งานไม่ออก!! ทั้ง ๆ ที่ Linux ตรวจเจอเครื่องพิมพ์

งานเข้าล่ะครับ เพราะแฟนผมชอบเหน็บให้เจ็บใจเล่น ๆ เวลาที่ Linux ทำอะไรบางอย่างไม่ได้ในขณะที่ Windows ของเธอทำได้ (ผมก็เหน็บเธอเหมือนกันเวลาที่ Windows ทำอะไรบางอย่างไม่ได้ในขณะที่ Linux ทำได้ ก็เจ๊ากันไปนะ ฮิ ฮิ)

ผมพบว่าระบบตรวจจับเครื่องพิมพ์อัตโนมัติของ Linux ใช้ไม่ได้กับเครื่องพิมพ์บางจำพวก และเจ้า Canon LBP3050 เครื่องนี้ก็เป็นหนึ่งในนั้นครับ ในกรณีของ Canon LBP3050 นั้นผมคิดว่าเป็นเพราะ LBP3050 เป็นเครื่องพิมพ์ที่ใช้เทคโนโลยี CAPT - Canon Advanced Printing Technology ซึ่งทาง Canon โฆษณาว่าสามารถพิมพ์งานได้เร็ว และพิมพ์งานที่ขนาด (หน่วยความจำ) ใหญ่ได้โดยไม่ต้องเพิ่มหน่วยความจำ ... เอาเถอะ ... จะเป็นอะไรก็ช่าง เอาเป็นว่าถ้าจะใช้เครื่องพิมพ์ตระกูล CAPT จะต้องมี CAPT Driver ไม่ว่าจะเป็นบน Linux Mac หรือ Windows ก็ตาม ทีนี้ในระบบ Linux เราใช้ CUPS - Common UNIX Printing Solution ก็แปลว่าเจ้า CAPT Driver ที่ว่าจะต้องคุยกับ CUPS ให้รู้เรื่อง และการทำให้มันคุยกันรู้เรื่อง ก็ต้องใช้การติดตั้งที่ถูกต้องจึงจะสำเร็จ

การติดตั้งมีด้วยกัน 4 ขั้นตอนคือ
  1. จัดหาแพคเกจที่จำเป็น
  2. ติดตั้งแพคเกจดังกล่าว
  3. ติดตั้งเครื่องพิมพ์ลงบน CUPS
  4. ผูกเครื่องพิมพ์เข้ากับ Service ccpd
  5. ใช้ insserv สั่งให้เริ่มบริการ ccpd โดยอัตโนมัติทุกครั้งที่มีการเริ่มระบบใหม่
  6. เรียกใช้ ccpd เพื่อใช้งานเครื่องพิมพ์
รายละเอียดการติดตั้งมีอยู่ในแฟ้มเอกสารที่มาพร้อมกับแพคเกจที่จำเป็น แต่จะขอบันทึกไว้เผื่อว่าจะได้ใช้ในภายหลัง โดยจะเขียนอธิบายตามรายการข้างต้นไปทีละข้อ ๆ

จัดหาแพคเกจที่จำเป็น
ดาว์นโหลดได้ที่เว็บไซต์ Canon ออสเตรเลียเลยครับ (ค้น ๆ ดูมีที่สิงค์โปร์ด้วย ส่วนเมืองไทยไม่มีนะครับ) แฟ้มที่โหลดได้คือ CAPT_Printer_Driver_for_Linux_v220_uk_EN.tar.gz ขนาดประมาณ 33 MB
เมื่อได้มาแล้วก็แตกแฟ้มไว้ที่ไหนสักแห่ง ซึ่งต่อไปจะขอเรียกไดเรคทอรีนี้ว่า #Canon เพื่อความสะดวก

ติดตั้งแพคเกจดังกล่าว
เมื่อแตกแฟ้มแล้วจะพบแพคเกจ
  • cndrvcups_common_2.20-1_i386.deb  และ
  • cndrvcups_capt_2.20-1_i386.deb
อยู่ในไดเรคทอรี #Canon/CAPT_Printer_Driver_for_Linux_v220_uk_EN/32-bit_Driver/Debian ติดตั้งแพคเกจตามลำดับที่แสดงไว้ข้างต้น โดยใช้ GDebi หรือ dpkg ก็ได้ ในกรณีของผมเองปัจจุบันใช้ Debian wheezy อยู่ จะขาดแพคเกจที่จำเป็นไปหนึ่งแพคเกจคือ gs-eps ผมก็แก้ไขโดยการเพิ่ม Repository ของ squeeze ลงไปใน sourcelist ก็พบแพคเกจ gs-eps ซึ่งเป็น Transition Package อยู่ ติดตั้งแพคเกจนี้เข้าไปก็ใช้ได้แล้ว

ติดตั้งเครื่องพิมพ์ลงบน CUPS
เมื่อติดตั้งแพคเกจทั้งสองเสร็จสิ้นให้เริ่ม CUPS ใหม่ซึ่งทำได้โดยใช้คำสั่ง

# /etc/init.d/cups restart

จากนั้นก็เพิ่มเครื่องพิมพ์ลงในคิวของ CUPS ด้วยคำสั่ง

#  lpadmin -p LBP3050 -m CNCUPSLBP3050CAPTK.ppd -v ccp://localhost:59687 -E

เมื่อข้อมูลหลังตัวเลือกต่าง ๆ มีความหมายดังนี้
  • -p [Printer Name] ระบุชื่อที่ระบบเราจะใช้เรียก จะตั้งว่าอะไรก็ได้
  • -m [ppd file] ระบุแฟ้ม ppd ที่เป็นตัว Driver ของเครื่องพิมพ์ของเรา ในรายละเอียดการติดตั้งที่ให้มาพร้อมกับแพคเกจจะบอกว่าเครื่องพิมพ์ของเราจะต้องใช้แฟ้ม ppd ตัวไหน ส่วนรายการเครื่องพิมพ์สำหรับ wheezy จะอยู่ที่ /usr/share/cups/model
  • -v [Device URI] ระบุ URI ที่เราจะให้เป็นทางผ่านข้อมูลสำหรับเครื่องพิมพ์ของเรา URI ที่เขียนไว้ตรงนี้ลอกมาจากรายละเอียดการติดตั้ง จากที่ค้น ๆ ดู ในกรณีทั่ว ๆ ไป ใคร ๆ ก็ใช้ URI นี้ มีบางกรณีของ UBUNTU ที่จะใช้ URI เป็น FIFO0 อันนี้ยังไม่ได้ลองว่าใช้ได้หรือไม่
  • -E เป็นการสั่ง Enable เครื่องพิมพ์
กระบวนการทั้งหมดนี้น่าจะสามารถทำด้วย GUI ได้ด้วย ระบบ->ดูแลระบบ->เครื่องพิมพ์ เพื่อเรียกเครื่องมือตั้งค่าเครื่องพิมพ์ของ GNOME โดยที่ตัวเลือก -E ข้างหลังสุดของคำสั่งนั้นคือการ Enable เครื่องพิมพ์นั่นเอง [ยังไม่ได้ลอง]

หลังจากนี้ถ้าเราเปิดเครื่องมือการตั้งค่าเครื่องพิมพ์ของ GNOME ดู ควรจะเห็นเครื่องพิมพ์ของเราปรากฏอยู่ในรายการด้วย ดังเช่นที่แสดงในรูปนี้ (เราต้องรู้ชื่อของเครื่องพิมพ์ของเรา เพราะเราเป็นคนตั้งชื่อเองด้วยตัวแปรหลังตัวเลือก -p ของคำสั่ง lpadmin)
ตอนนี้ยังใช้เครื่องพิมพ์ไม่ได้นะครับ 
[ตามความเข้าใจของผม] เพราะเราใช้ CAPT ซึ่งมีการ "ยำ" ข้อมูลก่อนส่งออกเครื่องพิมพ์ ดังนั้นถ้าเราส่งไปตรง ๆ เหมือนส่งเข้าเครื่องพิมพ์ประเภทอื่น ๆ เครื่องพิมพ์ก็จะไม่เข้าใจ จึงจำเป็นต้องมีข้อต่อไป

ผูกเครื่องพิมพ์เข้ากับ Service ccpd 
ซึ่งทำได้โดย

# ccpdadmin -p LBP3050 -o /dev/usb/lp0

นี่เป็นการบอก ccpd ว่าเครื่องพิมพ์ CUPS ชื่อ LBP3050 นั้นต่ออยู่กับช่องทางไหน ทีนี้ในคู่มือการติดตั้งเตือนไว้เหมือนกันว่า ถ้ามีเครื่องพิมพ์ USB หลายเครื่อง ลำดับก่อนหลังของ lp จะเรียงตามลำดับการต่อเครื่องพิมพ์เข้ากับคอมพิวเตอร์ ในอินเตอร์เนตมีคำแนะนำการตั้งค่าบริการ ccpd ให้ตั้งค่าเองเมื่อเสียบสาย USB ของเครื่องพิมพ์เข้ากับคอมพิวเตอร์ (แต่เป็นของ UBUNTU นะ) พอดีผมมีเครื่องพิมพ์เครื่องเดียวและต่ออยู่ตลอดเลยไม่สนใจสถานการณ์ที่ว่านี้

หลังจากนี้ ถ้าเริ่มบริการ ccpd ก็จะสามารถพิมพ์ได้เลย การเริ่มบริการ ccpd ทำได้โดย

# /etc/init.d/ccpd start

หรือไม่ก็ใช้ ระบบ->ดูแลระบบ->บริการระบบ เริ่มบริการ ccpd ก็ได้ ถ้าอยากให้บริการ ccpd เริ่มเองทุกครั้งก็ไปขั้นตอนถัดไป

ใช้ insserv สั่งให้เริ่มบริการ ccpd โดยอัตโนมัติทุกครั้งที่มีการเริ่มระบบใหม่
ในการนี้เราจะต้องแก้ไขแฟ้ม /etc/init.d/ccpd โดยการเพิ่มคอมเมนต์ต่อไปนี้เข้าไปในบรรทัดที่สามของ ccpd คอมเมนต์ที่จะเติมนี้ขอแนะนำว่าให้ไปคัดลอกจากต้นฉบับที่คู่มือการติดตั้ง ซึ่งอยู่ใน #Canon/CAPT_Printer_Driver_for_Linux_v220_uk_EN/Doc โดยตรงจะดีที่สุด

### BEGIN INIT INFO
# Provides:         ccpd
# Required-Start:   $local_fs $remote_fs $syslog $network $named
# Should-Start:     $ALL
# Required-Stop:    $syslog $remote_fs
# Default-Start:    3 5
# Default-Stop:     0 1 2 6
# Description:      Start Canon Printer Daemon for CUPS
### END INIT INFO
ผมก็สงสัยว่ามันเป็นคอมเมนต์ แล้วไปเติมมันทำไม เลยเข้าไปอ่านรายละเอียดของ insserv จึงได้ทราบว่าเจ้า insserv นี่จะเข้าไปอ่านคอมเมนต์ในสคริปต์แล้วเติมบริการนี้เข้าไปในรายการที่จะต้องเริ่มอัตโนมัติตอนเริ่มระบบ แต่ว่าแค่เติมคอมเมนต์นี่เข้าไปยังไม่พอ จะต้องเรียกคำสั่ง

# insserv ccpd

ด้วย ในระบบของผมมี Warning ขึ้นมานิดหน่อย แต่อ่าน ๆ ดูแล้วคิดว่าไม่สำคัญมาก ก็ปล่อยผ่านไป ทีนี้ถ้าท่านค้นข้อมูลจากอินเตอร์เนตท่านอาจจะพบวิธีการแก้ไขสคริปต์ที่ว่านี้หลาย ๆ แบบ ผมก็ลองแล้วปรากฏว่าไม่เวิร์ก อาจจะด้วยหลาย ๆ เหตุผล เช่นผมคัดลอกสคริปต์มาไม่สมบูรณ์หรืออะไรก็สุดแท้แต่ สุดท้ายผมมาใช้สคริปต์ต้นฉบับตามคู่มือของ Canon เองนั่นแหละ ถึงได้พิมพ์ได้ในที่สุด

ถึงขั้นตอนนี้ถ้าทั้ง cups และ ccpd กำลังทำงานอยู่ เราก็สามารถพิมพ์งานได้เลย

ระบบ CAPT ให้เครื่องมือกับเรามาอีก 2 อย่างก็คือ
  • captstatusui และ
  • cngplp (ผมเดาว่าคงจะเป็น Canon General Purpose lp)
# captstatusui -P LBP3050

สั่งงานพิมพ์จากบรรทัดคำสั่ง (แทน lpr) ได้โดย

# cngplp -p [Filename to be printed]


หมายเหตุ
ในคู่มือระบุว่าระบบ CAPT จะทำงานได้สมบูรณ์จำเป็นจะต้องติดตั้ง libstdc++5 เสียก่อน แม้ว่าระบบของผมมี libstdc++6 อยู่แล้ว แต่เพราะผมไม่ทราบแน่ชัดว่าใช้ได้หรือไม่ จึงติดตั้ง libstdc++5 ลงไปอยู่ดี

ที่พิมพ์ได้ตอนนี้คือ PS PDF และ ODT ที่ไม่มีรูปภาพ :o ตอนนี้กำลังหาทางอยู่ว่าถ้าจะพิมพ์รูปด้วยจะต้องทำอย่างไร :(

ที่ต้องลำบากลำบนขนาดนี้ เป็นเพราะว่าต้องพยายามใช้เครื่องที่มีอยู่ในเกิดประโยชน์ หากเป็นการพิจารณาซื้อเครื่องใหม่ ท่านอาจมีตัวเลือกที่สะดวกกว่าโดยเฉพาะเครื่องพิมพ์ที่มีรายการ Driver อยู่ใน CUPS อยู่แล้วเป็นต้น