เนื่องจากจำเป็นจะต้องทำงานกับไฟล์เสียงก็เลยต้องข้อมูลของไฟล์ wav มานั่งย่อยเพื่อเพิ่มความเข้าใจ หลังจากเข้าใจแล้วก็เลยต้องจดไว้ซักเล็กน้อยเผื่อว่าจะมีใครสนใจ
บล็อกนี้จะไม่อธิบายถึงวิธีการสร้างและรายละเอียดของเนื้อหาของไฟล์ Wave เท่าไหร่นะ แต่จะเน้นหนักไปที่เรื่องของโครงสร้างมากกว่า
พร้อมแล้วก็มาเริ่มได้เลย
จากความรู้ดั้งเดิมสมัยม.ปลาย เรารู้ว่าเสียงเป็นคลื่นตามยาว เสียงเกิดจากการสั่นสะเทือนของมวลอากาศที่สั่นจนมุดมาให้รูหูของเราทั้งสองรู หรือรูเดียวสำหรับผู้ที่มีรูหูแค่รูเดียว แล้วไปกระทบอะไรต่อมิอะไรมากมายจนสัญญาณส่งไปถึงสมองจนแปลความว่าได้ยินเสียงแล้ว ซึ่งกว่าคอมพิวเตอร์จะสร้างอะไรพวกนี้ให้เราได้ มันก็ต้องมีข้อมูลให้คอมพิวเตอร์สร้างเสียงออกมาถูกมั้ยฮะ??
คำศัพท์น่ารู้
เนื่องจากข้อมูลเสียงมีลักษณะที่ต่อเนื่อง แต่คอมพิวเตอร์นั้นจะทำงานกับข้อมูลที่ไม่ต่อเนื่อง เราจึงต้องมีการแปลงข้อมูลเสียงออกมาที่เรียกว่า แซมปลิ้ง(Sampling) ซึ่งก็เหมือนกับการดูว่า ณ เวลา t ระยะแอมปลิจูด A ที่อนุภาคขยับจากค่าปกติเป็นเท่าไหร่ ถ้าเราแซมปลิ้งด้วยความถี่ที่มากๆๆๆๆๆ เมื่อเอาข้อมูลมาต่อกัน มันก็น่าจะคล้ายกับของเดิม ความถี่ในการแซมปลิ้งนี้เราจะเรียกว่า Sampling Rate
ทีนี้เนื่องจากคอมพิวเตอร์มันรู้จักแต่ค่า 0 และ 1 เหมือน ไฮ กับ โล ดังนั้นถ้าเราใช้แค่บิตเดียวแทนก็คงได้เสียงหึ่งๆออกมาแค่นั้น นั้นก็เลยจำต้องกำหนดว่าเราจะใช้ข้อมูลกี่บิตในการแทนข้อมูล 1 ชุด ซึ่งปกติก็จะใช้เป็นจำนวนที่มีค่าเป็นยกกำลังของสองเช่น 8, 16, 32, … เป็นต้น
และเนื่องจากเรามีสองหูซ้ายขวา ทำให้เราต้องบอกว่าจะสร้างให้หูข้างซ้ายเป็นเสียงยังไง และเสียงสำหรับหูข้างขวาเป็นยังไง ดังนั้นเราจึงสามารถสร้างเสียงเป็ดสำหรับหูข้างซ้ายมาฟังพร้อมๆกับเสียงแตรวงในหูขวาก็ยังได้ ซึ่งเราเรียกระบบนี้ว่า สเตอริโอ แต่ถ้าจะสร้างออกมาให้เหมือนกันทั้งสองหู หรือ โมโน ล่ะ ก็ได้เช่นกัน โดยเรามักจะเรียกจำนวนหูนี้ว่า Channels
ที่กล่าวมาทั้งหมดเป็นคำศัพท์พื้นฐานที่อยากบอกให้รู้ แต่ถ้าไม่รู้เรื่องก็กองไว้ตรงนั้นก่อน เพราะไม่มีผลในการใช้งานแต่อย่างใด
สำหรับไฟล์ Wav นั้นจริงๆแล้วมันคือก้อนข้อมูลอะไรบางอย่าง ที่ได้รับการแปะเฮดเดอร์เพื่อบอกว่าหน้าตาของก้อนข้อมูลนั้นเป็นยังไง ไฟล์ Wav นี้ใช้กันมากในวินโดวส์ สำหรับในแมคจะใช้ AIFF ซึ่งหน้าตาคล้ายกันเพราะเป็นลูกพี่ลูกน้องสืบเชื้อสายมาจากไฟล์ประเภท RIFF เหมือนกันแทน โดยปกติเจ้าก้อนข้อมูลนี้มักจะใช้การเข้ารหัสแบบ PCM (Pulse Modulation Code) เพื่อแสดงแอมปลิจูด A ของคลื่นที่เวลา t แต่ในความเป็นจริงเราสามารถใช้ Codec อื่นๆในการเก็บข้อมูลก็ได้เช่นกัน
ทีนี้ การที่เราจะเล่นไฟล์เสียงได้เนี่ย เราก็ต้องรู้ก่อนว่าไฟล์เสียงเนี่ยเก็บข้อมูลยังไง ซึ่งกุญแจสำคัญก็อยู่ที่เฮดเดอร์นี่แหละ
เฮดเดอร์ ความลับสู่เสียงสวรรค์
เฮดเดอร์ที่ใช้ในไฟล์ Wav นั้นโดยทั่วไปประกอบด้วยข้อมูลขนาด 44 ไบต์พอดีไม่มีขาดไม่มีเกิน ข้อมูลจะถูกเก็บในรูปแบบ little endian โดยจะมีโครงสร้างดังนี้
ข้อความ 12 ไบต์แรกเรียกว่า “RIFF Chunk”
| ไบต์ที่ | ขนาด (ไบต์) | รายละเอียด |
|---|---|---|
| 0-3 | 4 | ข้อความ “RIFF” |
| 4-7 | 4 | ขนาดของข้อมูลที่จะตามมาด้านหลัง |
| 8-11 | 4 | ข้อความ “Wave” |
ข้อความ 24 ไบต์ถัดมาเรียกว่า “FORMAT Chunk”
| ไบต์ที่ | ขนาด (ไบต์) | รายละเอียด |
|---|---|---|
| 12-15 | 4 | ข้อความ “fmt ” (มีช่องว่างต่อท้ายนะ) |
| 16-19 | 4 | ขนาดของ FORMAT Chunk ปกติแล้วถ้าใช้ PCM ก็จะมีค่าเป็น 16 เสมอ |
| 20-21 | 2 | ถ้าเป็น Uncompressed data จะมีค่าเป็น 1 แต่ ถ้าเป็นค่าอื่นแสดงว่าข้อมูลถูกบีบอัดอยู่ |
| 22-23 | 2 | จำนวน Channel มีค่า 1 หรือ 2 |
| 24-27 | 4 | กำหนด Sampling Rate ปกติแล้วถ้าเป็น CD Quality จะมีค่าเป็น 44100 |
| 28-31 | 4 | Bytes Rate - คำนวณจาก Sampling Rate * จำนวน Channels * BitsPerSample / 8 |
| 32-33 | 2 | Block Alignment - คำนวณจาก จำนวน Channels * BitsPerSample / 8 |
| 34-35 | 2 | Bits per Sample - จำนวนบิตต่อแซมเปิล มีค่าเป็น 8, 16,24, … |
ส่วนสุดท้ายเรียกว่า “Data Chunk”
| ไบต์ที่ | ขนาด (ไบต์) | รายละเอียด |
|---|---|---|
| 36-40 | 4 | ข้อความ “data” |
| 41-44 | 4 | ขนาดของข้อมูลที่เหลือใน Data Chunk |
| 45-จบ | n | ข้อมูลของไฟล์ Wav |
จะเห็นว่าถ้าเรารู้รูปแบบของข้อมูลรวมทั้งมีข้อมูลในมือ เราก็สร้างเฮดเดอร์ขึ้นมาได้ไม่ยากนักหรอก
ลองดูเฮดเดอร์ของจริง
ทีนี้ถ้าเราลองเปิดไฟล์ Ding.wav ที่มากับวินโดวส์ดูจะได้ผลของ 44 ไบต์แรกเป็นดังนี้
ลองแปลงดูละกันว่า ding.wav มีข้อมูลยังไงบ้าง
สร้างเฮดเดอร์ปลอม
ทีนี้ สาเหตุที่ต้องศึกษาเรื่องนี้ก็เพราะว่าเจ้า Speech API ดันมีความสามารถสูง สามารถสังเคราะห์เสียงพูดออกมาได้ หรือจะให้ออกมาเป็นไฟล์ Wav ก็ได้ หรือจะให้ลง Memorystream ไว้ก็ได้ แต่ …. มันดันไม่สร้างเฮดเดอร์มาให้ ดังนั้นเราก็ต้องมาเขียนเฮดเดอร์เอง ก็เลยจำเป็นต้องสร้างเป็นคลาสนี้ขึ้นมา
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace Chula.SLS.TTS {
public class WaveHeaderWriter {
private int _fileSize;
private bool _isUncompressed;
public bool IsUncompressed {
get { return _isUncompressed; }
set { _isUncompressed = value; }
}
private short _bitRate;
public short BitsPerSample {
get { return _bitRate; }
set { _bitRate = value; }
}
private int _channels;
public int Channels {
get { return _channels; }
set { _channels = value; }
}
private int _sampleRate;
public int SampleRate {
get { return _sampleRate; }
set { _sampleRate = value; }
}
private int _dataSize;
public int DataSize {
get { return _dataSize; }
set { _dataSize = value; }
}
public int ByteRate {
get { return SampleRate * Channels * BitsPerSample / 8; }
}
public short BlockAlignment {
get { return (short)(Channels * BitsPerSample / 8); }
}
public byte[] CreateHeader() {
BinaryWriter writer = new BinaryWriter(new MemoryStream());
byte[] b = Encoding.ASCII.GetBytes("RIFF");
writer.Write(b);
writer.Write(DataSize + 44 - 8);
writer.Write(Encoding.ASCII.GetBytes("WAVEfmt "));
writer.Write(16);
writer.Write(IsUncompressed);
writer.Write(false);
writer.Write((short)Channels);
writer.Write(SampleRate);
writer.Write(ByteRate);
writer.Write(BlockAlignment);
writer.Write(BitsPerSample);
writer.Write(Encoding.ASCII.GetBytes("data"));
writer.Write(DataSize);
return GetBytes(writer.BaseStream);
}
private byte[] GetBytes(Stream stream) {
byte[] buffer = new byte[stream.Length];
stream.Position = 0;
stream.Read(buffer, 0, (int)stream.Length);
return buffer;
}
}
}
สำหรับวิธีใช้ก็คือสร้าง object ของคลาส WaveHeaderWriter ขึ้นมา กำหนดรายละเอียดให้ครบ คือขนาดของ Data, Sampling Rate, Bits Per Sample และจำนวน Channels แล้วเรียกเมธอด CreateHeader จะได้ อาเรย์ของ 44 ไบต์แรกของไฟล์ Wav ออกมา เอาไปใช้ได้ทันทีด้วยการเอาไปแปะไว้หน้า Data ได้เลย
ตัดต่อ ไฟล์ Wav
จริงๆมันก็ไม่ได้ยากเลย แต่มีเงื่อนไขง่ายๆก็คือ Data ที่จะมาต่อจะต้องมี Sampling Rate, Bits per sample และ จำนวน Channels เท่ากัน เวลานำมาต่อกันก็จะเหมือนกับเป็นไฟล์ Wav ใหม่ที่เล่นต่อกันนั่นแล พอแปะเฮดเดอร์ที่บอกขนาดถูกต้องก็เล่นได้ปกติ
สรุป
อย่างที่กล่าวข้างต้นว่าไฟล์ Wav นั้นนำมาใช้ในการสร้างเสียงของคอมพิวเตอร์สู่ลำโพง ซึ่งโดยทัวไปแล้วจะไม่มีการบีบอัด ทำให้ตัดต่อ แก้ไขได้ง่าย แต่ว่าเปลืองที่เก็บ จึงมีการนำเอา codec ต่างๆเช่น Flac, MP3, AAC ฯลฯ มาใช้ แต่แนวคิดพื้นฐานก็จะคล้ายๆกันทั้งหมดทั้งสิ้น

โอ้ววว เกรททท
โอ้ววว เกรททท
มาเก็บความรู้ด้วยคน :P
มาเก็บความรู้ด้วยคน :P
หนายๆๆๆ รออ่านอยู่
หนายๆๆๆ รออ่านอยู่
เยี่ยมเลย
เยี่ยมเลย
Post new comment