cannam@95: (* cannam@95: * Copyright (c) 1997-1999 Massachusetts Institute of Technology cannam@95: * Copyright (c) 2003, 2007-11 Matteo Frigo cannam@95: * Copyright (c) 2003, 2007-11 Massachusetts Institute of Technology cannam@95: * cannam@95: * This program is free software; you can redistribute it and/or modify cannam@95: * it under the terms of the GNU General Public License as published by cannam@95: * the Free Software Foundation; either version 2 of the License, or cannam@95: * (at your option) any later version. cannam@95: * cannam@95: * This program is distributed in the hope that it will be useful, cannam@95: * but WITHOUT ANY WARRANTY; without even the implied warranty of cannam@95: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the cannam@95: * GNU General Public License for more details. cannam@95: * cannam@95: * You should have received a copy of the GNU General Public License cannam@95: * along with this program; if not, write to the Free Software cannam@95: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA cannam@95: * cannam@95: *) cannam@95: cannam@95: (* generation of trigonometric transforms *) cannam@95: cannam@95: open Util cannam@95: open Genutil cannam@95: open C cannam@95: cannam@95: cannam@95: let usage = "Usage: " ^ Sys.argv.(0) ^ " -n " cannam@95: cannam@95: let uistride = ref Stride_variable cannam@95: let uostride = ref Stride_variable cannam@95: let uivstride = ref Stride_variable cannam@95: let uovstride = ref Stride_variable cannam@95: let normalization = ref 1 cannam@95: cannam@95: type mode = cannam@95: | MDCT cannam@95: | MDCT_MP3 cannam@95: | MDCT_VORBIS cannam@95: | MDCT_WINDOW cannam@95: | MDCT_WINDOW_SYM cannam@95: | IMDCT cannam@95: | IMDCT_MP3 cannam@95: | IMDCT_VORBIS cannam@95: | IMDCT_WINDOW cannam@95: | IMDCT_WINDOW_SYM cannam@95: | NONE cannam@95: cannam@95: let mode = ref NONE cannam@95: cannam@95: let speclist = [ cannam@95: "-with-istride", cannam@95: Arg.String(fun x -> uistride := arg_to_stride x), cannam@95: " specialize for given input stride"; cannam@95: cannam@95: "-with-ostride", cannam@95: Arg.String(fun x -> uostride := arg_to_stride x), cannam@95: " specialize for given output stride"; cannam@95: cannam@95: "-with-ivstride", cannam@95: Arg.String(fun x -> uivstride := arg_to_stride x), cannam@95: " specialize for given input vector stride"; cannam@95: cannam@95: "-with-ovstride", cannam@95: Arg.String(fun x -> uovstride := arg_to_stride x), cannam@95: " specialize for given output vector stride"; cannam@95: cannam@95: "-normalization", cannam@95: Arg.String(fun x -> normalization := int_of_string x), cannam@95: " normalization integer to divide by"; cannam@95: cannam@95: "-mdct", cannam@95: Arg.Unit(fun () -> mode := MDCT), cannam@95: " generate an MDCT codelet"; cannam@95: cannam@95: "-mdct-mp3", cannam@95: Arg.Unit(fun () -> mode := MDCT_MP3), cannam@95: " generate an MDCT codelet with MP3 windowing"; cannam@95: cannam@95: "-mdct-window", cannam@95: Arg.Unit(fun () -> mode := MDCT_WINDOW), cannam@95: " generate an MDCT codelet with window array"; cannam@95: cannam@95: "-mdct-window-sym", cannam@95: Arg.Unit(fun () -> mode := MDCT_WINDOW_SYM), cannam@95: " generate an MDCT codelet with symmetric window array"; cannam@95: cannam@95: "-imdct", cannam@95: Arg.Unit(fun () -> mode := IMDCT), cannam@95: " generate an IMDCT codelet"; cannam@95: cannam@95: "-imdct-mp3", cannam@95: Arg.Unit(fun () -> mode := IMDCT_MP3), cannam@95: " generate an IMDCT codelet with MP3 windowing"; cannam@95: cannam@95: "-imdct-window", cannam@95: Arg.Unit(fun () -> mode := IMDCT_WINDOW), cannam@95: " generate an IMDCT codelet with window array"; cannam@95: cannam@95: "-imdct-window-sym", cannam@95: Arg.Unit(fun () -> mode := IMDCT_WINDOW_SYM), cannam@95: " generate an IMDCT codelet with symmetric window array"; cannam@95: ] cannam@95: cannam@95: let unity_window n i = Complex.one cannam@95: cannam@95: (* MP3 window(k) = sin(pi/(2n) * (k + 1/2)) *) cannam@95: let mp3_window n k = cannam@95: Complex.imag (Complex.exp (8 * n) (2*k + 1)) cannam@95: cannam@95: (* Vorbis window(k) = sin(pi/2 * (mp3_window(k))^2) cannam@95: ... this is transcendental, though, so we can't do it with our cannam@95: current Complex.exp function *) cannam@95: cannam@95: let window_array n w = cannam@95: array n (fun i -> cannam@95: let stride = C.SInteger 1 cannam@95: and klass = Unique.make () in cannam@95: let refr = C.array_subscript w stride i in cannam@95: let kr = Variable.make_constant klass refr in cannam@95: load_r (kr, kr)) cannam@95: cannam@95: let load_window w n i = w i cannam@95: let load_window_sym w n i = w (if (i < n) then i else (2*n - 1 - i)) cannam@95: cannam@95: (* fixme: use same locations for input and output so that it works in-place? *) cannam@95: cannam@95: (* Note: only correct for even n! *) cannam@95: let load_array_mdct window n rarr iarr locations = cannam@95: let twon = 2 * n in cannam@95: let arr = load_array_c twon cannam@95: (locative_array_c twon rarr iarr locations "BUG") in cannam@95: let arrw = fun i -> Complex.times (window n i) (arr i) in cannam@95: array n cannam@95: ((Complex.times Complex.half) @@ cannam@95: (fun i -> cannam@95: if (i < n/2) then cannam@95: Complex.uminus (Complex.plus [arrw (i + n + n/2); cannam@95: arrw (n + n/2 - 1 - i)]) cannam@95: else cannam@95: Complex.plus [arrw (i - n/2); cannam@95: Complex.uminus (arrw (n + n/2 - 1 - i))])) cannam@95: cannam@95: let store_array_mdct window n rarr iarr locations arr = cannam@95: store_array_r n (locative_array_c n rarr iarr locations "BUG") arr cannam@95: cannam@95: let load_array_imdct window n rarr iarr locations = cannam@95: load_array_c n (locative_array_c n rarr iarr locations "BUG") cannam@95: cannam@95: let store_array_imdct window n rarr iarr locations arr = cannam@95: let n2 = n/2 in cannam@95: let threen2 = 3*n2 in cannam@95: let arr2 = fun i -> cannam@95: if (i < n2) then cannam@95: arr (i + n2) cannam@95: else if (i < threen2) then cannam@95: Complex.uminus (arr (threen2 - 1 - i)) cannam@95: else cannam@95: Complex.uminus (arr (i - threen2)) cannam@95: in cannam@95: let arr2w = fun i -> Complex.times (window n i) (arr2 i) in cannam@95: let twon = 2 * n in cannam@95: store_array_r twon (locative_array_c twon rarr iarr locations "BUG") arr2w cannam@95: cannam@95: let window_param = function cannam@95: MDCT_WINDOW -> true cannam@95: | MDCT_WINDOW_SYM -> true cannam@95: | IMDCT_WINDOW -> true cannam@95: | IMDCT_WINDOW_SYM -> true cannam@95: | _ -> false cannam@95: cannam@95: let generate n mode = cannam@95: let iarray = "I" cannam@95: and oarray = "O" cannam@95: and istride = "istride" cannam@95: and ostride = "ostride" cannam@95: and window = "W" cannam@95: and name = !Magic.codelet_name in cannam@95: cannam@95: let vistride = either_stride (!uistride) (C.SVar istride) cannam@95: and vostride = either_stride (!uostride) (C.SVar ostride) cannam@95: in cannam@95: cannam@95: let sivs = stride_to_string "ovs" !uovstride in cannam@95: let sovs = stride_to_string "ivs" !uivstride in cannam@95: cannam@95: let (transform, load_input, store_output) = match mode with cannam@95: | MDCT -> Trig.dctIV, load_array_mdct unity_window, cannam@95: store_array_mdct unity_window cannam@95: | MDCT_MP3 -> Trig.dctIV, load_array_mdct mp3_window, cannam@95: store_array_mdct unity_window cannam@95: | MDCT_WINDOW -> Trig.dctIV, load_array_mdct cannam@95: (load_window (window_array (2 * n) window)), cannam@95: store_array_mdct unity_window cannam@95: | MDCT_WINDOW_SYM -> Trig.dctIV, load_array_mdct cannam@95: (load_window_sym (window_array n window)), cannam@95: store_array_mdct unity_window cannam@95: | IMDCT -> Trig.dctIV, load_array_imdct unity_window, cannam@95: store_array_imdct unity_window cannam@95: | IMDCT_MP3 -> Trig.dctIV, load_array_imdct unity_window, cannam@95: store_array_imdct mp3_window cannam@95: | IMDCT_WINDOW -> Trig.dctIV, load_array_imdct unity_window, cannam@95: store_array_imdct (load_window (window_array (2 * n) window)) cannam@95: | IMDCT_WINDOW_SYM -> Trig.dctIV, load_array_imdct unity_window, cannam@95: store_array_imdct (load_window_sym (window_array n window)) cannam@95: | _ -> failwith "must specify transform kind" cannam@95: in cannam@95: cannam@95: let locations = unique_array_c (2*n) in cannam@95: let input = cannam@95: load_input n cannam@95: (C.array_subscript iarray vistride) cannam@95: (C.array_subscript "BUG" vistride) cannam@95: locations cannam@95: in cannam@95: let output = (Complex.times (Complex.inverse_int !normalization)) cannam@95: @@ (transform n input) in cannam@95: let odag = cannam@95: store_output n cannam@95: (C.array_subscript oarray vostride) cannam@95: (C.array_subscript "BUG" vostride) cannam@95: locations cannam@95: output cannam@95: in cannam@95: let annot = standard_optimizer odag in cannam@95: cannam@95: let tree = cannam@95: Fcn ("void", name, cannam@95: ([Decl (C.constrealtypep, iarray); cannam@95: Decl (C.realtypep, oarray)] cannam@95: @ (if stride_fixed !uistride then [] cannam@95: else [Decl (C.stridetype, istride)]) cannam@95: @ (if stride_fixed !uostride then [] cannam@95: else [Decl (C.stridetype, ostride)]) cannam@95: @ (choose_simd [] cannam@95: (if stride_fixed !uivstride then [] else cannam@95: [Decl ("int", sivs)])) cannam@95: @ (choose_simd [] cannam@95: (if stride_fixed !uovstride then [] else cannam@95: [Decl ("int", sovs)])) cannam@95: @ (if (not (window_param mode)) then [] cannam@95: else [Decl (C.constrealtypep, window)]) cannam@95: ), cannam@95: finalize_fcn (Asch annot)) cannam@95: cannam@95: in cannam@95: (unparse tree) ^ "\n" cannam@95: cannam@95: cannam@95: let main () = cannam@95: begin cannam@95: parse speclist usage; cannam@95: print_string (generate (check_size ()) !mode); cannam@95: end cannam@95: cannam@95: let _ = main()