Flutter: Tạo tính năng ghi âm có sóng âm mô phỏng
Hiện nay, các ứng dụng moble có tính năng ghi âm đang rất phổ biến. Việc đưa sóng âm mô phỏng trong ghi âm sẽ giúp người dùng có cái nhìn trực quan hơn về cường độ âm thanh và biến đổi của nó theo thời gian.
Sau đây là các bước thực hiện:
Bước 1: Thêm thư viện và xin quyền
Thêm thư viện audio_waveforms vào file pubspec.yaml:
Xin quyền record:
- Đối với android:
- Đối với IOS:
Bước 2: Tạo màn hình có tính năng ghi âm và import the package
Bước 3: Tạo các biến local
Trong đó:
- RecorderController là 1 biến controller được sử dụng để điều khiển việc ghi âm (recording),.
- PlayerController là một biến controller được sử dụng để điều khiển việc phát (playback) âm thanh
- isRecording là biến trạng thái
- pathVoice để đề cập đến đường dẫn tới một tập tin hoặc thư mục trong hệ thống tệp tin.
Bước 4: Tạo các hàm xử lý
Ngoài initState và dispose , chúng ta sử dụng 3 hàm xử lý chính là startRecording (ghi âm), stopRecording (dừng ghi) và playAndPause (phát và tạm dừng)
-
initState
playerController = PlayerController();: khởi tạo một đối tượng PlayerController mới và gán cho biến playerController. Đối tượng PlayerController là một class được sử dụng để điều khiển việc phát âm thanh.
recorderController = RecorderController(): khởi tạo một đối tượng RecorderController mới và gán cho biến recorderController. Đối tượng RecorderController là một class được sử dụng để điều khiển việc ghi âm.
..androidEncoder = AndroidEncoder.aac: cấu hình thuộc tính androidEncoder của đối tượng recorderController với giá trị wf.AndroidEncoder.aac. Điều này có thể đặt bộ mã hóa âm thanh cho ghi âm trên các thiết bị Android là AAC (Advanced Audio Coding).
..androidOutputFormat = AndroidOutputFormat.mpeg4: cấu hình thuộc tính androidOutputFormat của đối tượng recorderController với giá trị AndroidOutputFormat.mpeg4. Điều này có thể đặt định dạng tệp đầu ra cho ghi âm trên các thiết bị Android là MPEG-4.
..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC: cấu hình thuộc tính iosEncoder của đối tượng recorderController với giá trị wf.IosEncoder.kAudioFormatMPEG4AAC. Điều này có thể đặt bộ mã hóa âm thanh cho ghi âm trên các thiết bị iOS là MPEG-4 AAC (Advanced Audio Coding).
..sampleRate = 16000: cấu hình thuộc tính sampleRate của đối tượng recorderController với giá trị 16000. Điều này có thể đặt tần số mẫu âm thanh cho quá trình ghi âm là 16000 Hz.
Tổng quát, hàm initState trên khởi tạo và thiết lập các thuộc tính cần thiết cho đối tượng playerController và recorderController để chuẩn bị sẵn sàng cho việc điều khiển việc phát và ghi âm trong chương trình.
-
Dispose
Hàm dispose() thường được sử dụng để giải phóng tài nguyên và dọn dẹp sau khi sử dụng một đối tượng.
-
startRecording
Hàm startRecording() được sử dụng để bắt đầu quá trình ghi âm trong chương trình:
if (await recorderController.checkPermission()): kiểm tra xem có quyền ghi âm được cấp cho ứng dụng hay không. Hàm checkPermission() được gọi trên đối tượng recorderController để kiểm tra quyền ghi âm và trả về một giá trị boolean.
if (playerController.playerState == PlayerState.playing): kiểm tra xem trạng thái của đối tượng playerController có đang trong trạng thái phát (playing) không. playerState là một thuộc tính của playerController để biểu thị trạng thái hiện tại của việc phát âm thanh hoặc video.
await playerController.stopPlayer(): Nếu đối tượng playerController đang trong trạng thái phát, dòng này được sử dụng để dừng quá trình phát bằng cách gọi hàm stopPlayer() trên đối tượng playerController.
await recorderController.record(): Sử dụng để bắt đầu quá trình ghi âm bằng cách gọi hàm record() trên đối tượng recorderController.
setState(() { isRecording = true; }): Sử dụng để cập nhật trạng thái của biến isRecording. Hàm setState() được gọi để thông báo cho framework rằng trạng thái của widget đã thay đổi, và giao diện người dùng cần được cập nhật.
catch (e) { print(“Lỗi ghi âm: $e”); }: Bắt các ngoại lệ có thể xảy ra trong quá trình ghi âm và hiển thị thông báo lỗi trên bảng điều khiển hoặc terminal. Nếu có bất kỳ lỗi nào xảy ra trong khối try, thông điệp lỗi sẽ được in ra màn hình.
-
stopRecording
Hàm stopRecording() được sử dụng để dừng quá trình ghi âm trong chương trình:
String? path = await recorderController.stop();: gọi hàm stop() trên đối tượng recorderController để dừng quá trình ghi âm. Kết quả trả về là một chuỗi đường dẫn (path) tới tệp ghi âm đã được lưu trữ. Biến path có kiểu dữ liệu String?, có thể là null hoặc chứa một đường dẫn hợp lệ.
setState(() { isRecording = false; playerController.preparePlayer(path: path!); pathVoice = path; });: sử dụng hàm setState() để cập nhật trạng thái của widget. Trạng thái isRecording được đặt là false để chỉ rằng quá trình ghi âm đã dừng. Tiếp theo, hàm preparePlayer() được gọi trên đối tượng playerController với đường dẫn ghi âm (path) như một tham số để chuẩn bị việc phát âm thanh từ tệp ghi âm. Cuối cùng, biến pathVoice được cập nhật với giá trị của path.
catch (e) { print(“Lỗi dừng ghi âm: $e”); }: bắt các ngoại lệ có thể xảy ra trong quá trình dừng ghi âm và hiển thị thông báo lỗi trên bảng điều khiển hoặc terminal. Nếu có bất kỳ lỗi nào xảy ra trong khối try, thông điệp lỗi sẽ được in ra màn hình.
-
playAndPause
Hàm playandPause() được sử dụng để điều khiển quá trình phát và tạm dừng phát của đối tượng playerController:
playerController.playerState == wf.PlayerState.playing: kiểm tra trạng thái hiện tại của đối tượng playerController xem có đang trong trạng thái đang phát (playing) hay không. playerState là một thuộc tính của playerController để biểu thị trạng thái hiện tại của việc phát âm thanh hoặc video.
await playerController.pausePlayer(): Nếu playerController đang trong trạng thái đang phát, dòng này được sử dụng để tạm dừng quá trình phát bằng cách gọi hàm pausePlayer() trên playerController.
await playerController.startPlayer(finishMode: FinishMode.pause): Nếu playerController không trong trạng thái đang phát, dòng này được sử dụng để bắt đầu quá trình phát bằng cách gọi hàm startPlayer() trên playerController. Tham số finishMode được đặt là FinishMode.pause, cho biết rằng khi kết thúc quá trình phát, nó sẽ dừng lại và sẵn sàng để tiếp tục phát từ điểm đã dừng.
setState(() { });: sử dụng hàm setState() để thông báo cho framework rằng trạng thái của widget đã thay đổi, và giao diện người dùng cần được cập nhật. Trong trường hợp này, không có bất kỳ sự thay đổi nào được cập nhật trong hàm này, vì vậy hàm trống ({ }) được truyền vào setState().
Bước 5: Tạo giao diện và ghép các hàm xử lý
AudioWaveforms và AudioFileWaveforms là 2 widget được dùng để hiện thị sóng âm trong quá trình ghi âm và phát ghi âm.
Ở đây, chúng ta có thể tùy chỉnh giao diện của waveform bằng cách thay đổi các thuộc tính: enableGesture: kích hoạt các cử chỉ (gesture) trên widget AudioWaveforms, cho phép người dùng tương tác với nó.
- waveStyle (đây là thuộc tính để tùy chỉnh kiểu hiển thị của sóng âm thanh. Trong đoạn mã, ta sử dụng WaveStyle để cấu hình các thuộc tính sau:
- gradient: ui.Gradient.linear(…): Đây là thuộc tính để tạo gradient màu sắc cho sóng âm thanh. Gradient được tạo bằng cách sử dụng ui.Gradient.linear() với điểm bắt đầu và điểm kết thúc trên widget và danh sách các màu gradient.
- extendWaveform: true: Thuộc tính này chỉ định xem sóng âm thanh có được mở rộng (extend) ra ngoài widget hay không.
- showMiddleLine: false: Thuộc tính này chỉ định xem có hiển thị đường kẻ giữa sóng âm thanh hay không.)
- size:Thuộc tính này xác định kích thước của sóng âm.
- recorderController: recorderController: Thuộc tính này liên kết recorderController với widget AudioWaveforms, cho phép widget sử dụng dữ liệu ghi âm từ recorderController để hiển thị sóng âm thanh.
- playerController: playerController: Thuộc tính này liên kết recorderController với widget AudioFileWaveforms, cho phép widget sử dụng dữ liệu ghi âm từ playerController để hiển thị sóng âm thanh.
Và còn những thuộc tính khác chưa được đề cập đến trong bài viết này.
Vậy là ứng dụng của bạn đã có thể ghi âm và mô phỏng song âm rồi!
Tóm lại, waveform là một công cụ quan trọng trong ghi âm, cho phép bạn xem và làm việc với thông tin âm thanh theo cách trực quan và chi tiết.
Leave a Reply
Want to join the discussion?Feel free to contribute!