const List audioConversionTargetFormats = [ 'ALAC', 'FLAC', 'WAV', 'AIFF', 'AAC', 'MP3', 'Opus', ]; bool isLosslessConversionTarget(String targetFormat) { final normalized = targetFormat.trim().toLowerCase(); return normalized == 'alac' || normalized == 'flac' || normalized == 'wav' || normalized == 'aiff' || normalized == 'aif'; } bool isLosslessConversionSource(String sourceFormat) { switch (sourceFormat.trim().toUpperCase()) { case 'FLAC': case 'ALAC': case 'M4A': case 'WAV': case 'AIFF': case 'AIF': return true; default: return false; } } bool canConvertAudioFormat({ required String sourceFormat, required String targetFormat, }) { if (sourceFormat.trim().toUpperCase() == targetFormat.trim().toUpperCase()) { return false; } if (isLosslessConversionTarget(targetFormat) && !isLosslessConversionSource(sourceFormat)) { return false; } return true; } String? convertibleAudioSourceFormat({ String? storedFormat, String? filePath, String? fileName, }) { final fromStored = _convertibleAudioFormatLabel(storedFormat); if (fromStored != null) return fromStored; final name = (fileName != null && fileName.trim().isNotEmpty) ? fileName : filePath; if (name == null || name.trim().isEmpty) return null; final normalizedName = name.trim().toLowerCase(); final dotIndex = normalizedName.lastIndexOf('.'); if (dotIndex < 0 || dotIndex == normalizedName.length - 1) { return null; } return _convertibleAudioFormatLabel(normalizedName.substring(dotIndex + 1)); } String? _convertibleAudioFormatLabel(String? rawFormat) { final format = rawFormat?.trim().toLowerCase(); if (format == null || format.isEmpty) return null; switch (format) { case 'flac': return 'FLAC'; case 'alac': return 'ALAC'; case 'wav': case 'wave': return 'WAV'; case 'aiff': case 'aif': case 'aifc': return 'AIFF'; case 'm4a': case 'mp4': return 'M4A'; case 'aac': case 'mp4a': return 'AAC'; case 'mp3': return 'MP3'; case 'opus': case 'ogg': return 'Opus'; case 'eac3': case 'ec-3': return 'EAC3'; case 'ac3': case 'ac-3': return 'AC3'; case 'ac4': case 'ac-4': return 'AC4'; default: return null; } } String normalizedConvertedAudioFormat(String targetFormat) { return targetFormat.trim().toLowerCase(); } /// Returns the output file extension (with dot) and MIME type for a conversion /// target format. Used when creating the converted file via SAF so WAV/AIFF and /// the other formats get the correct extension + MIME. ({String ext, String mime}) convertTargetExtAndMime(String targetFormat) { switch (targetFormat.trim().toLowerCase()) { case 'opus': return (ext: '.opus', mime: 'audio/opus'); case 'alac': case 'aac': return (ext: '.m4a', mime: 'audio/mp4'); case 'flac': return (ext: '.flac', mime: 'audio/flac'); case 'wav': return (ext: '.wav', mime: 'audio/wav'); case 'aiff': case 'aif': return (ext: '.aiff', mime: 'audio/aiff'); default: return (ext: '.mp3', mime: 'audio/mpeg'); } } int? convertedAudioBitrateKbps({ required String targetFormat, required String bitrate, }) { if (isLosslessConversionTarget(targetFormat)) return null; final match = RegExp(r'(\d+)').firstMatch(bitrate); return match != null ? int.tryParse(match.group(1)!) : null; }