Tập tin âm thanh

Một phần của tài liệu Giải quyết vấn đề nhận dạng tiếng Việt bằng phân tích cú pháp (Trang 87)

Có rất nhiều định dạng tập tin âm thanh khác nhau, nhưng chúng tôi sử dụng tập tin WAV với định dạng PCM để lưu thông tin âm thanh. Không có nhiều thông tin âm thanh được lưu trữ trong các chương trình giao diện đồ hoạ do việc huấn luyện và nhận dạng xảy ra trực tuyến. Tuy nhiên chúng tôi lưu trữ âm thanh theo định dạng tập tin như sau

Tên trường Kích thước (byte) Ý nghĩa

riff 4 Gồm bốn ký tự “RIFF” đánh dấu đây là tập tin đa phương tiện trong Windows

file_size 4 Độ dài của tập tin âm thanh. Thường là phần format cộng với data

wave 4 Gồm bốn ký tự “WAVE” xác định đây là tập tin âm thanh, không phải video

fmt 4 Gồm bốn ký tự “fmt ” xác định điểm bắt đầu của định dạng. Ta nên tìm đến (seek) khối này

fmt_size 4 Kích thước của fmt. Thông thường là 16 hoặc 18 tuỳ vào chương trình ghi âm

fmt_tag 2 Định dạng của phần dữ liệu. Có giá trị là 1 tương ứng với định dạng PCM

CPS 2 Số kênh trên một mẫu. 1 ứng với mono, và 2 ứng với stereo.

SPS 4 Tần số lấy mẫu, hay là số mẫu trên một giây. Có giá trị 8000Hz, 16000Hz, 44100Hz ... BYTESEC

(avg_byte_sec)

4 Số ô nhớ trên một đơn vị thời gian, tính bằng công thức BPC*CPS*SPS/8

BYTESAM (block_align)

2 Số ô nhớ dành cho một mẫu, dùng để tính số mẫu, công thức BPC*CPS/8

BPC 2 Số bít trên mỗi kênh, thường là 8 hoặc 16, có thể là 32

data 4 Gồm bốn ký tự “data” đánh dấu điểm bắt đầu của dữ liệu âm thanh. Nên tìm đến (seek) data_size 4 Kích thước của dữ liệu âm thanh tính ra byte.

Đổi ra số mẫu bằng cách chia cho BYTESAM data_samp data_size Các mẫu sẽ được lưu liền kề nhau. s1, s2, s3.

Nếu mẫu có hai kênh thì kênh trái lưu trước rồi phải lưu sau. Nếu mỗi kênh có 16 bít, thì 8 bít thấp lưu trước và 8 bít cao lưu sau.

Bảng 5-1. Định dạng tập tin âm thanh 5.1.2. Tập tin nhãn (label file format)

Tập tin nhãn dùng để đánh nhãn các tập tin, nghĩa là xác định một khoảng (a, b) là của từ gì, và (c, d) là của từ gì. Một tập tin nhãn là tập tin văn bản thuần tuý. Chúng tôi lưu thêm thông số cơ sở (base) để xác định dòng cơ sở sẽ hiển thị nhãn (chỉ dùng trong hiển thị). Mỗi đoạn được lưu trên một dòng, trường đầu là tên từ, là

một chuỗi ký tự bọc trong hai dấu ngoặc kép. Trường thứ hai là điểm bắt đầu của đoạn trong tập tin âm thanh, trường thứ ba là điểm kết thúc của đoạn trong tập tin âm thanh, và trường thứ tư là dòng cơ sở để hiển thị.

“cộng” 33890 40210 51 “hoà” 48231 64791 73 “xã” 64377 82800 94 “hội” 83214 93771 71 “chủ” 98118 106398 76 “nghĩa” 106795 124614 91 “việt” 126270 133722 72 “nam” 137034 157320 88 Bảng 5-2. Ví dụ về tập tin nhãn

Chỉ số bắt đầu và kết thúc được tính bằng số mẫu. Chúng ta có thể đổi ra thời gian bằng cách chia cho tần số lấy mẫu. Quá trình đổi như vậy sẽ làm mất mát thông tin, nên thông số theo mẫu mặc dù phụ thuộc vật lý vào tập tin âm thanh tương ứng nhưng là thông số nguyên thuỷ.

5.1.3. Tập tin văn phạm (grammar file format)

Tập tin văn phạm chúng tôi dùng là dạng cải tiến của dạng BNF. Một văn phạm được lưu trong tập tin văn bản thuần tuý. Mỗi văn phạm gồm danh sách luật. Mỗi luật cách nhau bằng dấu chấm phảy. Hai luật có cùng vế trái có thể viết gộp nhau và phân cách nhau bằng dấu gạch đứng. Các dấu sao đánh dấu ký tự khởi đầu. Nếu có nhiều dấu sao thì dấu cuối cùng có hiệu lực. Các dấu cộng đánh dấu ký tự là phân loại (part of speech). Ký tự phân loại là ký tự được dùng đặc biệt trong xử lý từ mới. Các ký tự hằng được bọc trong dấu ngoặc kép, do đó ký tự hằng cùng tên với ký tự biến cũng không gây xung đột. Người dùng có thể sử dụng các dấu bình chú (comment) giống như ngôn ngữ C++, nghĩa là bình chú dòng và bình chú khối. Bình chú khối được chúng tôi thiết kế để bỏ đi một khối không được dùng trong luật.

//luật khởi đầu *s = n vp; /* phần ngữ danh từ */ +n = "tôi" | "nó"; /* phần ngữđộng từ */ vp = v pl; +v = "đi" | "ra"; +pl = "chơi" | "chợ"; Bảng 5-3. Ví dụ về tập tin văn phạm 5.1.4. Tập tin sơđồ tuyến tính (linear diagram)

Tập tin sơ đồ tuyến tính dùng để lưu sơ đồ chuyển trạng thái tuyến tính. Tập tin này chỉ có tác dụng gỡ rối và minh hoạ. Mỗi một dòng mô tả một phép chuyển từ trạng thái này sang trạng thái khác, ở giữa có một ký hiệu của phép chuyển. Nếu trạng thái đích có chứa ký hiệu đầu ra, ký hiệu đó sẽ được in ngay ở dòng cuối. (0)----[t]---->(1) (0)----[d]---->(5) (0)----[c]---->(8) (1)----[o]---->(2) (2)----[i]---->(3) tôi (4)----[d]---->(5) (5)----[i]---->(6) (6)----[i]---->(7) đi (8)----[c]---->(9) (9)----[d]---->(10) chơi (9)----[e]---->(11) chợ 0 t 1 2 3 “t«i” o i 4 d d 5 i c 8 c 9 d 10 “ch¬i” e 11 “chî” 6 i Bảng 5-4. Ví dụ về tập tin sơđồ tuyến tính

5.2. Phát sinh trong trin khai

Trong triển khai, có một số vấn đề phát sinh mà chúng tôi bỏ qua trong phần lý thuyết nhằm đảm bảo tính đơn giản của mô hình. Phát sinh triển khai sẽ bù đắp những thiếu sót để có thể triển khai một hệ thống hoàn chỉnh dựa trên lý thuyết.

5.2.1. Cơ sở tri thức của quá trình nhận dạng

Trong các bản nhận dạng chạy trên môi trường dòng lệnh, chúng tôi không thiết kế các phép ghi và đọc cơ sở tri thức mà chúng tôi gọi thủ tục huấn luyện ngay ở đầu chương trình. Do đó tri thức sẽ được cập nhật mỗi khi thư mục dữ liệu có dữ liệu huấn luyện mới. Các phiên bản này do đó chỉ phục vụ cho mục đích nghiên cứu.

Trong các phiên bản giao diện đồ hoạ, chúng tôi tải hoặc tạo cơ sở tri thức ở đầu chương trình và ghi lại cơ sở tri thức mỗi khi chương trình kết thúc. Người sử dụng cũng có quyền tải một cơ sở tri thức tại đường dẫn mà anh hay chị ta chỉ ra sau khi chương trình khởi động xong. Người sử dụng cũng có thể ghi cơ sở tri thức xuống tập tin bất kỳ lúc nào để đề phòng mất điện hoặc lỗi hệ thống mà chương trình không kịp kết thúc đúng cách đề ghi cơ sở tri thức.

5.2.2. Nhận dạng trực tuyến

Trong phần lý thuyết, chúng ta nhận dạng dựa trên tập tin. Nhưng thực tế chúng ta cần xử lý dữ liệu vào từ thiết bị thu thanh và nhận dạng trực tuyến. Để làm được việc này chúng tôi dùng một hàng đợi tín hiệu. Mỗi khi chương trình nhận được tín hiệu có dữ liệu ghi âm báo về, chương trình sẽ cập nhật vào một đầu của hàng đợi. Thủ tục nhận dạng hoạt động trên nền thời gian. Mỗi khi trên đầu còn lại của hàng đợi có dữ liệu, thủ tục nhận dạng biến đổi dữ liệu đó thành từ và đưa ra thiết bị đầu ra.

Cách giải quyết như vậy để đảm bảo mô hình lý thuyết không bị phá vỡ, nghĩa là vùng đệm âm thanh cũng sẽ được coi như tập tin, được trừu tượng hoá thành tập tin. Nhưng đồng thời nó cũng phản ánh cách giải quyết đã tồn tại với các thiết bị

vào khác như bàn phím và con chuột. Bàn phím có một vùng đệm có đủ sức chứa 16 phím ấn và con chuột có biến đếm nội tại chứa số lần ấn phím.

class CWaveBufferQueue { protected: ULONG m_BufferLength; ULONG m_NumberOfBuffer; CWaveBuffer *m_FreeList; UCHAR m_FreeListDenial; CWaveBuffer *m_UsedList; UCHAR m_UsedListDenial; ULONG m_UsedPos; public:

CWaveBufferQueue(DWORD dwNumberOfBuffer=32, DWORD dwBufferLength=44100, int nFormat=1); virtual ~CWaveBufferQueue();

double ConsumeSample(); int ListTo(LPCTSTR lpFileName);

public: ULONG GetFreeBufferNumber(); ULONG GetDataBufferNumber(); CWaveBuffer *GetFreeBuffer(); CWaveBuffer *GetFreeBufferList(); CWaveBuffer *GetDataBuffer(); CWaveBuffer *GetDataBufferList();

void EnqueueFreeBuffer(CWaveBuffer *pBuffer); void EnqueueDataBuffer(CWaveBuffer *pBuffer); public:

void EnterCriticalSection() {

while(m_FreeListDenial); m_FreeListDenial = 1; while(m_UsedListDenial); m_UsedListDenial = 1; }

void EnterFreeListSection() { while(m_FreeListDenial); m_FreeListDenial = 1; } void LeaveFreeListSection() { m_FreeListDenial = 0; }

void EnterUsedListSection() { while(m_UsedListDenial); m_UsedListDenial = 1; } void LeaveUsedListSection() { m_UsedListDenial = 0; }

};

Bảng 5-5. Lớp CWaveBufferQueue

Vùng đệm mà chúng tôi thiết kế có số khối dữ liệu cố định và độ dài của mỗi khối cũng cố định. Các thông số này có thể được thay đổi khi không có quá trình nhận dạng, nhưng giữ cố định khi công việc nhận dạng đang tiến hành. Phát sinh triển khai này không nằm ngoài những gì mà các nhà lập trình hệ thống đã đưa ra. Chúng tôi chỉ sử dụng lại giải pháp của họ.

5.2.3. Chuyển đổi trạng thái trực tuyến

Trong phân tích cú pháp, trạng thái được chuyển thông qua việc đưa từ vào sơ đồ chuyển trạng thái đẩy xuống. Mỗi khi có từ được nhận dạng, từ điển mẫu để nhận dạng từ tiếp theo sẽ được thay đổi. Việc thay đổi từ điển dựa vào trạng thái hiện tại và từ vừa mới nhận.

Trong nhận dạng trực tuyến, cụ thể hơn là trường hợp soạn thảo bằng giọng nói, chúng tôi chuyển trạng thái hiện tại, cũng là từ điển mẫu hiện tại, bằng cách gửi một thông điệp cho khung làm việc của hệ nhận dạng. Khung làm việc sẽ chịu tránh nhiệm phản ứng lại và thay đổi trạng thái. Cách làm như vậy không những đơn giản hoá công việc chuyển trạng thái mà còn không làm thay đổi thủ tục nhận dạng.

5.2.4. Huấn luyện trực tuyến và huấn luyện hàng loạt

Trong hầu hết các nghiên cứu về lĩnh vực học máy, việc huấn luyện thường được thực hiện trên một cơ sở dữ liệu hoặc một bảng dữ liệu đã được lưu trữ sẵn trong máy. Do đó bộ huấn luyện thường hoạt động độc lập với bộ nhận dạng, nên bộ nhận dạng có kích thước nhỏ. Và bộ huấn luyện có vai trò chuyển từ dữ liệu thô thành cơ sở tri thức. Bộ nhận dạng hoạt động trên cơ sở tri thức đã được chuyển đổi đó. Cách này được áp dụng trong giai đoạn đầu nghiên cứu của chúng tôi. Mặc dù cách này có ưu điểm là dễ dàng triển khai (không cần giao diện) và có thể huấn

luyện được hàng loạt (nhiều tập tin cùng một lượt huấn luyện). Nhưng cách này tỏ ra không thân thiện với người sử dụng. Chính vì vậy chúng tôi áp dụng phương pháp huấn luyện trực tuyến.

Phương pháp huấn luyện trực tuyến cho phép người dùng ghi âm và thêm vào cơ sở tri thức ngay trên hộp thoại. Mặc dù phương pháp huấn luyện trực tuyến không cho phép chúng ta huấn luyện nhiều tập tin một lúc, nhưng nó có rất nhiều lợi điểm. Thứ nhất, nó rất gần gũi với người dùng do mọi người dùng máy tính đều rất quen với hộp thoại. Thứ hai, nó cho thấy kết quả ngay do chúng ta có thể huấn luyện rồi nhận dạng trên cơ sở tri thức mới. Thứ ba, nó không cần lưu một lượng dữ liệu trung gian như âm thanh và nhãn, đây là lượng dữ liệu không nhỏ do bản thân mỗi tập tin đa phương tiện là rất lớn. Và thứ tư, chúng ta không cần nhiều các công cụ trung gian và các thao tác trung gian như đánh nhãn, ghi âm, huấn luyện. Tất cả được tích hợp trong một chương trình, cụ thể hơn là trong một tập tin thi hành.

5.3. Các thư vin dùng để trin khai

Trong quá trình tiến hành lập trình các chương trình nhận dạng, chúng tôi có dùng đến một số thư viện. Một số thư viện được cung cấp sẵn trong Windows và được chúng tôi khai thác trực tiếp. Đa số các thư viện còn lại đều được chúng tôi lập trình. Chúng tôi giới thiệu trong phần này các thư viện đóng vai trò hạt nhân của hệ thống.

5.3.1. WaveBuffer

Vùng đệm âm thanh là một vùng nhớ có độ dài cố định dùng để chứa âm thanh ghi hoặc được tải lên để xử lý. Chúng tôi thiết kế lớp dữ liệu này chủ yếu để ghi âm.

Mỗi vùng đệm có một con trỏ tới cửa sổ quản lý nó. Con trỏ này cho phép chúng ta tiếp tục chuyển tiếp (forward) thông điệp ghi xong hoặc chơi xong. Do đó không chỉ có bộ phần ghi và chơi âm thanh, các bộ phận khác liên quan tới vùng đệm cũng có thể nhận được thông điệp.

Mỗi vùng đệm có một con trỏ tới hàng đợi quản lý nó. Đây là cơ chế cho phép bộ phận ghi âm có thể thao tác với nhiều hàng đợi khác nhau. Khi vùng đệm đã được thao tác xong, nó được trả về và có thể được gắn vào hàng đợi nào là tuỳ thuộc vào con trỏ hàng đợi của nó.

Mỗi hàng đợi được gắn với một tiêu đề (header) âm thanh. Trong quá trình ghi âm và chơi lại, tiêu đề này được bộ phận âm thanh sử dụng. Do vậy chúng tôi gắn liền với vùng đệm cho tiện thao tác.

Hai thao tác SendToPlayer và SendToRecorder cũng được gắn liền với vùng đệm do hai thao tác này sử dụng thông tin nội bộ của vùng đệm.

class CWaveBuffer { protected:

WAVEHDR m_WaveHeader; UCHAR m_SampFormat; CWaveBuffer *m_NextBuffer;

class CWaveBufferQueue *m_OwnerQueue; CWnd *m_OwnerWindow;

public:

CWaveBuffer(DWORD dwBufferLength=44100, CWaveBuffer *pNextBuffer=0, UCHAR nFormat=0); virtual ~CWaveBuffer();

void ResizeBuffer(DWORD dwBufferLength, int nFormat); void SendToPlayer(HWAVEOUT hPlayer);

void SendToRecorder(HWAVEIN hRecorder); public:

void SetOwnerQueue(class CWaveBufferQueue *pQueue); void SetOwnerWindow(class CWnd *pWindow);

void SetNextBuffer(class CWaveBuffer *pBuffer); class CWaveBufferQueue * GetOwnerQueue();

class CWnd * GetOwnerWindow(); class CWaveBuffer *GetNextBuffer(); ULONG GetLength();

LPSHORT GetArray();

double GetSample(ULONG pos); };

Bảng 5-6. Lớp CWaveBuffer 5.3.2. WaveBufferQueue

Hàng đợi các vùng đệm âm thanh vừa được coi là tập tin âm thanh (wave file) vừa được coi là hàng đợi các tín hiệu ghi âm. Có thể coi đây là một tập tin trực tuyến. Một đầu của hàng đợi được bộ ghi âm sử dụng để đẩy các thông tin ghi được vào. Đầu kia của hàng đợi được bộ nhận dạng sử dụng để lấy các thông tin đã ghi và nhận dạng.

Để giải quyết tranh chấp giữa bộ ghi âm và bộ nhận dạng, chúng tôi cung cấp các hàm giải quyết tranh chấp như EnterCriticalSection và LeaveCriticalSection, xem trong [18]. Mặc dù cơ chế thông điệp (message) của Windows giải quyết rất tốt tranh chấp, nhưng chúng tôi không muốn dùng cơ chế này do hàng đợi cần được thao tác rất nhanh mà thông điệp có xung hướng làm chậm các thao tác cơ bản lại. Các hàm giải quyết tranh chấp cũng được viết nội tuyến (inline) để tăng tốc tối đa các thao tác cơ sở.

Chúng tôi tổ chức hàng đợi thành hai phần, một phần dùng để chứa các vùng đệm rỗng và phần kia chứa các hàng đợi có dữ liệu. Do đó tổng số các vùng đệm luôn là cố định. Điều này để đảm bảo hàng đợi không phát triển quá đà và xâm chiếm các vùng nhớ của các bộ phận khác. Khi tất cả các vùng đệm đã dùng, dữ liệu ghi âm đành phải bỏ phí (giống như việc chúng ta đánh quá 16 phím và chưa có chương trình xử lý, chương trình xử lý phím ấn phát ra tiếng bíp). Thuật toán về hàng đợi được tham khảo trong [11]

5.3.3. WaveRecorder

Bộ phận ghi âm đóng vai trò quan trọng trong các hệ nhận dạng trực tuyến. Chúng tôi thiết kế bộ ghi âm dựa trên hàng đợi các vùng đệm và hệ thống thư viện âm thanh mmsystem được Windows cung cấp.

Bộ ghi âm hỗ trợ hai chế độ, ghi âm với chiều dài hữu hạn dùng trong huấn luyện và ghi âm sử dụng hàng đợi vùng đệm được dùng trong nhận dạng trực tuyến. Trong chế độ trực tuyến, tín hiệu kết thúc do người dùng gửi tới (hoặc do họ đóng chương trình nhận dạng, hoặc do họ ấn nút dừng ghi).

class CWaveRecorder : public CWnd { protected: WAVEFORMATEX m_RecordFormat; HWAVEIN m_RecordDevice; CWaveBufferQueue *m_RecordQueue; public: CWaveRecorder(); virtual ~CWaveRecorder(); public:

void OpenRecorder(USHORT BPC, USHORT CPS, ULONG SPS); void CloseRecorder();

void RecordBuffer(CWaveBuffer *pBuffer); void StopBuffer();

void RecordBufferQueue(CWaveBufferQueue *pQueue); void StopBufferQueue();

};

Bảng 5-7. Lớp CWaveRecorder

Trong triển khai, chúng tôi coi bộ phận ghi như một khung làm việc độc lập, cụ thể hơn là một cửa sổ con độc lập. Do đó việc đón các thông điệp gửi từ thiết bị ghi âm có thể thực hiện bằng cơ chế thông điệp của Windows.

5.3.4. WaveMapper

Mặc dù một ánh xạ (mapper) độc lập với âm thanh, nhưng chúng tôi đặt tên với nhóm từ wave ở đầu để thống nhất với các phần khác trong thư viện và để phân biệt với ánh xạ tổng quát được đặt tên MetaMapper. Chúng tôi thiết kế MetaMapper như là lược đồ tổng quát của ánh xạ (trong đó các thủ tục đều được triển khai rỗng)

Một phần của tài liệu Giải quyết vấn đề nhận dạng tiếng Việt bằng phân tích cú pháp (Trang 87)