-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAiffParserTest.java
More file actions
111 lines (87 loc) · 4.13 KB
/
AiffParserTest.java
File metadata and controls
111 lines (87 loc) · 4.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package me.tamkungz.codecmedia.internal.audio.aiff;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
import me.tamkungz.codecmedia.CodecMediaException;
import me.tamkungz.codecmedia.internal.audio.BitrateMode;
class AiffParserTest {
@Test
void shouldParseBasicAiffComm() throws Exception {
byte[] aiff = createMinimalAiff(2, 44100, 16, 44100);
AiffProbeInfo info = AiffParser.parse(aiff);
assertEquals(2, info.channels());
assertEquals(44100, info.sampleRate());
assertEquals(1411, info.bitrateKbps());
assertEquals(1000, info.durationMillis());
assertEquals(BitrateMode.CBR, info.bitrateMode());
}
@Test
void shouldParseAifcWithPcmCompressionTypeNone() throws Exception {
byte[] aifc = createMinimalAifc(2, 44100, 16, 44100, "NONE");
AiffProbeInfo info = AiffParser.parse(aifc);
assertEquals(2, info.channels());
assertEquals(44100, info.sampleRate());
assertEquals(1411, info.bitrateKbps());
}
@Test
void shouldRejectUnsupportedAifcCompressionType() {
byte[] aifc = createMinimalAifc(2, 44100, 16, 44100, "ulaw");
CodecMediaException ex = assertThrows(CodecMediaException.class, () -> AiffParser.parse(aifc));
assertEquals("Unsupported AIFC compression type: ulaw", ex.getMessage());
}
private static byte[] createMinimalAiff(int channels, int sampleRate, int bitsPerSample, int frames) {
int commChunkSize = 18;
int formSize = 4 + 8 + commChunkSize;
byte[] bytes = new byte[8 + formSize];
bytes[0] = 'F'; bytes[1] = 'O'; bytes[2] = 'R'; bytes[3] = 'M';
writeBeInt(bytes, 4, formSize);
bytes[8] = 'A'; bytes[9] = 'I'; bytes[10] = 'F'; bytes[11] = 'F';
bytes[12] = 'C'; bytes[13] = 'O'; bytes[14] = 'M'; bytes[15] = 'M';
writeBeInt(bytes, 16, commChunkSize);
writeBeShort(bytes, 20, channels);
writeBeInt(bytes, 22, frames);
writeBeShort(bytes, 26, bitsPerSample);
writeExtended80Integer(bytes, 28, sampleRate);
return bytes;
}
private static byte[] createMinimalAifc(int channels, int sampleRate, int bitsPerSample, int frames, String compressionType) {
int commChunkSize = 22;
int formSize = 4 + 8 + commChunkSize;
byte[] bytes = new byte[8 + formSize];
bytes[0] = 'F'; bytes[1] = 'O'; bytes[2] = 'R'; bytes[3] = 'M';
writeBeInt(bytes, 4, formSize);
bytes[8] = 'A'; bytes[9] = 'I'; bytes[10] = 'F'; bytes[11] = 'C';
bytes[12] = 'C'; bytes[13] = 'O'; bytes[14] = 'M'; bytes[15] = 'M';
writeBeInt(bytes, 16, commChunkSize);
writeBeShort(bytes, 20, channels);
writeBeInt(bytes, 22, frames);
writeBeShort(bytes, 26, bitsPerSample);
writeExtended80Integer(bytes, 28, sampleRate);
bytes[38] = (byte) compressionType.charAt(0);
bytes[39] = (byte) compressionType.charAt(1);
bytes[40] = (byte) compressionType.charAt(2);
bytes[41] = (byte) compressionType.charAt(3);
return bytes;
}
private static void writeExtended80Integer(byte[] out, int offset, int value) {
// Integer encoded as normalized 80-bit extended float.
int msb = 31 - Integer.numberOfLeadingZeros(value);
int exp = 16383 + msb;
long mantissa = ((long) value) << (63 - msb);
out[offset] = (byte) ((exp >>> 8) & 0x7F);
out[offset + 1] = (byte) (exp & 0xFF);
for (int i = 0; i < 8; i++) {
out[offset + 2 + i] = (byte) ((mantissa >>> (56 - (i * 8))) & 0xFF);
}
}
private static void writeBeShort(byte[] out, int offset, int value) {
out[offset] = (byte) ((value >>> 8) & 0xFF);
out[offset + 1] = (byte) (value & 0xFF);
}
private static void writeBeInt(byte[] out, int offset, int value) {
out[offset] = (byte) ((value >>> 24) & 0xFF);
out[offset + 1] = (byte) ((value >>> 16) & 0xFF);
out[offset + 2] = (byte) ((value >>> 8) & 0xFF);
out[offset + 3] = (byte) (value & 0xFF);
}
}