แสดงบทความที่มีป้ายกำกับ Android แสดงบทความทั้งหมด
แสดงบทความที่มีป้ายกำกับ Android แสดงบทความทั้งหมด

วันพฤหัสบดีที่ 18 ตุลาคม พ.ศ. 2555

สังเคราะห์เสียงฆ้องบน Android ด้วย libpd ตอนที่ 1

หลังจากหัดเขียนโปรแกรมบน Android และทดลองเขียนโปรแกรมฆ้องวงขึ้นมา ก็รู้สึกถึงข้อจำกัดของการใช้เสียงฆ้องที่บันทึกไว้ล่วงหน้าซึ่งก็คือ
  1. มีข้อจำกัดด้านคุณภาพของการบันทึกเสียงและ
  2. ไม่สามารถปรับค่าความถี่และอัตราลดทอนของเสียงได้
แต่การสังเคราะห์เสียงโดยใช้ภาษา Java โดยตรงดูจะไม่ใช่ทางเลือกที่ดีนัก ยิ่งไม่ใช่ทางเลือกที่ดีสำหรับคนที่ไม่เชี่ยวชาญ Java อย่างผม หลังจากที่เสาะหากรรมวิธีเหมาะ ๆ ได้สักพักก็เจอเครื่องมือด้านการสังเคราะห์เสียงจำนวนหนึ่งคือ
ผมได้ทดลองใช้ Chuck กับ Python เพื่อสังเคราะห์เสียงบน Linux ดูแล้วก็ใช้งานได้สะดวกดี แต่ Chuck ไม่มีเครื่องมือที่จะเชื่อมต่อกับ Java และ Android (หรือมีแต่ผมหาไม่เจอ) ส่วน Csound นั้นผมไม่เคยใช้ ค้นดูก็ไม่เจอเครื่องมือที่จะเชื่อมต่อกับ Java และ Android เช่นกัน

สำหรับ puredata นั้นเดิมผมเคยยอมแพ้มันมาแล้วหนหนึ่งด้วยเหตุว่าเขียนแพตช์ (Patch) ของ puredata ไปแล้วก็เอาไปใช้ในโปรแกรมอื่นเหมือน Chuck ไม่ได้...จนกระทั่งผมได้พบกับ libpd จึงได้ทราบว่าผมคิดผิด

อันที่จริง puredata สามารถสื่อสารกับภาษาโปรแกรมอื่น ๆ ได้ผ่านทาง libpd ขั้นตอนการพัฒนาโปรแกรมโดยใช้ libpd จะเป็นดังนี้
  1. ผู้พัฒนาจะสร้างแพตช์ puredata ขึ้นมาก่อน โดยกำหนดชื่อตัวแปรควบคุมไว้แทนอินเลต
  2. เปิดแพตช์ที่สร้างขึ้นจากคำสั่ง openPatch
  3. ส่ง Bang Float Message ผ่านคำสั่ง sendBang sendFloat และ sendMessage ไปยังแพตช์เป้าหมายตามลำดับ
เนื่องจากมีขั้นตอนที่เกี่ยวข้องแยกเป็น 2 ส่วนใหญ่ ๆ ที่ไม่เกี่ยวข้องกันก็คือส่วนการสังเคราะห์เสียงด้วย pd เป็นส่วนหนึ่ง และการตั้งค่าและเรียกใช้ libpd ในแอนดรอยด์เป็นอีกส่วนหนึ่ง ในตอนนี้จึงขอบันทึกไว้เฉพาะส่วนการสังเคราะห์เสียงก่อน

การสังเคราะห์เสียงฆ้องด้วย pd
จากการวิเคราะห์เสียงฆ้องในเบื้องต้นพบว่าคุณลักษณะพื้นฐานที่โดดเด่นของเสียงฆ้องคือองค์ประกอบ Exponentially Decayed Sinusoid ซึ่งสามารถสร้างได้โดยแพตช์ดังแสดงในรูป
andgong.pd
อินเลตของแพตช์นี้จะเป็นค่าความถี่ของลูกฆ้อง เมื่อมี float เข้ามาทางอินเลต bang จะถูกกระตุ้นและจะสร้างอาเรย์ของตัวแปรเวลา t ขึ้นมา ตัวแปรเวลานี้จะคูณเข้ากับอัตราการลดทอนของเสียงฆ้องซึ่งในที่นี้เป็น -2 เมื่อข้อมูลนี้ผ่านออบเจ็กต์ [exp~] ก็จะเป็นฟังก์ชัน
amath f(t)=e^{-2t} endamath
ส่วนตัวเลขความถี่ที่ป้อนเข้ามาแต่แรกก็จะไปกระตุ้น [osc~] เพื่อให้สร้างสัญญาณไซนูซอยด์ออกมา เมื่อนำมาคูณกับเอกโพเนนเชียลในตอนแรกและคูณกับ 0.3 ก่อนส่งออกทางเอาต์เลตจะทำให้ได้ฟังก์ชัน
amath g(t) = 0.3 e^{-2t} cos(2\pi f t) endamath
จะเป็นเสียงฆ้องลูกทวนหรือว่าลูกยอดก็แล้วแต่ว่าความถี่ที่ป้อนเข้าทางอินเลตนั้นเป็นเท่าใด

แต่ [timearray] ไม่ใช่ออบเจกต์มาตรฐานของ pd แต่เป็นออบเจกต์ที่ผมสร้างขึ้นมาเองเพื่อสร้างตัวแปร t ที่วิ่งจาก 0 ถึง 5000 ในเวลา 5 วินาที (ขั้นละ 1 มิลลิวินาที) ทุกครั้งที่มีการกระตุ้นออบเจกต์ด้วย [bang( ซึ่งกลไกของ [timearray] แสดงดังรูปต่อไปนี้
timearray.pd
เมื่อมี [bang( เข้ามาทางอินเลต ข้อความ 0 จะถูกกระตุ้นเพื่อส่งให้ [line~] กระโดดจากค่าใด ๆ ก็ตามขณะนั้นไปที่ [0( ทันที หลังจากนั้น 1 มิลลิวินาที [bang( ที่ถูกหน่วงเวลาไว้ก็จะกระตุ้นข้อความ [5 5000( เพื่อส่งให้ [line~] ทำให้เอาต์พุตของ [line~] เปลี่ยนแปลงจาก 0 ไปเป็น 5 ภายในเวลา 5000 มิลลิวินาที นั่นหมายความว่าเอาต์เลตของแพตช์นี้ก็คือค่าเวลาเป็นวินาทีขั้นละ 1 มิลลิวินาทีเป็นเวลา 5 วินาทีนั่นเอง

เนื่องจาก libpd อนุญาตให้มีแพตช์ Instance เดียว เราก็เลยต้องสร้างลูกฆ้องทั้ง 16 ลูกในแพตช์โดยให้ฆ้องแต่ละลูกถูกกระตุ้นโดยตัวแปร h01 - h16 ด้วยตัวเลขค่าความถี่
gongwong.pd
แม้ว่าจะตีฆ้องทีละลูกหรืออย่างมาก 2 ลูก เพื่อให้การเชื่อมต่อสัญญาณกับ [dac~] ไม่ติดขัดเพราะเชื่อมกับอินพุตมากเกินไปเราเลยใช้ [+~] รวมสัญญาณจากฆ้องแต่ละลูกเข้าด้วยกัน แต่ Hot Inlet คืออินเลตทางซ้ายเท่านั้น เราเลยต้องให้ตัวแปรความถี่ลูกฆ้องลูกที่ 2 - 16 กระตุ้น [bang( เพื่อกระตุ้น Hot Inlet ของ [+~] ตัวแรกด้วย นอกจากนี้ก่อนจะส่งสัญญาณเสียงออกมาทาง [dac~] เราจะป้องกันองค์ประกอบไฟตรง (DC Component) โดยใช้ตัวกรองความถี่สูงผ่าน [hip~] โดยตั้งค่าความถี่ตัดไว้ที่ 1 เฮิร์ทซ และป้องกันการทำงานผิดพลาดของ libpd โดยการขริบสัญญาณขาออกไว้ให้ไม่เกิน +/- 1

เราสามารถทดสอบแพตช์ gongwong.pd ใน puredata ได้โดยการเปลี่ยน [r h01] ถึง [r h16] ให้เป็นข้อความ [xxx01( - [xxx16( รวม 16 ข้อความเมื่อ xxx01 - xxx16 คือค่าความถี่เสียงที่เราต้องการ และทดลองฟังเสียงโดยการคลิ๊กที่ข้อความแต่ละข้อความนั้น ๆ

เมื่อเราเตรียมแพตช์ของเราเรียบร้อยแล้ว ในตอนต่อไปเราจะมาดูว่าจะสามารถเรียกใช้แพตช์นี้ผ่าน libpd เพื่อเขียนโปรแกรมสำหรับแอนดรอยด์ได้อย่างไร

วันพุธที่ 22 สิงหาคม พ.ศ. 2555

ดูภาพหน้าจอของ Android Tablet บน PC

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

Tablet เครื่องนี้มีข้อโดดเด่นอยู่อย่างหนึ่งคือมีช่องต่อพ่วงอุปกรณ์ครบ มี USB ใหญ่ USB เล็ก HDMI 3.5 mm Audio Jack SD Card ขาด VGA ก็จะใช้เป็นคอมพิวเตอร์เครื่องหนึ่งได้แล้ว

แต่คงเพราะเป็น Tablet จึงมีปุ่มควบคุมอยู่น้อย มีปุ่ม Volume ปุ่มเรียกเมนู และปุ่ม ESC แค่นี้ ที่เหลือต้องควบคุมผ่านหน้าจอระบบสัมผัสทั้งหมด

อะไรจะเกิดขึ้นถ้ามีอุบัติเหตุทำให้การตั้งค่าความสว่างหน้าจอเป็นศูนย์!??

จอมันก็มืดสิครับ ผมเคยเจอปัญหานี้หนหนึ่งเมื่อสักสองวันก่อนนี่เอง คือไปลงโปรแกรมประหยัดแบตเตอรีแล้วอ่าน UI ไม่เข้าใจไปตั้งค่าให้ประหยัดพลังงานโดยปิดหน้าจอ มืดสนิทไปหมด เราก็นึกว่าเครื่องดับเลย Reset มันซะ ปรากฏว่าเครื่องก็ Restart ตามปกตีมี Splash Screen มาตามลำดับ ๆ พอจบลำดับจอก็มืดเหมือนเดิม เพราะโปรแกรมประหยัดแบตเตอรีมันคุมไว้ ทำไงดีล่ะทีนี้

ก็เลยคิดว่ามันน่าจะมีการควบคุม Android Tablet ผ่าน PC ได้สักทางล่ะน่า หลังจากค้นหาอยู่ไม่นาน (Thank you Google!) ก็พบหน้าเว็บนี้ครับ How to Remote View and Control Your Android Phone ซึ่งอธิบายว่าเราสามารถดูภาพหน้าจอของ Android Tablet ได้โดยใช้เครื่องมือ 3 อย่างคือ
  1. โปรแกรม ADB ซึ่งได้จาก Android SDK อยู่ในไดเรคทอรีย่อย platform-tools
  2. สาย USB
  3. โปรแกรม Androidscreencast ซึ่งเป็นโปรแกรมภาษาจาวา
ขั้นตอนก็ขอเรียบเรียงเป็น 2 ส่วนนะครับ คือส่วนเตรียมการและส่วนใช้งาน ส่วนเตรียมการคือทำหนเดียวแล้วไม่ต้องทำอีก ส่วนใช้งานก็คือทำทุกครั้งที่ใช้งาน

ส่วนเตรียมการ
  • ติดตั้ง JAVA JRE เวอร์ชัน 5 ขึ้นไป ถ้ายังไม่มี (แต่น่าจะมีกันหมดแล้วล่ะมั้ง) เอาไว้รันโปรแกรม Androidscreencast
  • ติดตั้ง Android SDK รุ่นล่าสุด เพื่อจะได้ใช้ ADB ได้
  • ติดตั้งโปรแกรม Androidscreencast โดยการดาวน์โหลดโปรแกรมมาแล้วเก็บไว้ที่ใดสักที่หนึ่งที่ไม่เกะกะ ตรงไหนก็ได้ครับผมเก็บไว้ใน platform-tools นั่นแหละ ไม่ต้อง Setup ไม่ต้อง Install
สำหรับ Debian และ Ubuntu อาจารย์รุจชัยเคยมาบรรยายที่ KKLUG ว่าจะต้องผูกให้ระบบรู้จักกับ Tablet เสียก่อนโดย
สร้างแฟ้มข้อความ (Text File) ชื่อ 52-android.rules ไว้ใน /etc/udev/rules.d/ (แน่นอนว่าต้องผ่าน su นะครับ) โดยในแฟ้มจะมีข้อความว่า
SUBSYSTEM=="usb",SYSFS{idVendor}=="xxxx",ATTRS{idProduct}="yyyy",MODE="666"
ทั้งนี้ xxxx คือ Vendor ID และ yyyy คือ Product ID ที่สามารถทราบได้โดยใช้คำสั่ง
lsusb
ซึ่งจะแสดงรายการอุปกรณ์ที่ต่อพ่วงกับ PC ของเราทาง USB ดังนี้
Bus zzz Device zzz: ID xxxx:yyyy Product Name
เมื่อสร้างแฟ้มข้อความ 52-android.rules แล้วตรวจให้แน่ใจว่าโหมดของแฟ้มคือ 644 หลังจากนั้นเพื่อให้การเปลี่ยนแปลงเกิดผลทันทีก็สั่งให้บริการ ABD เริ่มต้นใหม่โดย
> ./adb kill-server
> ./adb start-server
มาถึงจุดนี้ก็ถือว่าพร้อมใช้งาน ADB ผ่านพอร์ด USB แล้ว

ส่วนใช้งาน
  • ต่อ Android Tablet เข้ากับพอร์ด USB ของ PC ตอนนี้ Tablet อาจจะถามว่าจะเปิดที่เก็บข้อมูลไหม ไม่ต้องตอบครับ Exit ออกมาเลย ถ้าเปิดที่เก็บข้อมูล PC จะมองเห็น Tablet เราเป็น USB Flashdrive ตัวหนึ่งเท่านั้น ถ้าทำต่อมาจากขั้นเตรียมการก็ข้ามขั้นนี้ไปเลย
  • เรียกใช้โปรแกรม ADB ซึ่งใน Debian ของผมจะใช้ Command Line
> ./adb devices
ถ้าเชื่อมต่อได้ก็จะมีข้อความขึ้นมาที่ Prompt ดังนี้
* daemon not running. starting it now on port xxxx *
* daemon started successfully *
List of devices attached
xxxxxxxxxxxxxxxx device
  • เรียกใช้โปรแกรม androidscreencast.jnlp
> jawaws androidscreencast.jnlp
เราจะเห็นหน้าจอของ Tablet ของเราอยู่ในหน้าต่างของโปรแกรม androidscreencast.jnlp นี่แหละครับ  จะบันทึกเป็นวิดีโอก็ได้ ในระบบของผมเขาจะบันทึกให้เป็นแฟ้ม MOV ดังตัวอย่างข้างล่างนี้ครับ

หรือจะบันทึกภาพหน้าจอก็ใช้เครื่องมือบันทึกภาพหน้าจอของ Gnome ก็ได้

เมื่อเราเห็นหน้าจอของ Tablet ของเราทางจอคอมพิวเตอร์ (ตอนนี้จอ Tablet มันดำอยู่) ก็พอจะหาทางควบคุมความสว่างได้ แต่ขอบอกให้ชัด ๆ ก่อนว่าไม่ใช่ว่าควบคุม Tablet จาก PC แต่ให้ PC แสดงหน้าจอของ Tablet เฉย ๆ เรายังต้องใช้ Touch Screen ของ Tablet ในการควบคุมอยู่ดี

ในเว็บแจ้งว่าหากต้องการควบคุม Tablet ผ่าน PC แบบเต็มตัวจะต้อง Root Tablet ตัวนั้นเสียก่อน ผมยังไม่กล้าพอครับ

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

วันพฤหัสบดีที่ 1 มีนาคม พ.ศ. 2555

หัดเขียนแอนดรอยด์ - โปรแกรมฆ้องวง

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

แต่เมื่อปลายปีที่ผ่านมามีโอกาสได้จับแทบเบล็ตของเพื่อน ลองเล่นดูทำให้มองเห็นว่าที่มีคนกล่าวกว่า Mobile Computing is already here น่าจะเป็นจริง ก็เลยคิดว่าควรหาความรู้ด้านนี้ใส่ตัวไว้บ้าง

หลายปีก่อนผมเคยพยายามเรียนรู้ Java แต่ไม่ประสบความสำเร็จเนื่องจากไม่มีความสามารถที่จะทำความเข้าใจระบบคลาสที่ซับซ้อนของ Java ได้ ศาสตร์ของ Java เองก็ถือว่ากว้างขวางจนกระทั่งเมื่อเริ่มเรียนรู้ขั้นต้นแล้วแล้วจะไปต่อขั้นกลาง ขั้นสูงก็ไปไม่ถูก (แต่ก็ได้พื้นฐานของ Java มาเล็กน้อย พออ่านโปรแกรมออก)

ในทางกลับกัน ถึง Android จะใช้พื้นฐานภาษา Java (ซึ่งผมขยาดเอาเลยทีเดียว) แต่ระบบคลาสของ Android ชัดเจนกว่ามาก ทำให้เกิดทัศนคติต่อตัวเองว่าการเรียนรู้ Android น่าจะง่ายกว่า ซึ่งหลังจากที่ลองลงมือทำก็พบว่าจริงทีเดียว

แม้ว่า Android จะเป็น Open Source แต่การติดตั้ง SDK และ IDE ลงบน Debian กลับเป็นเรื่องไม่ง่ายนัก คือใช้ apt-get หรือ synaptic ก็ไม่ได้ นี่เป็นอุปสรรคสำหรับผมอย่างมากจนกระทั่งผมได้พบกับ Developing Android Applications on Debain ที่ workaround.org ซึ่งมีคำแนะนำอย่างละเอียด

เมื่อดำเนินการตามขั้นตอนที่แนะนำแล้วก็เริ่มต้นเรียนรู้ Android จาก Hello, World พอเริ่มเข้าใจเครื่องไม้เครื่องมือและมองเห็นศักยภาพของ Android แล้วก็เกิดไอเดียบรรเจิดว่าอย่างทำโน่นอยากทำนี่ สิ่งแรกที่อยากทำบนแอนดรอยด์คือโปรแกรมดนตรีไทย เริ่มต้นที่ฆ้องวงก่อน เพราะมีทรัพยากรครบ เสียงต้นแบบก็มีแล้ว ภาพลูกฆ้องก็มีแล้ว กลไกการสังเคราะห์ก็มีแล้ว

โปรแกรมฆ้องวงรุ่นแรกสุดใช้ ImageButton เป็นรูปฆ้อง ใช้ Absolute Layout ระบุตำแหน่งลงใน XML และใช้ MediaPlayer เพื่อเล่นเสียงฆ้องที่บันทึกไว้ล่วงหน้า (ไม่ได้สังเคราะห์) โปรดสังเกตว่าคลาสชื่อ HelloButtonActivity ที่เป็นเช่นนี้เพราะว่าโปรแกรมนี้เริ่มมาจากการศึกษาโปรแกรม HelloButton ของ Android Tutorial บทแรก ๆ แล้วค่อย ๆ ขยายขอบเขตออกมา (โปรแกรมที่แสดงนี้ลดรูป คือเหลือลูกฆ้องเพียงลูกเดียวเท่านั้น)
public class HelloButtonActivity extends Activity {

        ImageButton gongButton01;
 
        OnClickListener gongListener = new OnClickListener() {
         @Override
  public void onClick(View v){
          if (v==gongButton01)
   {
           MediaPlayer mp = MediaPlayer.create(HelloButtonActivity.this, R.raw.gong01);
           mp.setOnCompletionListener(new OnCompletionListener() {
                                 public void onCompletion(MediaPlayer mp) {                
                                         mp.stop();
                                         mp.release();
                                 }
    });
    mp.start(); 
      }
         }

         @Override
 public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
        
                setContentView(R.layout.main);

                addListenerOnButton();
        }

        public void addListenerOnButton(){
             gongButton01 = (ImageButton) findViewById(R.id.gongButton01);
        }
}

วิธีแบบนี้มีข้อจำกัดอยู่หลายประการคือ
  1. เมื่อเป็น ImageButton แล้ว Event ที่ตรวจจับได้คือ Click ซึ่งหมายความว่าต้อง "กด" และ "ปล่อย" จึงจะนับเป็น Click Event และโปรแกรมจะส่งเสียงออกมา ในมุมมองของผู้ใช้ถือว่าไม่สมจริง
  2. วิศวกรของ Android ไม่แนะนำให้ใช้ Absolute Layout เนื่องจากหน้าจอขอโทรศัพท์มีหลายขนาด
  3. MediaPlayer ที่เล่นเสียงของแต่ละลูกฆ้องถือเป็น 1 อินสแตนซ์ เรียกมาเล่นแล้วต้องลบทิ้ง ไม่เช่นนั้นแล้วโปรแกรมจะกินพื้นที่หน่วยความจำมากขึ้นเรื่อย ๆ และวิธีที่ผมใช้เขียนทำให้เล่นได้ทีละ 1 เสียงเท่านั้น ในทางปฏิบัติการบรรเลงฆ้องจะใช้สองมือ ควรเล่นได้พร้อมกันอย่างน้อย 2 เสียง โปรแกรมเมอร์หลายคนแนะนำว่าให้ใช้ SoundPool ดีกว่า เพราะ SoundPool 1 อินสแตนซ์เรียกเสียงมาเล่นได้พร้อม ๆ กันหลายเสียง
หลังจากนั้นได้มีโอกาสชมผลงานโครงงานนักศึกษาภาควิชาวิศวกรรมคอมพิวเตอร์ มีหลายโครงงานใช้แอนดรอยด์ เลยได้เข้าไปสอบถามหาความรู้เพิ่มเติม นักศึกษาแนะนำว่าใช้ Canvas ดีกว่า ตอนนั้นยังไม่รู้ว่า Canvas คืออะไร ก็มาถามเฮียกู เฮียเลยแนะนำให้รู้จักกับ Android Tutorial: 2D Canvas Graphics ที่ Programmer XR พบว่าการวาดรูปลง Canvas นั้นไม่ยาก ดูจากตัวอย่างแล้วดัดแปลงนิด ๆ หน่อย ๆ ก็ใช้ได้ ไอ้ที่ยากน่ะคือให้รูปใน Canvas มันดักอีเวนต์การแตะหน้าจอ (Tap) ต่างหาก

จากการดู Source Code ของชาวบ้านประกอบกับคำอธิบายใน stackoverflow (นี่แหละข้อดีของโอเพนซอร์ส) ถึงได้รู้ว่าเขาใช้คลาส onTouch แล้วดักด้วย OnTouchListener กัน แต่การทำแบบนี้จะถือว่าฆ้องทั้ง 16 ลูกเป็นรูปภาพเพียงรูปเดียว ดัก OnTouchListener ฟังก์ชันเดียว แล้วจำแนกการเล่นเสียงของฆ้องแต่ละลูกตามตำแหน่งสัมบูรณ์ใน Canvas

พอดัก OnTouchListener ได้แล้วก็กำหนดให้โปรแกรมเรียก SoundPool มาเล่นเสียงที่บันทึกไว้ล่วงหน้าเมื่อเกิด onTouch ขึ้น การใช้ SoundPool นี้ได้ข้อมูลจาก The Game Programming Wiki ลดรูปตัดมาใช้เฉพาะที่จำเป็น (โปรแกรมที่แสดงนี้ลดรูปเช่นเดียวกัน คือเหลือลูกฆ้องเพียงลูกเดียว)
public class GongwongActivity extends Activity {
        SoundPool soundPool;
 int gong01ID; 
 
        @Override
        public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                requestWindowFeature(Window.FEATURE_NO_TITLE);        
                setContentView(new Panel(this));
                setVolumeControlStream(AudioManager.STREAM_MUSIC);
                soundPool = new SoundPool(16, AudioManager.STREAM_MUSIC,0);            
  gong01ID = soundPool.load(getBaseContext(), R.raw.gong01, 1);
    }
    
    class Panel extends View {
     Rect dst = new Rect();
     float xTouch, yTouch;
     
     public Panel(Context context) {
      super(context);
     }
     
     public boolean onTouchEvent(MotionEvent event){
      int action = event.getAction();
      
      switch(action){
      case MotionEvent.ACTION_DOWN:
       xTouch = event.getX();
       yTouch = event.getY();
       if (xTouch > 44 & xTouch < 44 + 68 & yTouch > 224 & yTouch < 224 + 68){
        soundPool.play(gong01ID,1,1,0,0,1);
       }
      }
      return true;
     }
     
     @Override
     public void onDraw(Canvas canvas) {
      dst.set(0,0,480,800);
      Bitmap gongwong = BitmapFactory.decodeResource(getResources(), R.drawable.gongimg);
      canvas.drawColor(Color.BLACK);
      canvas.drawBitmap(gongwong, null, dst,null);
     }
    }
}


ผลลัพธ์ก็คือโปรแกรม gongwong โดย SDK ที่ใช้เป็นรุ่น Android 2.0 ไม่น่ามีปัญหากับอุปกรณ์แอนดรอยด์ส่วนใหญ่ หากท่านในสนใจทดลองใช้งาน ก็สามารถดาวน์โหลดแฟ้ม APK ได้ที่นี่ (ขอเตือนก่อนว่าโปรแกรมรุ่นนี้ถือเป็น Alpha Version อาจมีข้อบกพร่องอยู่มาก) เมื่อเรียกใช้โปรแกรมบนแทบเบล็ตก็จะเห็นหน้าตาโปรแกรมดังรูป และเมื่อแตะบนหน้าจอในบริเวณลูกฆ้องก็จะได้ยินเสียงฆ้องแต่ละลูก ทั้งนี้จากการทดลองพบว่าหูฟังจะให้คุณภาพเสียงที่ดีกว่าลำโพงก็ขอให้แนะนำให้ใช้กับหูฟังก็แล้วกัน

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

สิ่งที่ต้องปรับปรุง
  1. แม้ว่า SoundPool จะเล่นเสียงได้พร้อมกันหลายเสียง แต่ onTouch ที่ตรวจจับได้ก็จับได้ทีละ Touch ยังไม่สามารถขยายไปถึง Multi Touch ได้
  2. รูปฆ้องสำหรับฆ้องลูกเล็ก เล็กเกินไปโดยแม้กระทั่งกับแทบเบล็ตที่มีหน้าจอขนาด 8 นิ้ว รูปลูกฆ้องไม่จำเป็นต้องย่อส่วนตามมาตรส่วนคงที่ก็ได้
  3. การกำหนดขอบเขตของฆ้องแต่ละลูก ใช้การกำหนดค่าคงที่ตายตัวลงในโปรแกรม นี่ไม่ใช่การเขียนโปรแกรมที่ดี ควรหาทางจัดเก็บข้อมูลตามรูปแบบมาตรฐาน หรือไม่เช่นนั้นก็ให้หันไปใช้แนวทางให้ลูกฆ้องแต่ละลูกเป็น Sprite ที่แต่ละตัวมี OnTouchListener ของตัวเองก็ได้ ถ้าเป็นอย่างนี้ ก็ไม่ต้องกำหนดขอบเขตลูกฆ้องแต่ต้องกำหนดตำแหน่งแทน
  4. หากฟังก์ชันพื้นฐานสมบูรณ์ดีแล้ว ควรทดสอบโปรเจ็คตามกรรมวิธีมาตรฐานของ Android ด้วย (ยังทำไม่เป็น)