File src/remiaudio/windows.cr from the latest check-in


     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
#### RemiAudio
#### Copyright (C) 2022-2024 Remilia Scarlet <remilia@posteo.jp>
####
#### This program is free software: you can redistribute it and/or modify it
#### under the terms of the GNU Affero General Public License as published by
#### the Free Software Foundation, either version 3 of the License, or (at your
#### option) any later version.
####
#### This program is distributed in the hope that it will be useful, but WITHOUT
#### ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
#### FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
#### License for more details.
####
#### You should have received a copy of the GNU Affero General Public License
#### along with this program.  If not, see <https://www.gnu.org/licenses/>.
require "math"
require "libremiliacr"

# The Windows module contains implementations of various windowing functions.
module RemiAudio::Windows
  extend self

  alias WindowFunction = Proc(Int32, Slice(Float64))

  private macro defineCosineWindow(name, *a)
    def {{name.id}}(size : Int32) : Slice(Float64)
      {% i = 1 %}
      {% ops = [:+, :-] %}
      {% op = 0 %}
      Slice(Float64).new(size) do |i|
        {{a[0]}} -
        {% for i in 1...a.size %}
          {{a[i]}} *
          Math.cos({{i}} * Math::PI * 2 * i / (size - 1)) {% if i < a.size - 1 %} {{ops[op % 2].id}} {% end %}
          {% op += 1 %}
        {% end %}
      end
    end
  end

  defineCosineWindow(blackmanHarris, 0.35875, 0.48829, 0.14128, 0.01168)
  defineCosineWindow(blackman, 0.42, 0.5, 0.08)
  defineCosineWindow(hamming, 0.54, 0.46)
  defineCosineWindow(flattop, 0.21557895, 0.41663158, 0.277263158, 0.083578947, 0.006947368) # TODO known to fail
  defineCosineWindow(nuttall, 0.355768, 0.487396, 0.144232, 0.012604)
  defineCosineWindow(blackmanNuttall, 0.3635819, 0.4891775, 0.1365995, 0.0106411)

  def hann(size : Int32) : Slice(Float64)
    Slice(Float64).new(size) do |i|
      0.5_f64 * (1.0_f64 - Math.cos(Math::PI * 2 * i / (size - 1)))
    end
  end
end