import 'dart:math'; import 'dart:typed_data'; import 'package:file_picker/file_picker.dart'; import 'package:http/http.dart' as http; class SelectedAudio { const SelectedAudio({required this.name, required this.bytes}); final String name; final Uint8List bytes; } Future pickAudio(List supportedExtensions) async { final result = await FilePicker.platform.pickFiles( type: FileType.custom, allowedExtensions: supportedExtensions, allowMultiple: false, withData: true, ); final pickedFile = result?.files.single; final bytes = pickedFile?.bytes; if (pickedFile == null || bytes == null) { return null; } return SelectedAudio(name: pickedFile.name, bytes: bytes); } Future audioFromRecorderPath( String path, String fallbackName, ) async { final response = await http.get(Uri.parse(path)); if (response.statusCode < 200 || response.statusCode >= 300) { return null; } return SelectedAudio(name: fallbackName, bytes: response.bodyBytes); } Future> buildWavePreview(SelectedAudio audio) async { return _wavePoints(audio.bytes); } Future multipartFileFromAudio( String fieldName, SelectedAudio audio, ) { return Future.value( http.MultipartFile.fromBytes(fieldName, audio.bytes, filename: audio.name), ); } String recordingFilePath(String fileName) => fileName; List _wavePoints(List bytes) { if (bytes.isEmpty) { return const []; } const pointCount = 96; final step = max(1, bytes.length ~/ pointCount); final points = []; for (var index = 0; index < bytes.length; index += step) { final normalized = (bytes[index] - 128) / 128.0; points.add(normalized.clamp(-1.0, 1.0)); if (points.length == pointCount) { break; } } return points; }