main
dart 75 lines 2.12 KB
Raw
1 import 'dart:typed_data';
2
3 /// Merges multiple PCM WAV files (same format) into a single WAV.
4 Uint8List mergeWavFiles(List<Uint8List> wavFiles) {
5 if (wavFiles.isEmpty) return Uint8List(0);
6 if (wavFiles.length == 1) return wavFiles.first;
7
8 final first = wavFiles.first;
9 final dataOffset = _findPcmDataOffset(first);
10 if (dataOffset == null) return first;
11
12 final dataSizeOffset = _findDataChunkSizeOffset(first);
13
14 final pcmBuilder = BytesBuilder(copy: false);
15 for (final wav in wavFiles) {
16 final offset = _findPcmDataOffset(wav);
17 if (offset != null && wav.length > offset) {
18 pcmBuilder.add(wav.sublist(offset));
19 }
20 }
21 final pcmData = pcmBuilder.toBytes();
22
23 final header = Uint8List.fromList(first.sublist(0, dataOffset));
24 _writeUint32LE(header, 4, header.length + pcmData.length - 8);
25 if (dataSizeOffset != null) {
26 _writeUint32LE(header, dataSizeOffset, pcmData.length);
27 }
28
29 return Uint8List.fromList([...header, ...pcmData]);
30 }
31
32 int? _findPcmDataOffset(Uint8List wav) {
33 final dataSizeOffset = _findDataChunkSizeOffset(wav);
34 return dataSizeOffset == null ? null : dataSizeOffset + 4;
35 }
36
37 int? _findDataChunkSizeOffset(Uint8List wav) {
38 if (wav.length < 12) return null;
39 if (wav[0] != 0x52 ||
40 wav[1] != 0x49 ||
41 wav[2] != 0x46 ||
42 wav[3] != 0x46 ||
43 wav[8] != 0x57 ||
44 wav[9] != 0x41 ||
45 wav[10] != 0x56 ||
46 wav[11] != 0x45) {
47 return null;
48 }
49
50 var offset = 12;
51 while (offset + 8 <= wav.length) {
52 final chunkId = String.fromCharCodes(wav.sublist(offset, offset + 4));
53 final chunkSize = _readUint32LE(wav, offset + 4);
54 if (chunkId == 'data') {
55 return offset + 4;
56 }
57 offset += 8 + chunkSize;
58 if (chunkSize.isOdd) offset++;
59 }
60 return null;
61 }
62
63 int _readUint32LE(Uint8List bytes, int offset) {
64 return bytes[offset] |
65 (bytes[offset + 1] << 8) |
66 (bytes[offset + 2] << 16) |
67 (bytes[offset + 3] << 24);
68 }
69
70 void _writeUint32LE(Uint8List bytes, int offset, int value) {
71 bytes[offset] = value & 0xff;
72 bytes[offset + 1] = (value >> 8) & 0xff;
73 bytes[offset + 2] = (value >> 16) & 0xff;
74 bytes[offset + 3] = (value >> 24) & 0xff;
75 }