import 'package:ffmpeg_kit_flutter/ffmpeg_kit.dart';
import 'package:ffmpeg_kit_flutter/return_code.dart';
/// 透過 FFmpeg 後處理對聲音進行降噪音
/// 使用內建的 afftdn (目前版本無法附加額外參數)
Future<void> audioNoiseCanceling(String inputFilePath, String outputFilePath)async {
// FFmpeg command to remove noise using the 'afftdn' filter
String command = '-i $inputFilePath -af afftdn $outputFilePath';
// 檢查檔案是否已經存在,若存在則刪除
final outputFile = File(outputFilePath);
if (await outputFile.exists()) {
try {
await outputFile.delete();
print('Existing file deleted: $outputFilePath');
} catch (e) {
print('Failed to delete existing file: $e');
}
}
Tag: dart
-
Flutter – 透過 FFmpeg 為聲音降噪
-

Dart 程式語言命名原則
- 資料夾和檔案名稱
使用小寫英數字加底線,例如:models\customer_model.dart - Class 類別名稱
使用 Upper Camel Case 大駝峰式命名,例如:class CustomerModel - 分辨 public 和 private
類別的屬性和方法名稱若有底線,則代表 private,反之則為 public,例如:class _CustomerModel
(Dart 沒有 public 和 private 關鍵字) - 變數和函數名稱
使用 Lower Camel Case 小駝峰式命名,例如:int customerId = -1; - 建立新物件時可省略 new 這關鍵字
例如:return new CustomerModel(); 可以寫成 return CustomerModel();
- 資料夾和檔案名稱
-

Dart 的物件繼承
- extends 繼承單一物件
- implements 繼承且覆寫所有方法 (Dart 沒有提供 interface 的功能,但可透過 implements 達到相同目的)
- mixins 繼承多個物件(多重繼承)
-

Flutter 範例專案 Caculator 計算機 App
A Caculator App project for demonstrating Flutter.

main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:caculator/daos/cacu_dao.dart';
import 'package:caculator/daos/value_viewer_dao.dart';
import 'package:caculator/screens/caculate_screen.dart';
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_)=> CacuDao()),
ChangeNotifierProvider(create: (_) => ValueViewerDao())],
child: const AppEntryPoint()
)
);
}
class AppEntryPoint extends StatelessWidget {
const AppEntryPoint({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Caculator',
theme: ThemeData(
primarySwatch: Colors.blueGrey,
),
routes: {
"/caculate":(BuildContext context) => CaculateScreen(),
},
initialRoute: "/caculate",
);
}
}models\cacu.dart
class Cacu {
String cacuValue; // Value for caculate
CacuType cacuType; // Caculate type
Cacu(this.cacuValue, this.cacuType);
}
enum CacuType {
none,
addition,
subtraction,
multiplication,
division,
}daos\cacu_dao.dart
import 'package:flutter/material.dart';
import 'package:caculator/models/cacu.dart';
class CacuDao extends ChangeNotifier {
List<Cacu> cacuList = [];
List<Cacu> getCacus() {
return cacuList;
}
/// Insert value for caculate later
void insertCacu(Cacu cacu) {
cacuList.add(cacu);
notifyListeners();
}
/// Update caculate type to value
void clearCacu() {
cacuList.clear();
notifyListeners();
}
}daos\value_viewer_dao.dart
import 'package:flutter/material.dart';
class ValueViewerDao extends ChangeNotifier {
double value = 0;
/// Update caculate type to value
void updateValue(double value) {
this.value = value;
notifyListeners();
}
}components\common_functions.dart
import 'package:caculator/models/cacu.dart';
class CommonFunctions {
static String getCacuSign(CacuType cacuType) {
switch (cacuType) {
case CacuType.addition:
return "+";
case CacuType.subtraction:
return "-";
case CacuType.multiplication:
return "x";
case CacuType.division:
return "÷";
default:
return "";
}
}
}cacu_component.dartimport 'package:flutter/material.dart';
import 'package:caculator/models/cacu.dart';
import 'package:caculator/components/common_functions.dart';
// ignore: must_be_immutable
class CacuComponent extends StatefulWidget {
Cacu cacu;
CacuComponent(this.cacu, {super.key});
@override
State createState() {
return _CacuComponent();
}
}
class _CacuComponent extends State<CacuComponent> {
@override
Widget build(BuildContext context) {
Widget cacuValueText = Text(
widget.cacu.cacuValue,
);
Widget cacuTypeText = Text(
CommonFunctions.getCacuSign(widget.cacu.cacuType),
);
return Card(
child: ListTile(
title: Row(children: [
cacuValueText,
const SizedBox(width: 10),
cacuTypeText,
]),
),
);
}
}screens\caculate_screen.dart
import 'dart:async';
import 'package:caculator/components/common_functions.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:caculator/daos/cacu_dao.dart';
import 'package:caculator/components/cacu_component.dart';
import 'package:caculator/models/cacu.dart';
// ignore: must_be_immutable
class CaculateScreen extends StatefulWidget {
CaculateScreen({super.key});
Cacu currentCacu = Cacu('0', CacuType.none);
@override
State createState() {
return _CaculateScreen();
}
}
class _CaculateScreen extends State<CaculateScreen> {
final ScrollController _scrollController = ScrollController();
@override
Widget build(BuildContext context) {
Timer(const Duration(milliseconds: 500), () => _scrollController.jumpTo(_scrollController.position.maxScrollExtent));
Widget valueViewer = Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 250,
margin: const EdgeInsets.all(15.0),
padding: const EdgeInsets.all(3.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.blueAccent)
),
child: Text(
widget.currentCacu.cacuValue,
textAlign: TextAlign.right,
style: const TextStyle(fontSize: 20),),
),
Text(CommonFunctions.getCacuSign(widget.currentCacu.cacuType)),
],
);
Widget keybooards = Column(children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 70.0,
child: OutlinedButton(
child: const Text('AC',
overflow: TextOverflow.clip,
maxLines: 1,
softWrap: false,
),
onPressed: (){
setState(() {
widget.currentCacu = Cacu('0', CacuType.none);
context.read<CacuDao>().clearCacu();
});
},
)
),
const SizedBox(width: 5),
OutlinedButton(
child: const Text('C'),
onPressed: (){
setState(() {
widget.currentCacu = Cacu('0', CacuType.none);
});
},
),
const SizedBox(width: 5),
OutlinedButton(
child: const Text('±'),
onPressed: (){
setState(() {
if(widget.currentCacu.cacuValue[0] == '-'){
widget.currentCacu.cacuValue = widget.currentCacu.cacuValue.substring(1);
}
else {
widget.currentCacu.cacuValue = '-${widget.currentCacu.cacuValue}';
}
});
},
),
const SizedBox(width: 5),
OutlinedButton(
child: const Text('÷'),
onPressed: (){
setState(() {
widget.currentCacu.cacuType = CacuType.division;
});
}
),
]
),
const SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
OutlinedButton(
child: const Text('7'),
onPressed: (){
setState(() {
String num = '7';
if(widget.currentCacu.cacuType == CacuType.none) {
if(widget.currentCacu.cacuValue == '0') {
widget.currentCacu.cacuValue = num;
} else {
widget.currentCacu.cacuValue = widget.currentCacu.cacuValue + num;
}
}
else {
context.read<CacuDao>().insertCacu(widget.currentCacu);
widget.currentCacu = Cacu(num, CacuType.none);
}
});
}
),
const SizedBox(width: 5),
OutlinedButton(
child: const Text('8'),
onPressed: (){
setState(() {
String num = '8';
if(widget.currentCacu.cacuType == CacuType.none) {
if(widget.currentCacu.cacuValue == '0') {
widget.currentCacu.cacuValue = num;
} else {
widget.currentCacu.cacuValue = widget.currentCacu.cacuValue + num;
}
}
else {
context.read<CacuDao>().insertCacu(widget.currentCacu);
widget.currentCacu = Cacu(num, CacuType.none);
}
});
}
),
const SizedBox(width: 5),
OutlinedButton(
child: const Text('9'),
onPressed: (){
setState(() {
String num = '9';
if(widget.currentCacu.cacuType == CacuType.none) {
if(widget.currentCacu.cacuValue == '0') {
widget.currentCacu.cacuValue = num;
} else {
widget.currentCacu.cacuValue = widget.currentCacu.cacuValue + num;
}
}
else {
context.read<CacuDao>().insertCacu(widget.currentCacu);
widget.currentCacu = Cacu('0', CacuType.none);
}
});
}
),
const SizedBox(width: 10),
OutlinedButton(
child: const Text('x'),
onPressed: (){
setState(() {
widget.currentCacu.cacuType = CacuType.multiplication;
});
}
),
],
),
const SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
OutlinedButton(
child: const Text('4'),
onPressed: (){
setState(() {
String num = '4';
if(widget.currentCacu.cacuType == CacuType.none) {
if(widget.currentCacu.cacuValue == '0') {
widget.currentCacu.cacuValue = num;
} else {
widget.currentCacu.cacuValue = widget.currentCacu.cacuValue + num;
}
}
else {
context.read<CacuDao>().insertCacu(widget.currentCacu);
widget.currentCacu = Cacu(num, CacuType.none);
}
});
}
),
const SizedBox(width: 5),
OutlinedButton(
child: const Text('5'),
onPressed: (){
setState(() {
String num = '5';
if(widget.currentCacu.cacuType == CacuType.none) {
if(widget.currentCacu.cacuValue == '0') {
widget.currentCacu.cacuValue = num;
} else {
widget.currentCacu.cacuValue = widget.currentCacu.cacuValue + num;
}
}
else {
context.read<CacuDao>().insertCacu(widget.currentCacu);
widget.currentCacu = Cacu(num, CacuType.none);
}
});
}
),
const SizedBox(width: 5),
OutlinedButton(
child: const Text('6'),
onPressed: (){
setState(() {
String num = '6';
if(widget.currentCacu.cacuType == CacuType.none) {
if(widget.currentCacu.cacuValue == '0') {
widget.currentCacu.cacuValue = num;
} else {
widget.currentCacu.cacuValue = widget.currentCacu.cacuValue + num;
}
}
else {
context.read<CacuDao>().insertCacu(widget.currentCacu);
widget.currentCacu = Cacu(num, CacuType.none);
}
});
}
),
const SizedBox(width: 10),
OutlinedButton(
child: const Text('-'),
onPressed: (){
setState(() {
widget.currentCacu.cacuType = CacuType.subtraction;
});
}
),
],
),
const SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
OutlinedButton(
child: const Text('1'),
onPressed: (){
setState(() {
String num = '1';
if(widget.currentCacu.cacuType == CacuType.none) {
if(widget.currentCacu.cacuValue == '0') {
widget.currentCacu.cacuValue = num;
} else {
widget.currentCacu.cacuValue = widget.currentCacu.cacuValue + num;
}
}
else {
context.read<CacuDao>().insertCacu(widget.currentCacu);
widget.currentCacu = Cacu(num, CacuType.none);
}
});
}
),
const SizedBox(width: 5),
OutlinedButton(
child: const Text('2'),
onPressed: (){
setState(() {
String num = '2';
if(widget.currentCacu.cacuType == CacuType.none) {
if(widget.currentCacu.cacuValue == '0') {
widget.currentCacu.cacuValue = num;
} else {
widget.currentCacu.cacuValue = widget.currentCacu.cacuValue + num;
}
}
else {
context.read<CacuDao>().insertCacu(widget.currentCacu);
widget.currentCacu = Cacu(num, CacuType.none);
}
});
}
),
const SizedBox(width: 5),
OutlinedButton(
child: const Text('3'),
onPressed: (){
setState(() {
String num = '3';
if(widget.currentCacu.cacuType == CacuType.none) {
if(widget.currentCacu.cacuValue == '0') {
widget.currentCacu.cacuValue = num;
} else {
widget.currentCacu.cacuValue = widget.currentCacu.cacuValue + num;
}
}
else {
context.read<CacuDao>().insertCacu(widget.currentCacu);
widget.currentCacu = Cacu(num, CacuType.none);
}
});
}
),
const SizedBox(width: 10),
OutlinedButton(
child: const Text('+'),
onPressed: (){
setState(() {
widget.currentCacu.cacuType = CacuType.addition;
});
}
),
],
),
const SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 130.0,
child: OutlinedButton(
child: const Text('0'),
onPressed: (){
setState(() {
String num = '0';
if(widget.currentCacu.cacuType == CacuType.none) {
if(widget.currentCacu.cacuValue != '0' && !widget.currentCacu.cacuValue.contains('.')) {
widget.currentCacu.cacuValue = widget.currentCacu.cacuValue + num;
}
}
else {
context.read<CacuDao>().insertCacu(widget.currentCacu);
widget.currentCacu = Cacu(num, CacuType.none);
}
});
}
),
),
const SizedBox(width: 5),
OutlinedButton(
child: const Text('.'),
onPressed: (){
String num = '.';
if(widget.currentCacu.cacuType == CacuType.none) {
if(!widget.currentCacu.cacuValue.contains('.')) {
widget.currentCacu.cacuValue = widget.currentCacu.cacuValue + num;
}
}
else {
context.read<CacuDao>().insertCacu(widget.currentCacu);
widget.currentCacu = Cacu('0', CacuType.none);
}
}
),
const SizedBox(width: 10),
OutlinedButton(
child: const Text('='),
onPressed: (){
setState(() {
double result = 0;
CacuType lastCacuType = CacuType.none;
List<Cacu> cacus = context.read<CacuDao>().getCacus();
cacus.add(Cacu(widget.currentCacu.cacuValue, CacuType.none));
for (var cacu in cacus) {
switch(lastCacuType) {
case CacuType.division:
result = result / double.parse(cacu.cacuValue);
case CacuType.multiplication:
result = result * double.parse(cacu.cacuValue);
case CacuType.subtraction:
result = result - double.parse(cacu.cacuValue);
case CacuType.addition:
result = result + double.parse(cacu.cacuValue);
default:
result = double.parse(cacu.cacuValue);
}
lastCacuType = cacu.cacuType;
}
widget.currentCacu = Cacu(result.toString(), CacuType.none);
context.read<CacuDao>().clearCacu();
});
}
),
],
),
const SizedBox(height: 5),
]);
return Scaffold(
appBar: AppBar(title: const Text("Caculator"),),
body: Container(
alignment: Alignment.topCenter,
child: Column(
children: [
Expanded(
child: ListView(
controller: _scrollController,
children: [
...context.watch<CacuDao>().getCacus().map((e) => CacuComponent(e)).toList(),
],
),
),
valueViewer,
keybooards,
]
),
),
);
}
} -

Flutter 專案生成 API 文件
在 命令提示字元、Android Studio 或 VSCode 的終端機介面,輸入以下指令即可:
- 切換到專案所在目錄
- 取得當前專案目錄底下的相關資訊:dart pub get
- 確保沒有錯誤:dart analyze
- 產生API文件到專案所在目錄的 ./doc 資料夾中:dart doc .


