Use this plugin to generate waveforms while recording audio in any file format supported by given encoders or from audio files. We can use gestures to scroll through the waveforms or seek any position while playing audio and style waveforms.
Prerequisites
Add dependency to pubspec.yaml
dependencies:
audio_waveforms: <latest-version>
flutter clean
and then flutter pub get
Below are platform specific setup for recording audio to be able work.
This is a quick example showcasing how to show waveforms while recording,
String? recordedFilePath;
final RecorderController recorderController = RecorderController();
@override
void initState() {
super.initState();
recorderController.checkPermission();
}
@override
void dispose() {
recorderController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
ElevatedButton(
onPressed: () {
if (recorderController.hasPermission) {
recorderController.record(); // By default saves file with datetime as name.
}
},
child: Text('Record'),
),
ElevatedButton(
onPressed: () {
recorderController.pause();
},
child: Text('Record'),
),
ElevatedButton(
onPressed: () async {
if (recorderController.isRecording) {
recordedFilePath = await recorderController.stop();
}
},
child: Text('Stop'),
),
AudioWaveforms(
controller: recorderController,
size: Size(300, 50),
),
],
);
}
recorderController.record(path: '../myFile.m4a');
recorderController.record(
androidEncoder: AndroidEncoder.aac,
androidOutputFormat: AndroidOutputFormat.mpeg4,
iosEncoder: IosEncoder.kAudioFormatMPEG4AAC,
);
Note -: These are default encoder and output format to support .m4a
file format. If you change them make sure that your file extension, sample rate and bit rate supports them and also which are supported by MediaRecorder
for Android and AVAudioRecorder
for iOS.
recorderController.updateFrequency = const Duration(milliseconds: 100);
recorderController.overrideAudioSession = false;
By Setting this to false, you can use own implement your own implementation so that your doesn't interfere with other app or even this plugin does't override previously set audio session.
recorderController.record(); // If path isn't provided by default sets current date time as file name m4a is used as file extension.
recorderController.pause(); // Pauses the recording.
Note-: To resume recording, use record function.
recorderController.stop(false); // Stops the current recording.
The boolean parameter callReset detects if after stopping the recording waveforms should get cleared or not.
recorderController.reset(); // Clears waveforms and duration legends from the AudioWaveforms widget.
recorderController.refresh(); // Move back waveforms to original position if they have ever been scrolled.
recorderController.dispose(); // Dispose the controller and recorder if haven't already stopped.
recorderController.onCurrentDuration.listen((duration){}); // Provides currently recorded duration of audio every 50 milliseconds.
recorderController.onRecorderStateChanged.listen((state){}); // Provides current state of recorder.
recorderController.onRecordingEnded.listen((duration){}); // Provided duration of the audio file after recording is ended.
recorderController.currentScrolledDuration;
A ValueNotifier which provides current position of scrolled waveform with respect to middle line.
shouldCalculateScrolledPosition
flag must be enabled to use it (available in AudioWaveform widget).
For better idea how duration is reported, enable duration labels and scroll toward middle line.
Reported duration is in milliseconds.
recorderController.waveData; // The waveform data in form of normalised peak power for Ios and normalised peak amplitude for Android. The values are between 0.0 and 1.0.
recorderController.elapsedDuration; // Recorded duration of the file.
recorderController.recordedDuration; // Duration of recorded audio file when recording has been stopped. Until recording has been stopped, this duration will be zero(Duration.zero). Also, once new recording is started this duration will be reset to zero.
recorderController.hasPermission; // If we have microphone permission or not.
recorderController.isRecording; // If the recorder is currently recording.
recorderController.recorderState; // Current state of the recorder.
AudioWaveforms(
size: Size(MediaQuery.of(context).size.width, 200.0), // The size of your waveform widget.
shouldCalculateScrolledPosition: true, // recorderController.currentScrolledDuration will notify only when this is enabled.
enableGesture: true, // Enable/disable scrolling of the waveforms.
waveStyle: WaveStyle(), // Customize how waveforms looks.
);
Using WaveStyle, you customize color, gradients, space between the waves, add duration legends and many more things.
This is a quick example showcasing how to show waveforms while playing an audio file,
final PlayerController playerController = PlayerController();
@override
void initState() {
super.initState();
playerController.preparePlayer(path: '../myFile.mp3');
}
@override
void dispose() {
playerController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
ElevatedButton(
onPressed: () {
playerController.startPlayer();
},
child: Text('play'),
),
ElevatedButton(
onPressed: () {
playerController.pausePlayer();
},
child: Text('pause'),
),
ElevatedButton(
onPressed: () {
playerController.stopPlayer();
},
child: Text('Stop'),
),
AudioFileWaveforms(
controller: playerController,
size: Size(300, 50),
),
],
);
}
File file = File('${appDirectory.path}/audio.mp3');
final audioFile = await rootBundle.load('assets/audio.mp3');
await file.writeAsBytes(audioFile.buffer.asUint8List());
playerController.preparePlayer(path: file.path);
playerController.preparePlayer(shouldExtractWaveform: true);
Note-: When shouldExtractWaveform
is enabled, with preparePlayer waveform data will also start to be extracted and PlayerController
will hold the extracted waveform data so an AudioFileWaveforms
widget with same PlayerController will always show same waveforms if it is rebuild or even if widget is removed from widget tree and added again.
0
millisecond after finishing the audio file.playerController.startPlayer(finishMode: FinishMode.stop);
playerController.setVolume(1.0); // Values should be between 0 and 1.
playerController.setRate(1.0);
playerController.seekTo(5000); // Required value is in milliseconds.
You can precalculate waveforms by using playerController.extractWaveformData()
.
This function gives back list of doubles which you can directly set into AudioFileWaveforms
widget. Since calculating waveforms is expensive process, you can save this data somewhere and use it again when same file is used.
final waveformData = await playerController.extractWaveformData(path: '../audioFile.mp3');
AudioFileWaveforms( ... waveformData: waveformData, );
#### Listening to events from the player
```dart
playerController.onPlayerStateChanged.listen((state) {}); // Provides events when the player state changes.
playerController.onCurrentDurationChanged.listen((duration) {}); // Provides events when audio is sought to any duration.
playerController.onCurrentExtractedWaveformData.listen((data) {}); // Provides latest data while extracting the waveforms.
playerController.onExtractionProgress.listen((progress) {}); // Provides progress of the waveform extractions.
playerController.onCompletion.listen((_){}); // Provides events every time audio file is finished playing.
final fileLengthInDuration = await playerController.getDuration(DurationType.max);
final currentDuration = await playerController.getDuration(DurationType.current); // This is where file is paused or an in progress audio files current duration.
fitWidth
AudioFileWaveforms(
waveformType: WaveformType.fitWidth,
);
For this, you will need to provide number of samples for the width which you can get from the PlayerWaveStyle
.
final style = PlayerWaveStyle(...);
final samples = style.getSamplesForWidth(screenWidth / 2);
await playerController.preparePlayer(noOfSamples: samples); // extractWaveformData also has this parameter.
Note-: If you don't provide number of samples then waveforms may get cut or won't fill whole space since default samples are 100.
long
AudioFileWaveforms(
waveformType: WaveformType.long,
);
You may provide any number of samples for this.
playerController.updateFrequency = UpdateFrequency.high;
There are 3 modes low, medium and high. Setting updateFrequency to high
will update current progress of the playing file faster(every 50ms) which will mame waveform seek animation smooth and low
makes slower(every 200ms) which could make seek animation a little laggy. You can update this according to device configuration.
playerController.release();
playerController.stopAllPlayer();
There could be any number of players but you can just call this function from any one player and it will stop all the players.
playerController.dispose();
As a responsible flutter devs, we dispose our controllers and it will also release resources taken by a native player.
AudioFileWaveforms(
continuousWaveform: true,
playerWaveStyle: PlayerWaveStlye(),
);
continuousWaveform
will show waveforms as soon as and as much as data is extracted. Disabling it show waveforms only after whole extraction process is complete.PlayerWaveStyle(
scaleFactor: 100,
scrollScale: 1.2,
);
scaleFactor
.scrollScale
> 1.0.Ujas Majithiya |
Devarsh Ranpara |