Flutter音频编码插件flutter_lame的使用
Flutter音频编码插件flutter_lame的使用
flutter_lame
是一个用于将音频数据编码为MP3格式的Flutter插件,它集成了LAME MP3编码器的源代码,并在构建Flutter Runner时自动编译。与 dart_lame
不同,您不需要自己提供预编译的库文件。
使用方法
基本用法
下面是一个简单的示例,展示了如何使用 flutter_lame
将音频样本编码为MP3格式:
import 'dart:io';
import 'dart:typed_data';
final File f = File("output.mp3");
final IOSink sink = f.openWrite();
final LameMp3Encoder encoder = LameMp3Encoder(sampleRate: 44100, numChannels: 2);
Float64List leftChannelSamples;
Float64List rightChannelSamples;
// 获取样本数据,可以来自文件或麦克风
final mp3Frame = await encoder.encode(
leftChannel: leftChannelSamples,
rightChannel: rightChannelSamples);
sink.add(mp3Frame);
// 继续编码直到所有样本都处理完毕
// 最后,刷新编码器缓冲区
final lastMp3Frame = await encoder.flush();
sink.add(lastMp3Frame);
完整示例
以下是一个更完整的示例,展示了如何从WAV文件中读取音频数据并将其编码为MP3格式:
import 'dart:io';
import 'dart:async';
import 'dart:typed_data';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:path/path.dart' as path;
import 'package:flutter_lame/flutter_lame.dart';
import 'package:wav/wav.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
[@override](/user/override)
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String? inputPath;
String outputName = "output.mp3";
bool working = false;
void selectInputFile() async {
final result = await FilePicker.platform.pickFiles(
type: FileType.custom,
dialogTitle: "Select WAV file",
allowedExtensions: ["wav"],
allowMultiple: false);
if (result == null || result.paths.isEmpty) {
return;
}
setState(() {
inputPath = result.paths[0];
});
}
void encodeMp3() async {
if (inputPath == null) {
throw StateError("inputPath should not be null");
}
final outputDir = await FilePicker.platform.getDirectoryPath(
dialogTitle: "Pick a directory to save output MP3 file");
if (outputDir == null) {
return;
}
setState(() {
working = true;
});
LameMp3Encoder? encoder;
IOSink? sink;
try {
final wav = await compute(Wav.readFile, inputPath!);
final File f = File(path.join(outputDir, outputName));
sink = f.openWrite();
encoder = LameMp3Encoder(
sampleRate: wav.samplesPerSecond, numChannels: wav.channels.length);
final left = wav.channels[0];
Float64List? right;
if (wav.channels.length > 1) {
right = wav.channels[1];
}
for (int i = 0; i < left.length; i += wav.samplesPerSecond) {
final mp3Frame = await encoder.encodeDouble(
leftChannel: left.sublist(i, i + wav.samplesPerSecond),
rightChannel: right?.sublist(i, i + wav.samplesPerSecond));
sink.add(mp3Frame);
}
sink.add(await encoder.flush());
} catch (e) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text("Error"),
content: Text(e.toString()),
));
} finally {
encoder?.close();
sink?.close();
setState(() {
working = false;
});
}
}
[@override](/user/override)
Widget build(BuildContext context) {
const textStyle = TextStyle(fontSize: 25);
const spacerSmall = SizedBox(height: 10);
const spacerLarge = SizedBox(height: 30);
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter LAME Example'),
),
body: SingleChildScrollView(
child: Container(
padding: const EdgeInsets.all(10),
child: Column(
children: [
const Text(
'Call LAME API through FFI that is shipped as source in the package. '
'The native code is built as part of the Flutter Runner build.',
style: textStyle,
textAlign: TextAlign.center,
),
const Divider(),
spacerLarge,
ElevatedButton(
onPressed: !working ? selectInputFile : null,
child: const Text(
"Select WAV file",
style: textStyle,
)),
spacerSmall,
RichText(
text: TextSpan(
style: const TextStyle(fontSize: 25, color: Colors.black),
children: [
const TextSpan(
text: "Input WAV file: ",
style: TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: inputPath)
]),
textAlign: TextAlign.center,
),
spacerSmall,
TextFormField(
onChanged: (v) => setState(() {
outputName = v;
}),
decoration:
const InputDecoration(labelText: "Output MP3 filename"),
initialValue: outputName),
spacerSmall,
ElevatedButton(
onPressed:
inputPath != null && outputName.isNotEmpty && !working
? encodeMp3
: null,
child: const Text(
"Encode to MP3",
style: textStyle,
)),
spacerSmall,
if (working) const CircularProgressIndicator(),
],
),
),
),
),
);
}
}
更多关于Flutter音频编码插件flutter_lame的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
1 回复