cannam@127: (* cannam@127: * Copyright (c) 1997-1999 Massachusetts Institute of Technology cannam@127: * Copyright (c) 2003, 2007-14 Matteo Frigo cannam@127: * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology cannam@127: * cannam@127: * This program is free software; you can redistribute it and/or modify cannam@127: * it under the terms of the GNU General Public License as published by cannam@127: * the Free Software Foundation; either version 2 of the License, or cannam@127: * (at your option) any later version. cannam@127: * cannam@127: * This program is distributed in the hope that it will be useful, cannam@127: * but WITHOUT ANY WARRANTY; without even the implied warranty of cannam@127: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the cannam@127: * GNU General Public License for more details. cannam@127: * cannam@127: * You should have received a copy of the GNU General Public License cannam@127: * along with this program; if not, write to the Free Software cannam@127: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA cannam@127: * cannam@127: *) cannam@127: cannam@127: (* trigonometric transforms *) cannam@127: open Util cannam@127: cannam@127: (* DFT of real input *) cannam@127: let rdft sign n input = cannam@127: Fft.dft sign n (Complex.real @@ input) cannam@127: cannam@127: (* DFT of hermitian input *) cannam@127: let hdft sign n input = cannam@127: Fft.dft sign n (Complex.hermitian n input) cannam@127: cannam@127: (* DFT real transform of vectors of two real numbers, cannam@127: multiplication by (NaN I), and summation *) cannam@127: let dft_via_rdft sign n input = cannam@127: let f = rdft sign n input cannam@127: in fun i -> cannam@127: Complex.plus cannam@127: [Complex.real (f i); cannam@127: Complex.times (Complex.nan Expr.I) (Complex.imag (f i))] cannam@127: cannam@127: (* Discrete Hartley Transform *) cannam@127: let dht sign n input = cannam@127: let f = Fft.dft sign n (Complex.real @@ input) in cannam@127: (fun i -> cannam@127: Complex.plus [Complex.real (f i); Complex.imag (f i)]) cannam@127: cannam@127: let trigI n input = cannam@127: let twon = 2 * n in cannam@127: let input' = Complex.hermitian twon input cannam@127: in cannam@127: Fft.dft 1 twon input' cannam@127: cannam@127: let interleave_zero input = fun i -> cannam@127: if (i mod 2) == 0 cannam@127: then Complex.zero cannam@127: else cannam@127: input ((i - 1) / 2) cannam@127: cannam@127: let trigII n input = cannam@127: let fourn = 4 * n in cannam@127: let input' = Complex.hermitian fourn (interleave_zero input) cannam@127: in cannam@127: Fft.dft 1 fourn input' cannam@127: cannam@127: let trigIII n input = cannam@127: let fourn = 4 * n in cannam@127: let twon = 2 * n in cannam@127: let input' = Complex.hermitian fourn cannam@127: (fun i -> cannam@127: if (i == 0) then cannam@127: Complex.real (input 0) cannam@127: else if (i == twon) then cannam@127: Complex.uminus (Complex.real (input 0)) cannam@127: else cannam@127: Complex.antihermitian twon input i) cannam@127: in cannam@127: let dft = Fft.dft 1 fourn input' cannam@127: in fun k -> dft (2 * k + 1) cannam@127: cannam@127: let zero_extend n input = fun i -> cannam@127: if (i >= 0 && i < n) cannam@127: then input i cannam@127: else Complex.zero cannam@127: cannam@127: let trigIV n input = cannam@127: let fourn = 4 * n cannam@127: and eightn = 8 * n in cannam@127: let input' = Complex.hermitian eightn cannam@127: (zero_extend fourn (Complex.antihermitian fourn cannam@127: (interleave_zero input))) cannam@127: in cannam@127: let dft = Fft.dft 1 eightn input' cannam@127: in fun k -> dft (2 * k + 1) cannam@127: cannam@127: let make_dct scale nshift trig = cannam@127: fun n input -> cannam@127: trig (n - nshift) (Complex.real @@ (Complex.times scale) @@ cannam@127: (zero_extend n input)) cannam@127: (* cannam@127: * DCT-I: y[k] = sum x[j] cos(pi * j * k / n) cannam@127: *) cannam@127: let dctI = make_dct Complex.one 1 trigI cannam@127: cannam@127: (* cannam@127: * DCT-II: y[k] = sum x[j] cos(pi * (j + 1/2) * k / n) cannam@127: *) cannam@127: let dctII = make_dct Complex.one 0 trigII cannam@127: cannam@127: (* cannam@127: * DCT-III: y[k] = sum x[j] cos(pi * j * (k + 1/2) / n) cannam@127: *) cannam@127: let dctIII = make_dct Complex.half 0 trigIII cannam@127: cannam@127: (* cannam@127: * DCT-IV y[k] = sum x[j] cos(pi * (j + 1/2) * (k + 1/2) / n) cannam@127: *) cannam@127: let dctIV = make_dct Complex.half 0 trigIV cannam@127: cannam@127: let shift s input = fun i -> input (i - s) cannam@127: cannam@127: (* DST-x input := TRIG-x (input / i) *) cannam@127: let make_dst scale nshift kshift jshift trig = cannam@127: fun n input -> cannam@127: Complex.real @@ cannam@127: (shift (- jshift) cannam@127: (trig (n + nshift) (Complex.uminus @@ cannam@127: (Complex.times Complex.i) @@ cannam@127: (Complex.times scale) @@ cannam@127: Complex.real @@ cannam@127: (shift kshift (zero_extend n input))))) cannam@127: cannam@127: (* cannam@127: * DST-I: y[k] = sum x[j] sin(pi * j * k / n) cannam@127: *) cannam@127: let dstI = make_dst Complex.one 1 1 1 trigI cannam@127: cannam@127: (* cannam@127: * DST-II: y[k] = sum x[j] sin(pi * (j + 1/2) * k / n) cannam@127: *) cannam@127: let dstII = make_dst Complex.one 0 0 1 trigII cannam@127: cannam@127: (* cannam@127: * DST-III: y[k] = sum x[j] sin(pi * j * (k + 1/2) / n) cannam@127: *) cannam@127: let dstIII = make_dst Complex.half 0 1 0 trigIII cannam@127: cannam@127: (* cannam@127: * DST-IV y[k] = sum x[j] sin(pi * (j + 1/2) * (k + 1/2) / n) cannam@127: *) cannam@127: let dstIV = make_dst Complex.half 0 0 0 trigIV cannam@127: