mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-07-06 04:37:59 +02:00
feat(audio): add WAV and AIFF support + settings-style metadata menu
WAV/AIFF: library scan, quality probe, native tag read/write via embedded ID3 chunk (RIFF id3 / AIFF ID3), cover art, ReadFileMetadata, ExtractLyrics, and FLAC<->WAV/AIFF conversion (PCM, bit-depth preserved via ffprobe). Treat WAV/AIFF as lossless across all convert sheets (no bitrate picker, Lossless labels) via isLosslessConversionTarget. Native MIME maps for SAF. Redesign the track metadata three-dot menu to a settings-style grouped card with a single divider above Share.
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
const List<String> audioConversionTargetFormats = [
|
||||
'ALAC',
|
||||
'FLAC',
|
||||
'WAV',
|
||||
'AIFF',
|
||||
'AAC',
|
||||
'MP3',
|
||||
'Opus',
|
||||
@@ -8,7 +10,11 @@ const List<String> audioConversionTargetFormats = [
|
||||
|
||||
bool isLosslessConversionTarget(String targetFormat) {
|
||||
final normalized = targetFormat.trim().toLowerCase();
|
||||
return normalized == 'alac' || normalized == 'flac';
|
||||
return normalized == 'alac' ||
|
||||
normalized == 'flac' ||
|
||||
normalized == 'wav' ||
|
||||
normalized == 'aiff' ||
|
||||
normalized == 'aif';
|
||||
}
|
||||
|
||||
bool isLosslessConversionSource(String sourceFormat) {
|
||||
@@ -16,6 +22,9 @@ bool isLosslessConversionSource(String sourceFormat) {
|
||||
case 'FLAC':
|
||||
case 'ALAC':
|
||||
case 'M4A':
|
||||
case 'WAV':
|
||||
case 'AIFF':
|
||||
case 'AIF':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -66,6 +75,13 @@ String? _convertibleAudioFormatLabel(String? rawFormat) {
|
||||
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';
|
||||
@@ -95,6 +111,28 @@ 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,
|
||||
|
||||
@@ -16,6 +16,10 @@ String audioMimeTypeForPath(String filePath) {
|
||||
return 'audio/ogg';
|
||||
case 'wav':
|
||||
return 'audio/wav';
|
||||
case 'aiff':
|
||||
case 'aif':
|
||||
case 'aifc':
|
||||
return 'audio/aiff';
|
||||
case 'aac':
|
||||
return 'audio/aac';
|
||||
default:
|
||||
|
||||
@@ -19,6 +19,8 @@ const _audioExtensions = <String>[
|
||||
'.opus',
|
||||
'.ogg',
|
||||
'.wav',
|
||||
'.aiff',
|
||||
'.aif',
|
||||
'.aac',
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user