xref: /aosp_15_r20/external/flac/test/write_iff.pl (revision 600f14f40d737144c998e2ec7a483122d3776fbc)
1*600f14f4SXin Li#!/usr/bin/perl -w
2*600f14f4SXin Li
3*600f14f4SXin Liuse strict;
4*600f14f4SXin Li
5*600f14f4SXin Lirequire Math::BigInt;
6*600f14f4SXin Li
7*600f14f4SXin Limy $usage = "
8*600f14f4SXin Li$0 <format> <bps> <channels> <sample-rate> <#samples> <sample-type>
9*600f14f4SXin Li
10*600f14f4SXin Li     <format> is one of aiff,wave,wave64,rf64
11*600f14f4SXin Li        <bps> is 8,16,24,32
12*600f14f4SXin Li   <channels> is 1-8
13*600f14f4SXin Li<sample-rate> is any 32-bit value
14*600f14f4SXin Li   <#samples> is 0-2^64-1
15*600f14f4SXin Li<sample-type> is one of zero,rand
16*600f14f4SXin Li
17*600f14f4SXin Li";
18*600f14f4SXin Li
19*600f14f4SXin Lidie $usage unless @ARGV == 6;
20*600f14f4SXin Li
21*600f14f4SXin Limy %formats = ( 'aiff'=>1, 'wave'=>1, 'wave64'=>1, 'rf64'=>1 );
22*600f14f4SXin Limy %sampletypes = ( 'zero'=>1, 'rand'=>1 );
23*600f14f4SXin Limy @channelmask = ( 0, 1, 3, 7, 0x33, 0x607, 0x60f, 0, 0 ); #@@@@@@ need proper masks for 7,8
24*600f14f4SXin Li
25*600f14f4SXin Limy ($format, $bps, $channels, $samplerate, $samples, $sampletype) = @ARGV;
26*600f14f4SXin Limy $bigsamples = new Math::BigInt $samples;
27*600f14f4SXin Li
28*600f14f4SXin Lidie $usage unless defined $formats{$format};
29*600f14f4SXin Lidie $usage unless $bps == 8 || $bps == 16 || $bps == 24 || $bps == 32;
30*600f14f4SXin Lidie $usage unless $channels >= 1 && $channels <= 8;
31*600f14f4SXin Lidie $usage unless $samplerate >= 0 && $samplerate <= 4294967295;
32*600f14f4SXin Lidie $usage unless defined $sampletypes{$sampletype};
33*600f14f4SXin Li
34*600f14f4SXin Li# convert bits-per-sample to bytes-per-sample
35*600f14f4SXin Li$bps /= 8;
36*600f14f4SXin Li
37*600f14f4SXin Limy $datasize = $samples * $bps * $channels;
38*600f14f4SXin Limy $bigdatasize = $bigsamples * $bps * $channels;
39*600f14f4SXin Li
40*600f14f4SXin Limy $padding = int($bigdatasize & 1); # for aiff/wave/rf64 chunk alignment
41*600f14f4SXin Limy $padding8 = 8 - int($bigdatasize & 7); $padding8 = 0 if $padding8 == 8; # for wave64 alignment
42*600f14f4SXin Li# wave-ish file needs to be WAVEFORMATEXTENSIBLE?
43*600f14f4SXin Limy $wavx = ($format eq 'wave' || $format eq 'wave64' || $format eq 'rf64') && ($channels > 2 || ($bps != 8 && $bps != 16));
44*600f14f4SXin Li
45*600f14f4SXin Li# write header
46*600f14f4SXin Li
47*600f14f4SXin Liif ($format eq 'aiff') {
48*600f14f4SXin Li	die "sample data too big for format\n" if 46 + $datasize + $padding > 4294967295;
49*600f14f4SXin Li	# header
50*600f14f4SXin Li	print "FORM";
51*600f14f4SXin Li	print pack('N', 46 + $datasize + $padding);
52*600f14f4SXin Li	print "AIFF";
53*600f14f4SXin Li	# COMM chunk
54*600f14f4SXin Li	print "COMM";
55*600f14f4SXin Li	print pack('N', 18); # chunk size = 18
56*600f14f4SXin Li	print pack('n', $channels);
57*600f14f4SXin Li	print pack('N', $samples);
58*600f14f4SXin Li	print pack('n', $bps * 8);
59*600f14f4SXin Li	print pack_sane_extended($samplerate);
60*600f14f4SXin Li	# SSND header
61*600f14f4SXin Li	print "SSND";
62*600f14f4SXin Li	print pack('N', $datasize + 8); # chunk size
63*600f14f4SXin Li	print pack('N', 0); # ssnd_offset_size
64*600f14f4SXin Li	print pack('N', 0); # blocksize
65*600f14f4SXin Li}
66*600f14f4SXin Lielsif ($format eq 'wave' || $format eq 'wave64' || $format eq 'rf64') {
67*600f14f4SXin Li	die "sample data too big for format\n" if $format eq 'wave' && ($wavx?60:36) + $datasize + $padding > 4294967295;
68*600f14f4SXin Li	# header
69*600f14f4SXin Li	if ($format eq 'wave') {
70*600f14f4SXin Li		print "RIFF";
71*600f14f4SXin Li		# +4 for WAVE
72*600f14f4SXin Li		# +8+{40,16} for fmt chunk
73*600f14f4SXin Li		# +8 for data chunk header
74*600f14f4SXin Li		print pack('V', 4 + 8+($wavx?40:16) + 8 + $datasize + $padding);
75*600f14f4SXin Li		print "WAVE";
76*600f14f4SXin Li	}
77*600f14f4SXin Li	elsif ($format eq 'wave64') {
78*600f14f4SXin Li		# RIFF GUID 66666972-912E-11CF-A5D6-28DB04C10000
79*600f14f4SXin Li		print "\x72\x69\x66\x66\x2E\x91\xCF\x11\xD6\xA5\x28\xDB\x04\xC1\x00\x00";
80*600f14f4SXin Li		# +(16+8) for RIFF GUID + size
81*600f14f4SXin Li		# +16 for WAVE GUID
82*600f14f4SXin Li		# +16+8+{40,16} for fmt chunk
83*600f14f4SXin Li		# +16+8 for data chunk header
84*600f14f4SXin Li		my $bigriffsize = $bigdatasize + (16+8) + 16 + 16+8+($wavx?40:16) + (16+8) + $padding8;
85*600f14f4SXin Li		print pack_64('V', $bigriffsize);
86*600f14f4SXin Li		# WAVE GUID 65766177-ACF3-11D3-8CD1-00C04F8EDB8A
87*600f14f4SXin Li		print "\x77\x61\x76\x65\xF3\xAC\xD3\x11\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A";
88*600f14f4SXin Li	}
89*600f14f4SXin Li	else {
90*600f14f4SXin Li		print "RF64";
91*600f14f4SXin Li		print pack('V', 0xffffffff);
92*600f14f4SXin Li		print "WAVE";
93*600f14f4SXin Li		# ds64 chunk
94*600f14f4SXin Li		print "ds64";
95*600f14f4SXin Li		print pack('V', 28); # chunk size
96*600f14f4SXin Li		# +4 for WAVE
97*600f14f4SXin Li		# +(8+28) for ds64 chunk
98*600f14f4SXin Li		# +8+{40,16} for fmt chunk
99*600f14f4SXin Li		# +8 for data chunk header
100*600f14f4SXin Li		my $bigriffsize = $bigdatasize + 4 + (8+28) + 8+($wavx?40:16) + 8 + $padding;
101*600f14f4SXin Li		print pack_64('V', $bigriffsize);
102*600f14f4SXin Li		print pack_64('V', $bigdatasize);
103*600f14f4SXin Li		print pack_64('V', $bigsamples);
104*600f14f4SXin Li		print pack('V', 0); # table size
105*600f14f4SXin Li	}
106*600f14f4SXin Li	# fmt chunk
107*600f14f4SXin Li	if ($format ne 'wave64') {
108*600f14f4SXin Li		print "fmt ";
109*600f14f4SXin Li		print pack('V', $wavx?40:16); # chunk size
110*600f14f4SXin Li	}
111*600f14f4SXin Li	else { # wave64
112*600f14f4SXin Li		# fmt GUID 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A
113*600f14f4SXin Li		print "\x66\x6D\x74\x20\xF3\xAC\xD3\x11\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A";
114*600f14f4SXin Li		print pack('V', 16+8+($wavx?40:16)); # chunk size (+16+8 for GUID and size fields)
115*600f14f4SXin Li		print pack('V', 0);                  # ...is 8 bytes for wave64
116*600f14f4SXin Li	}
117*600f14f4SXin Li	print pack('v', $wavx?65534:1); # compression code
118*600f14f4SXin Li	print pack('v', $channels);
119*600f14f4SXin Li	print pack('V', $samplerate);
120*600f14f4SXin Li	print pack('V', $samplerate * $channels * $bps);
121*600f14f4SXin Li	print pack('v', $channels * $bps); # block align = channels*((bps+7)/8)
122*600f14f4SXin Li	print pack('v', $bps * 8); # bits per sample = ((bps+7)/8)*8
123*600f14f4SXin Li	if ($wavx) {
124*600f14f4SXin Li		print pack('v', 22); # cbSize
125*600f14f4SXin Li		print pack('v', $bps * 8); # validBitsPerSample
126*600f14f4SXin Li		print pack('V', $channelmask[$channels]);
127*600f14f4SXin Li		# GUID = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}
128*600f14f4SXin Li		print "\x01\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71";
129*600f14f4SXin Li	}
130*600f14f4SXin Li	# data header
131*600f14f4SXin Li	if ($format ne 'wave64') {
132*600f14f4SXin Li		print "data";
133*600f14f4SXin Li		print pack('V', $format eq 'wave'? $datasize : 0xffffffff);
134*600f14f4SXin Li	}
135*600f14f4SXin Li	else { # wave64
136*600f14f4SXin Li		# data GUID 61746164-ACF3-11D3-8CD1-00C04F8EDB8A
137*600f14f4SXin Li		print "\x64\x61\x74\x61\xF3\xAC\xD3\x11\xD1\x8C\x00\xC0\x4F\x8E\xDB\x8A";
138*600f14f4SXin Li		print pack_64('V', $bigdatasize+16+8); # +16+8 for GUID and size fields
139*600f14f4SXin Li	}
140*600f14f4SXin Li}
141*600f14f4SXin Lielse {
142*600f14f4SXin Li	die;
143*600f14f4SXin Li}
144*600f14f4SXin Li
145*600f14f4SXin Li# write sample data
146*600f14f4SXin Li
147*600f14f4SXin Liif ($sampletype eq 'zero') {
148*600f14f4SXin Li	my $chunk = 4096;
149*600f14f4SXin Li	my $buf = pack("x[".($channels*$bps*$chunk)."]");
150*600f14f4SXin Li	for (my $s = $samples; $s > 0; $s -= $chunk) {
151*600f14f4SXin Li		if ($s < $chunk) {
152*600f14f4SXin Li			print substr($buf, 0, $channels*$bps*$s);
153*600f14f4SXin Li		}
154*600f14f4SXin Li		else {
155*600f14f4SXin Li			print $buf;
156*600f14f4SXin Li		}
157*600f14f4SXin Li	}
158*600f14f4SXin Li}
159*600f14f4SXin Lielsif ($sampletype eq 'rand') {
160*600f14f4SXin Li	for (my $s = 0; $s < $samples; $s++) {
161*600f14f4SXin Li		for (my $c = 0; $c < $channels; $c++) {
162*600f14f4SXin Li			for (my $b = 0; $b < $bps; $b++) {
163*600f14f4SXin Li				print pack('C', int(rand(256)));
164*600f14f4SXin Li			}
165*600f14f4SXin Li		}
166*600f14f4SXin Li	}
167*600f14f4SXin Li}
168*600f14f4SXin Lielse {
169*600f14f4SXin Li	die;
170*600f14f4SXin Li}
171*600f14f4SXin Li
172*600f14f4SXin Li# write padding
173*600f14f4SXin Liif ($format eq 'wave64') {
174*600f14f4SXin Li	print pack("x[$padding8]") if $padding8;
175*600f14f4SXin Li}
176*600f14f4SXin Lielse {
177*600f14f4SXin Li	print "\x00" if $padding;
178*600f14f4SXin Li}
179*600f14f4SXin Li
180*600f14f4SXin Liexit 0;
181*600f14f4SXin Li
182*600f14f4SXin Lisub pack_sane_extended
183*600f14f4SXin Li{
184*600f14f4SXin Li	my $val = shift;
185*600f14f4SXin Li	die unless $val > 0;
186*600f14f4SXin Li	my $shift;
187*600f14f4SXin Li	for ($shift = 0; ($val>>(31-$shift)) == 0; ++$shift) {
188*600f14f4SXin Li	}
189*600f14f4SXin Li	$val <<= $shift;
190*600f14f4SXin Li	my $exponent = 63 - ($shift + 32);
191*600f14f4SXin Li	return pack('nNN', $exponent + 16383, $val, 0);
192*600f14f4SXin Li}
193*600f14f4SXin Li
194*600f14f4SXin Lisub pack_64
195*600f14f4SXin Li{
196*600f14f4SXin Li	my $c = shift; # 'N' for big-endian, 'V' for little-endian, ala pack()
197*600f14f4SXin Li	my $v1 = shift; # value, must be Math::BigInt
198*600f14f4SXin Li	my $v2 = $v1->copy();
199*600f14f4SXin Li	if ($c eq 'V') {
200*600f14f4SXin Li		$v1->band(0xffffffff);
201*600f14f4SXin Li		$v2->brsft(32);
202*600f14f4SXin Li	}
203*600f14f4SXin Li	elsif ($c eq 'N') {
204*600f14f4SXin Li		$v2->band(0xffffffff);
205*600f14f4SXin Li		$v1->brsft(32);
206*600f14f4SXin Li	}
207*600f14f4SXin Li	else {
208*600f14f4SXin Li		die;
209*600f14f4SXin Li	}
210*600f14f4SXin Li	return pack("$c$c", 0+$v1->bstr(), 0+$v2->bstr());
211*600f14f4SXin Li}
212