آموزش جامع کار با پکیج Audio Waveforms در فلاتر؛ ضبط و نمایش موج صدا بهصورت زنده
در خیلی از اپلیکیشنهای صوتی (مثلاً یادداشت صوتی، چت صوتی، ضبط پادکست، ابزار موسیقی) یکی از جنبههای جذاب و حرفهای تجربه کاربری، «نمایش موج صدا (waveform) هنگام ضبط یا پخش» است. امکانی که به کاربر میگوید «صدام داری ضبط میکنی»، یا «در حال پخش هستیم» و همچنین باعث میشود کاربر حس بهتری از تعامل بگیرد.
پکیج audio_waveforms برای فلاتر آمده تا این کار را به سادگی ممکن کند: هم رکورد صدا همراه با تولید موج صدا بصورت زنده، و هم پخش فایل صوتی همراه با نمایش موج از فایل صوتی. با استفاده از این پکیج میتوانید ابزارهای صوتی حرفهای بزنید بدون اینکه از صفر همه چیز را بنویسید.

ویژگیهای اصلی
طبق مستندات این پکیج: Dart packages
- امکان ضبط صدا با کنترل کامل (شروع، توقف، مکث) و ذخیره فایل. Dart packages+1
- تولید موج صوت (waveform) حین ضبط یا پس از ضبط، و نمایش آن در ویجت. Dart packages
- قابلیت پخش فایل صوتی با نمایش موج آن؛ کنترلهای پخش، مکث، توقف، و نیز پیمایش (seek) داخل موج. Dart packages
- امکان سفارشیسازی بسیار زیاد: رنگ موج، ضخامت، فضای میان موجها، جریان بهروزرسانی، پیمایش موج (scroll) و … Dart packages
- پشتیبانی از اندروید و iOS (بهعنوان پلتفرمهای اصلی در فلاتر)؛ نیازمندیها در سطح پلتفرم تعریف شدهاند. Dart packages
نصب و تنظیم اولیه
۱. افزودن به pubspec.yaml
در فایل pubspec.yaml پروژه فلاتر، بخش dependencies را باز کرده و این پکیج را اضافه کنید (نسخه ممکن است جدیدتر باشد؛ در زمان نگارش نسخه 1.3.0 است) Dart packages
dependencies:
flutter:
sdk: flutter
audio_waveforms: ^1.3.0
سپس اجرای:
flutter pub get
۲. تنظیمات پلتفرم
اندروید
- حداقل SDK اندروید (minSdkVersion) باید حداقل 21 باشد. Dart packages
- در فایل
android/app/src/main/AndroidManifest.xmlباید مجوز ضبط صدا اضافه شود:<uses-permission android:name="android.permission.RECORD_AUDIO" />Dart packages
iOS
- در فایل
ios/Runner/Info.plistباید توضیحی برای استفاده از میکروفون اضافه شود:<key>NSMicrophoneUsageDescription</key> <string>توضیح شما برای استفاده از میکروفون</string>Dart packages - در فایل
ios/Podfileباید پلتفرم iOS حداقل «12.0» تعریف شود. Dart packages
مرحلهٔ پاکسازی
پکیج توصیه میکند پس از افزودن، اپ را از دستگاه حذف کرده و دستور زیر را بزنید تا تمیز شود:
flutter clean
flutter pub get
ساختار و API پکیج
برای کار با ضبط صدا و موج صوت، مهمترین کلاسها و ویجتها عبارتاند از:
RecorderController: کنترلر برای ضبط صدا + تولید موج. Dart packagesAudioWaveforms: ویجتی برای نمایش موج صدا در حین ضبط. Dart packagesPlayerController: کنترلر برای پخش فایل صوتی. Dart packagesAudioFileWaveforms: ویجتی برای نمایش موج فایل صوتی هنگام پخش. Dart packages
متدهای مهم در RecorderController
checkPermission()— بررسی و درخواست مجوز میکروفون. Dart packagesrecord({path, androidEncoder, iosEncoder, androidOutputFormat, updateFrequency, ...})— شروع ضبط، با گزینههایی برای مسیر ذخیره، انکدر، فرمت، نرخ بهروزرسانی موج و … Dart packagespause()— موقتا ضبط را متوقف میکند (و قابل ادامه است). Dart packagesstop({callReset = false})— ضبط را به پایان میرساند؛ اگرcallResetرا true دهید، موجها پاک میشوند. Dart packagesreset()— پاک کردن وضعیت موج، آماده ضبط دوباره. Dart packagesrefresh()— بازنشانی موقعیت اسکرول موجها (اگر قابلیت پیمایش فعال باشد). Dart packages- رویدادها (Streams) که میتوان به آنها گوش داد:
onCurrentDuration: مدت زمان جاری ضبط. Dart packagesonRecorderStateChanged: وضعیت ضبط (در حال ضبط، متوقف، مکث) Dart packagesonRecordingEnded: پس از اتمام ضبط، مدت زمان نهایی فایل صوتی. Dart packages
- وضعیتهایی مانند
hasPermission,isRecording,recorderState,elapsedDuration,recordedDuration,waveData(داده موج خام) در کنترلر موجود هستند. Dart packages
سفارشیسازی ویجت AudioWaveforms
مثالی از نحوه استفاده:
AudioWaveforms(
controller: recorderController,
size: Size(MediaQuery.of(context).size.width, 200),
shouldCalculateScrolledPosition: true,
enableGesture: true,
waveStyle: WaveStyle( /* تنظیمات ظاهری */ ),
)
در مستندات آمده است که میتوانید ویژگیهایی مانند continuousWaveform, waveformType, playerWaveStyle و … را تنظیم کنید. Dart packages
نکات حرفهای / مباحث قابل توجه
- مجوز میکروفون: حتما مجوز RECORD_AUDIO در اندروید و NSMicrophoneUsageDescription در iOS داده شود، وگرنه ضبط کار نخواهد کرد.
- minSdkVersion: در اندروید حداقل 21.
- فرمت فایل خروجی: اگر فرمت یا انکدر را تغییر دهید، مطمئن شوید پسوند فایل، نرخ نمونه (sample rate) و بیتریت (bitrate) با آن انکدر مطابقت دارد — زیرا این پکیج بر پایه
MediaRecorder(اندروید) وAVAudioRecorder(iOS) کار میکند. Dart packages - تولید موج در زمان ضبط: برای اینکه موج در زمان ضبط ایجاد شود، باید
updateFrequencyرا تنظیم کنید؛ مثلا هر 100 میلیثانیه دادهها بهروز شوند. Dart packages - نمایش موج پس از ضبط یا حین پخش: اگر موجها قرار است بعدا نمایش داده شود (مثلاً فایل را پخش میکنید)، میتوانید از
drop-inویجتAudioFileWaveformsاستفاده کنید و حتی دادههای موج را باextractWaveformDataذخیره کنید برای استفاده بعدی. Dart packages - پیمایش موج (scrolling): اگر بخواهید کاربر بتواند موج را پیمایش کند، پارامتر
enableGesture: trueوshouldCalculateScrolledPosition: trueرا فعال کنید. سپس میتوانید موقعیت موج پیمایششده را از کنترلر بخوانید (currentScrolledDuration). Dart packages - پاکسازی منابع: بعد از ضبط یا پخش حتماً کنترلرها را dispose کنید تا منابع آزاد شوند.
- نمایش مناسب در UI: به اندازه ویجت، ضخامت خطوط موج، فاصله بین پیکها، رنگها توجه کنید تا در نسخههای مختلف دستگاهها خوب دیده شود.
- ذخیره و مسیر فایل: مسیر ذخیره فایل ضبط را بهدرستی انتخاب کنید—ممکن است بخواهید در مسیر موقت دستگاه یا مسیر خاص ذخیره کنید.
- محدودیتها و تست روی دستگاه حقیقی: شبیهسازها ممکن است ضبط میکروفون را دقیق پیاده نکنند؛ حتما روی دستگاه واقعی تست کنید.
- هماهنگی با حالت صوتی سیستم: در iOS برخی موارد مربوط به AudioSession وجود دارد؛ پارامتر
overrideAudioSessionدر کنترلر وجود دارد تا اگر بخواهید تنظیمات خودتان را انجام دهید. Dart packages
مثال عملی: ضبط صدا همراه با نمایش موج
در ادامه یک مثال کامل (در سطح ساده ولی قابل توسعه) ارائه میدهم که در آن یک صفحهٔ فلاتر داریم که کاربر میتواند ضبط صدا را شروع کند، متوقف کند، در حال ضبط موج صوت را میبیند، و پس از توقف مسیر فایل ضبطشده را دریافت کند.
فایل pubspec.yaml
dependencies:
flutter:
sdk: flutter
audio_waveforms: ^1.3.0
فایل record_page.dart
import 'package:flutter/material.dart';
import 'package:audio_waveforms/audio_waveforms.dart';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
class RecordPage extends StatefulWidget {
@override
_RecordPageState createState() => _RecordPageState();
}
class _RecordPageState extends State<RecordPage> {
final RecorderController _recorderController = RecorderController();
String? _recordedFilePath;
@override
void initState() {
super.initState();
// ابتدا مجوز میکروفون را بررسی کن
_recorderController.checkPermission();
}
@override
void dispose() {
_recorderController.dispose();
super.dispose();
}
Future<String> _getFilePath() async {
final dir = await getApplicationDocumentsDirectory();
final path = '${dir.path}/${DateTime.now().millisecondsSinceEpoch}.m4a';
return path;
}
void _startRecording() async {
if (_recorderController.hasPermission) {
final path = await _getFilePath();
// شروع ضبط با تنظیمات دلخواه
await _recorderController.record(
path: path,
androidEncoder: AndroidEncoder.aac,
androidOutputFormat: AndroidOutputFormat.mpeg4,
iosEncoder: IosEncoder.kAudioFormatMPEG4AAC,
updateFrequency: const Duration(milliseconds: 100),
);
setState(() {
_recordedFilePath = null;
});
} else {
// پیغامی برای کاربر نمایش دهید که مجوز لازم نیست
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('نیاز به مجوز میکروفون دارید')),
);
}
}
void _pauseRecording() async {
await _recorderController.pause();
}
void _stopRecording() async {
final path = await _recorderController.stop(false);
setState(() {
_recordedFilePath = path;
});
// حالا فایل ضبط شده در مسیر path قرار دارد
print('Recorded file path: $path');
}
void _resetRecording() async {
await _recorderController.reset();
setState(() {
_recordedFilePath = null;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ضبط صدا با نمایش موج'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
AudioWaveforms(
controller: _recorderController,
size: Size(MediaQuery.of(context).size.width, 100),
waveStyle: WaveStyle(
waveColor: Colors.blueAccent,
showMiddleLine: false,
extendWaveform: true,
spacing: 4.0,
),
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton(
onPressed: _startRecording,
child: Text('شروع ضبط'),
),
ElevatedButton(
onPressed: _pauseRecording,
child: Text('مکث'),
),
ElevatedButton(
onPressed: _stopRecording,
child: Text('توقف'),
),
ElevatedButton(
onPressed: _resetRecording,
child: Text('ریست'),
),
],
),
const SizedBox(height: 20),
if (_recordedFilePath != null)
Text('مسیر فایل ضبطشده: $_recordedFilePath'),
],
),
),
);
}
}
توضیح کد
- یک
RecorderControllerساختهایم تا ضبط و داده موج را کنترل کنیم. - در
initState()مجوز میکروفون را میگیریم (checkPermission()). - متدی برای تولید مسیر فایل ضبط (
_getFilePath()) داریم که در پوشه Documents دستگاه ذخیره میکند (با پسوند.m4a). _startRecording()شروع ضبط را انجام میدهد، با تنظیم انکدرها (اندروید: AAC، خروجی MPEG4؛ iOS: MPEG4AAC) و نرخ بهروزرسانی موج هر 100 میلیثانیه._pauseRecording()برای مکث ضبط._stopRecording()ضبط را متوقف میکند، مسیر فایل ضبطشده را از کنترلر میگیرد و در حالتsetStateنگه میدارد تا نمایش دهد._resetRecording()موجها و وضعیت ضبط را ریست میکند.- در بخش UI:
- ویجت
AudioWaveformsباcontroller: _recorderControllerداریم که موج صوت در حال ضبط را نمایش میدهد. - با استفاده از
WaveStyleکمی ظاهرسازی کردهایم (رنگ موج، فضای بین موجها، غیرفعالسازی خط میانی). - دکمههایی برای کنترل ضبط (شروع، مکث، توقف، ریست).
- در صورت وجود مسیر فایل ضبطشده، آن را نمایش میدهیم.
- ویجت
خروجی کد :

نکات تکمیلی
- میتوانید نمایش مدت زمان ضبط را از طریق
onCurrentDurationکنترلر بگیرید و در UI نشان دهید. - اگر بخواهید پس از ضبط، فایل را پخش کرده و موج ضبطشده را نمایش دهید، میتوانید از
PlayerController+AudioFileWaveformsاستفاده کنید. - برای پروژههای بزرگتر ممکن است بخواهید انتخاب فرمتها، نرخ نمونه، بیتریت، مسیر سفارشی، و مدیریت خطاها را اضافه کنید.
- برای بهبود UX، میتوانید نمایش پیام «در حال ضبط» با انیمیشن، یا دکمهٔ شروع/توقف متغیر، یا نمایش موج در نوار وضعیت اضافه کنید.
جمعبندی
پکیج audio_waveforms یکی از ابزارهای بسیار کاربردی برای توسعهدهندگان فلاتر است که قصد دارند قابلیتهای ضبط و نمایش موج صوت را به اپ خود اضافه کنند. با رابط کاربری ساده ولی امکانات قوی، میتواند در پروژههای یادداشت صوتی، چت صوتی، ضبط موسیقی، یا حتی پادکست مورد استفاده باشد.
دیدگاهتان را بنویسید