123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103(* Claude Code
*
* Copyright (C) 2026 Yoann Padioleau
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* (LGPL) as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*)(* See Polyphase.mli *)(* Table B.3's values times 2^16, the signs of every other block of 64
* undone: h.(i) for i from 0 to 256, h.(512 - i) = h.(i) *)letprototype=[|0;-1;-1;-1;-1;-1;-1;-2;-2;-2;-2;-3;-3;-4;-4;-5;-5;-6;-7;-7;-8;-9;-10;-11;-13;-14;-16;-17;-19;-21;-24;-26;-29;-31;-35;-38;-41;-45;-49;-53;-58;-63;-68;-73;-79;-85;-91;-97;-104;-111;-117;-125;-132;-139;-147;-154;-161;-169;-176;-183;-190;-196;-202;-208;-213;-218;-222;-225;-227;-228;-228;-227;-224;-221;-215;-208;-200;-189;-177;-163;-146;-127;-106;-83;-57;-29;2;36;72;111;153;197;244;294;347;401;459;519;581;645;711;779;848;919;991;1064;1137;1210;1283;1356;1428;1498;1567;1634;1698;1759;1817;1870;1919;1962;2001;2032;2057;2075;2085;2087;2080;2063;2037;2000;1952;1893;1822;1739;1644;1535;1414;1280;1131;970;794;605;402;185;-45;-288;-545;-814;-1095;-1388;-1692;-2006;-2330;-2663;-3004;-3351;-3705;-4063;-4425;-4788;-5153;-5517;-5879;-6237;-6589;-6935;-7271;-7597;-7910;-8209;-8491;-8755;-8998;-9219;-9416;-9585;-9727;-9838;-9916;-9959;-9966;-9935;-9863;-9750;-9592;-9389;-9139;-8840;-8492;-8092;-7640;-7134;-6574;-5959;-5288;-4561;-3776;-2935;-2037;-1082;-70;998;2122;3300;4533;5818;7154;8540;9975;11455;12980;14548;16155;17799;19478;21189;22929;24694;26482;28289;30112;31947;33791;35640;37489;39336;41176;43006;44821;46617;48390;50137;51853;53534;55178;56778;58333;59838;61289;62684;64019;65290;66494;67629;68692;69679;70590;71420;72169;72835;73415;73908;74313;74630;74856;74992;75038|]letwindow=Array.init512(funi->leth=prototype.(ifi<=256thenielse512-i)inletsign=ifi/64mod2=1then-1.else1.insign*.float_of_inth/.65536.)(* the matrixing's cosines, N[i][k] *)letn=Array.init64(funi->Array.init32(funk->cos(float_of_int((16+i)*((2*k)+1))*.Float.pi/.64.)))(* V as a ring: the newest 64 values at [top], older ones after it; the
* standard shifts all 1024 each time slot instead *)typet={v:floatarray;mutabletop:int}letcreate():t={v=Array.make10240.;top=0}(* row i of the matrixing, N[i] . S *)letrow(i:int)(slot:floatarray):float=letr=n.(i)andsum=ref0.infork=0to31dosum:=!sum+.(r.(k)*.slot.(k))done;!sum(* claude: half of the matrixing's 64 rows, the others their mirrors.
* The standard's way, all 64 computed, is
*
* for i = 0 to 63 do f.v.((f.top + i) land 1023) <- row i slot done
*
* but the cosines repeat: cos((16 + i)(2k + 1) pi / 64) with 16 + i
* replaced by 64 - (16 + i) changes sign (cos((2k + 1) pi - x) = -cos x,
* 2k + 1 odd), and by 128 - (16 + i) doesn't (cos(2 pi (2k + 1) - x) =
* cos x): V[32 - i] = -V[i] (so V[16] = 0) and V[96 - i] = V[i]. So
* rows 0 to 15 and 33 to 48 are computed, 1024 multiplications instead
* of 2048 -- the matrixing was 80% of the filterbank, the filterbank
* half of an MP3's decoding (notes_opti_ocaml.md). A fast DCT goes much
* further (Polyphase.mli), at the price of the formula's plainness. *)letsynthesize(f:t)(slot:floatarray)(out:floatarray)(at:int):unit=f.top<-(f.top+1024-64)land1023;letvix=f.v.((f.top+i)land1023)<-xinfori=0to15doletx=rowislotinvix;v(32-i)(-.x)done;v160.;fori=33to48doletx=rowislotinvix;v(96-i)x(* row 48 its own mirror *)done;(* U[i * 64 + j] is V[i * 128 + j], U[i * 64 + 32 + j] is V[i * 128 +
* 96 + j]: out[j] sums U[j + 32 k], k even from the first, odd from
* the second *)forj=0to31doletsum=ref0.infori=0to7dosum:=!sum+.(f.v.((f.top+(i*128)+j)land1023)*.window.(j+(64*i)));sum:=!sum+.(f.v.((f.top+(i*128)+96+j)land1023)*.window.(j+(64*i)+32))done;out.(at+j)<-!sumdone