[Signal processing with Python] Bài 1: WAV file

Ngô Văn Tuân

Gà con
Staff member
Chào các bạn:1cool_byebye:,
Trước khi nói về xử lý tín hiệu với python, chúng ta hãy cùng đi tìm hiểu cách mà tín hiệu, cụ thể ở đây là âm thanh được lưu trong máy tính của chúng ta như thế nào :gach?

Tổng quan:
  • Một file được lưu trong hard disk bao gồm metadatadata. Trong đó:
    • Metadata là phần lưu thông tin của dữ liệu thật sự. Ex. file name, file extenstion, file attributes, time created or last updated, date created or last upadted, file size,...
    • Data là phần dữ liệu thật sự của file.
  • Phần metadata được quản lý bởi driver dành cho filesystems (FAT16, FAT32, NTFS) hiện hành của hard disk. Do đó metadata sẽ có format phụ thuộc vào filesystems.
  • Khi ta gọi hàm open("<path_to_file>/<file_name>"), driver sẽ dựa vào <file_name> mà chúng ta cung cấp để load phần data của file lên RAM.
  • Sau đó ta sẽ làm việc với phần data này. Việc chúng ta ghi gì vào phần data này, ghi với format nào thì driver sẽ không quan tâm:-(. Driver sẽ chỉ coi data của chúng ta là một chuỗi các bytes.
  • Khi ta close một file, nếu ta không can thiệp gì thì metadata sẽ được tự động điền vào bởi driver, sau đó, cả metadatadata sẽ được lưu xuống hard disk. Việc lưu file này như thế nào sẽ do driver của filesystems quản lý.
Nhận xét:
  • Như vậy cho thấy, driver của filesystems giúp ta abstract được quá trình lưu trữ dữ liệu trên hard disk.
  • Phần file extension trong metadata cung cấp thông tin về định dạng của dữ liệu được lưu trong phần data.
  • Dựa vào file extension, người sử dụng file có thể biết được cần sử dụng chương trình nào để đọc file đó.
Ví dụ:
Sử dụng chương trình Bless Hex Editor trên Ubuntu để mở audio file "cartoon008.wav". Phần thông tin chúng ta thấy ở đây chính là phần data thật sự của file, chứa thông tin về âm thanh được lưu dưới chuẩn lưu trữ âm thanh WAVE.​


Như chúng ta thấy, phần data của file "cartoon008.wav" bắt đầu bằng RIFF. Vậy:

1. Resource Interchange File Format (RIFF) là gì?

  • RIFF là một generic file container format (định dạng lưu trữ dữ liệu chung).
  • Được sử dụng chủ yếu để lưu trữ âm thanh và video, nhưng cũng có thể lưu dữ liệu bất kì.
  • Microsoft đã phát triển định dạng file WAV, AVI dựa trên RIFF.
  • Trong RIFF, dữ liệu được tổ chức thành các segments (đoạn dữ liệu), mỗi segment được gọi là một chunks (khối dữ liệu).
  • Mỗi khối dữ liệu bao gồm 12 bytes header. Trong đó gồm:
    • 4 bytes signature (Ex. RIFF)
    • 4 bytes data size.
    • 4 bytes RIFF type. (Ex: WAVE, AVI, ...)
  • Kích thước một chunk (chunk size) = data size + 8 (bytes). Trong đó 8 bytes gồm 4 bytes signature và 4 bytes data size (do data size là size của khối dữ liệu trong chunk sau data size nên data size chưa tính phần 4 bytes của data size và đã tính phần 4 bytes của RIFF type).
2. WAV file format là gì?

  • Waveform Audio File Format (WAVE hay WAV) là một chuẩn lưu trữ âm thanh trên máy tính được phát triển bởi Microsoft và IBM.
  • WAV file format được sử dụng trên Microsoft Windows OS để lưu trữ raw, uncompressed audio (âm thanh chưa được nén).
  • WAV file format là một dạng của Resource Interchange File Format (RIFF).
  • WAV file thường là một RIFF file với chỉ một "WAVE" chunk, "WAVE" chunk này bao gôm 2 sub-chunks là "fmt""data".
3. Định dạng WAV lưu audio như thế nào?
Hình trên cho ta thấy format của một WAVE file.
Chú giải:
  • endian: Ví dụ trong bộ nhớ, ở ô 0x00 có dữ liệu 0x00, ở ô 0x01 có dữ liệu 0x01, giá trị lưu trong hai ô này là một số 16 bit. Nếu đọc theo kiểu little endian thì giá trị số đó là 0x0100 = 256d, còn nếu đọc theo kiển big endian thì ta có giá trị 0x0001 = 1d.
  • File offsets (bytes): địa chỉ của phần tử trong khối dữ liệu kể tử địa chỉ đầu tiên của khối.
  • Field size (bytes): Kích thước của khối dữ liệu, đơn vị là byte.
Trong quá trình phân tích cấu trúc của WAVE file, ta sẽ lấy file "cartoon008.wav" là ví dụ:

  • ChunkID: có giá trị cố định 0x52_49_46_46 (big endian), theo bảng mã ASCII, ta có chữ "RIFF".
  • ChunkSize: 0x00_00_78_68 = 30824 (bytes) -> Kích thước khối dữ liệu phía sau là 30824 bytes. Suy ra file size là 30824 + 8 = 30832 bytes. Chúng ta có thể kiểm chứng gia trị này bằng cách xem properties của file. Lưu ý: Size của file không bao gồm size của metadata.
  • Format: có giá trị cố định 0x57_41_45_66 = "WAVE".
  • Subchunk1 ID: có giá trị cố định 0x66_6D_74_20 = "fmt ".
  • Subchunk1 Size: 0x00_00_00_10 = 16 bytes -> Kích thước của khối dữ liệu phía sau trong subchunk "fmt " là 16 bytes
  • AudioFormat: 0x00_01. PCM = 1 (PCM for pules-code modulation). Nếu PCM khác 1 thì dữ liệu âm thanh đã được nén. PCM = 1 chứng tỏ dữ liệu âm thanh chưa được nén (compress).
  • NumChannels: 0x00_01 = 1. Số kênh của dữ liệu âm thanh. NumChannels = 1 cho thấy đây là mono audio, NumChannels = 2 thì ta có stereo audio.
  • SampleRate: 0x00_00_AC_44 = 44100 (Hz). Tốc độ lấy mẫu của file âm thanh này là 44100 = 2 * 22050. Ta biết rằng âm thanh nghe được có tần số từ 20 đến 20,000 Hz. Các tần số lớn hơn 20,000Hz một chút vẫn phần nào anh hưởng đến chất lượng âm thanh nên ta coi tần số nghe được lớn nhất là 22050Hz, do đó, file âm thanh thường được lấy mẫu ở tần số 44100 Hz để thỏa định lý lấy mẫu Nyquist.
  • ByteRate: 0x00_01_58_88 = 88200 = SampleRate * NumChannels * BitsPerSample/8 = 44100 * 1 * 16/8.
  • BlockAlign: 0x00_02 = 2 = NumChannels * BitsPerSample / 8 = 1 * 16/8 = 2 bytes. Mỗi mẫu trong data sẽ gồm 2 bytes.
  • BitsPerSample: 0x00_10 = 16. Số lượng bit của mỗi một sample: 8 bits => 8, 16 bits => 16, etc.
  • Subchunk2 ID: có giá trị cố định 0x64_61_74_61 = "data".
  • Subchunk2 Size: 0x00_00_78_44 = 30788 bytes = NumSamples * NumChannels * BitsPerSample/8 = NumSamples * 1 * 16/8 => NumSamples = 30788/2 = 15394 (samples) => Dữ liệu âm thanh gồm 15394 mẫu. Kích thước của khối dữ liệu phía sau trong subchunk này là 30788 bytes.
  • data: Âm thanh được lấy mẫu và biên độ của các mẫu được lưu vào phần data này. Mỗi mẫu gồm 2 bytes, cứ thế mà đọc cho tới khi đủ Subchunk2 Size bytes:gach.
Kết luận: File "cartoon008.wav" là file audio 1 kênh (mono), được lấy mẫu với tần số 44100Hz, mỗi mẫu có chiều dài 16 bits.

4. Thực hành:
a. Tạo sóng sin với tần số 1000Hz và lưu dưới định dạng wav.
b. Mở file "cartoon008.wav" và add sine noise vừa tạo vào file âm thanh đó.
 
Last edited:
Top