ผมต้องมาทำงานกับ Wave File อีกแล้วล่ะ ทีนี้ปัญหาคือ Wave file ที่ได้จาก SAPI มันมีเสียงเงียบอยู่ตรงทางหัวและท้าย ดังตัวอย่างข้างล่างเป็น wave form ของคำว่า united states ซึ่งไม่เข้าใจว่ามันเป็นเฉพาะ Microsoft Anna รึเปล่า ทำให้ทางหัวมันจะเป็นเสียงเงียบอยู่ซัก 0.05 วินาที ส่วนตอนท้ายจะมีเสียงเงียบอยู่ 0.1 - 0.3 วินาที เวลาเอามาต่อกันหลายๆส่วนแล้วจะฟังเป็นเสียงเงียบไปนานมาก จึงจำเป็นเลยต้องตัดมันออก
ใน .NET นั้นเราสามารถแทนข้อมูลแบบไบนารีด้วยอาเรย์ของ byte ได้ ผมเอาข้อมูลของ wave ที่ต้องการออกมาดูพบว่าช่วงที่เป็นเสียงเงียบนั้นมีค่าเป็น 0 ตลอด ผมก็เลยจัดการเขียนโค้ดสำหรับ trim ขึ้นมา
private static byte[] TrimStartTrailSilence(byte[] bb, out int end, out int start)
{
byte[] target;
// Trim trailing silence
end = bb.Length -1 ;
while (bb[end--] == 0);
start = 0;
while (bb[start++] == 0);
target = new byte[end - start + 1];
Array.Copy(bb,start, target, 0, end-start +1 );
return target;
}
หลักการก็คือดูจากทางหัวและท้าย แล้วตัดเอาข้อมูลมาเมื่อเจอไบต์ที่ค่าเริ่มไม่เป็นศูนย์ ไปจนถึงไบต์ที่มีค่าเริ่มเป็นศูนย์ไปจนจบ (จริงๆแล้วเราไม่ต้องคัดลอกข้อมูลลงในอาเรย์ใหม่ก็ได้เพราะเรารู้ตำแหน่งของข้อมูลจากพารามิเตอร์แล้ว) ผมลองเอาเมธอดนี้ไปใช้ดู ลองให้ SAPI สร้างเสียงออกมาต่อๆกันดู เสร็จแล้วก็มานั่งฟังผลงาน
โอ้วเยี่ยม หูแตกครับท่านผู้อ่าน พอลองเปิดไฟล์ผลลัพธ์ดูก็พบว่าหูผมไม่ได้เพี้ัยน
ลองดูใหม่อีกรอบผมก็พบว่าไม่น่าแปลกใจที่กราฟมันจะโด่งได้ขนาดนี้ เพราะในช่วงที่กราฟตีโด่งเยอะๆเป็นรอยต่อระหว่างหลายๆไฟล์ และในไบต์ที่ 81, 82, .. ซึ่งเป็นไบต์ที่เริ่มมีค่าไม่ใช่ 0 ของไฟล์ที่เอามาต่อนั้นมีค่า 252 251 253, … ตอนแรกผมโยนความผิดให้ SAPI ไปครึ่งตัวแล้ว อีกครึ่งตัวที่เหลือก็ได้แต่ถามตัวเองว่า เราทำอะไรผิด พอมาลองฟังแบบยังไม่เอามาต่อพบว่ามันก็ปกติ ผมพบคนร้ายแล้ว
นั่งงงอยู่ 10 นาที สุดท้ายด้วยผลกรรมดีที่เคยทำด้วยการเขียนบล็อกเรื่อง header ของไฟล์ wave ก็ชี้นำให้ระลึกได้ว่าไฟล์ Wave มันเก็บข้อมูลเป็น Sample แล้วมันก็มีการกำหนด Sampling rate ดังนั้นเราต้องทำการเลื่อนมันให้ถูกตาม Sampling rate และ จำนวน Channel ของเราด้วย ในกรณีของผมมันเป็น Mono ซึ่งใช้ Sampling rate เป็น 8000 Hz และมีค่า Bits/Sample เป็น 16 ดังนั้นผมจึงใช้
private static byte[] TrimStartTrailSilence(byte[] bb, out int end, out int start)
{
byte[] target;
// Trim trailing silence
end = bb.Length;
end--;
while (bb[end--] == 0);
if (end % 2 > 0)
{
end ++;
}
start = 0;
while (bb[start++] == 0);
if (start % 2 > 0)
{
start --;
}
target = new byte[end - start + 1];
Array.Copy(bb,start, target, 0, end-start +1 );
return target;
}
แค่นี้ก็ใช้ได้เรียบร้อย