#### RemiAudio
#### Copyright (C) 2022-2024 Remilia Scarlet <remilia@posteo.jp>
#### Based on MVerb
#### Copyright (c) 2010 Martin Eastwood
####
#### 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 "./reverb"
module RemiAudio::DSP
class MVerb < Reverb
# Defines a set of parameters for `MVerb`.
class Preset < Reverb::Preset
# Applies a filter to the higher frequenices, with 0.0 meaning the filter
# is fully open, while 1.0 means it is nearly closed.
getter dampingFreq : Float64 = DEFAULT_DAMPING_FREQ
# How much feedback gets applied, from 0.0 to 1.0.
getter density : Float64 = DEFAULT_DENSITY
# How wide the pre-filter is. The larger the more frequencies from the
# original signal are processed. Likewise, the smaller this is, fewer
# frequencies are processed and the resulting sound is darker. Valid
# range is 0.0 to 1.0.
getter bandwidthFreq : Float64 = DEFAULT_BANDWIDTH_FREQ
# How long the reverb lasts, from 0.0 to 1.0.
getter decay : Float64 = DEFAULT_DECAY
# how much delay is added between the original signal and the processed
# signal, between 0.0 and 1.0.
getter predelay : Float64 = DEFAULT_PREDELAY
# The size of the virtual room. Note that larger values adds a slight
# delay to the early reflections.
getter size : Float64 = DEFAULT_SIZE
# How loud the mixed output signal is.
getter gain : Float64 = DEFAULT_GAIN
# How much of the processed signal is mixed into the original signal, from
# 0.0 to 1.0.
getter mix : Float64 = DEFAULT_MIX
# How much of the early reflection versus the late reverb tail is mixed
# into the signal. A value of 0 means that the signal contains only the
# early reflections, while a value of 1.0 means the signal contains only
# the late reverb tail.
getter earlyLateMix : Float64 = DEFAULT_EARLY_LATE_MIX
# Creates a new `Preset` instance.
def initialize
end
# :ditto:
def initialize(*, @dampingFreq : Float64 = DEFAULT_DAMPING_FREQ,
@density : Float64 = DEFAULT_DENSITY,
@bandwidthFreq : Float64 = DEFAULT_BANDWIDTH_FREQ,
@decay : Float64 = DEFAULT_DECAY,
@predelay : Float64 = DEFAULT_PREDELAY,
@size : Float64 = DEFAULT_SIZE,
@gain : Float64 = DEFAULT_GAIN,
@mix : Float64 = DEFAULT_MIX,
@earlyLateMix : Float64 = DEFAULT_EARLY_LATE_MIX)
MVerb.checkDampingFreq(@dampingFreq)
MVerb.checkDensity(@density)
MVerb.checkBandwidthFreq(@bandwidthFreq)
MVerb.checkDecay(@decay)
MVerb.checkPredelay(@predelay)
MVerb.checkSize(@size)
MVerb.checkGain(@gain)
MVerb.checkMix(@mix)
MVerb.checkEarlyLateMix(@earlyLateMix)
end
def dampingFreq=(value : Float64)
MVerb.checkDampingFreq(value)
@dampingFreq = value
end
def density=(value : Float64)
MVerb.checkDensity(value)
@density = value
end
def bandwidthFreq=(value : Float64)
MVerb.checkBandwidthFreq(value)
@bandwidthFreq = value
end
def decay=(value : Float64)
MVerb.checkDecay(value)
@decay = value
end
def predelay=(value : Float64)
MVerb.checkPredelay(value)
@predelay = value
end
def size=(value : Float64)
MVerb.checkSize(value)
@size = value
end
def gain=(value : Float64)
MVerb.checkGain(value)
@gain = value
end
def mix=(value : Float64)
MVerb.checkMix(value)
@mix = value
end
def earlyLateMix=(value : Float64)
MVerb.checkEarlyLateMix(value)
@earlyLateMix = value
end
end
# Names for the pre-constructed `Preset` instances in `MVerb::PRESETS`.
enum PresetNames
# A good default for General MIDI use.
GmDefault
# An alternative default for General MIDI use.
GmDefault2
# A subtle reverb effect.
Subtle
# A reverb similar to a large stadium.
Stadium
# A small wooden room or box.
Cupboard
# A dark reverb.
Dark
# A reverb where most values are set to 0.5.
Halves
# A large concert hall.
Hall
# A somewhat large concert hall, but slightly more subtle than the `Hall`
# preset.
SubtleHall
end
# Pre-constructed `Preset` instances for `MVerb` that correspond to the
# names in `PresetNames`.
PRESETS = {
PresetNames::GmDefault => Preset.new(dampingFreq: 0.59,
density: 0.469,
bandwidthFreq: 0.688,
decay: 0.5084,
predelay: 0.0,
size: 0.69,
gain: 0.5,
mix: 1.0,
earlyLateMix: 0.795),
PresetNames::GmDefault2 => Preset.new(dampingFreq: 0.69,
density: 0.425,
bandwidthFreq: 0.785,
decay: 0.5036,
predelay: 0.0,
size: 0.42,
gain: 0.5,
mix: 1.0,
earlyLateMix: 0.79),
PresetNames::Subtle => Preset.new(dampingFreq: 0.0,
density: 0.5,
bandwidthFreq: 1.0,
decay: 0.5,
predelay: 0.0,
size: 0.5,
gain: 1.0,
mix: 0.15,
earlyLateMix: 0.75),
PresetNames::Stadium => Preset.new(dampingFreq: 0.0,
density: 0.5,
bandwidthFreq: 1.0,
decay: 0.5,
predelay: 0.0,
size: 1.0,
gain: 1.0,
mix: 0.35,
earlyLateMix: 0.75),
PresetNames::Cupboard => Preset.new(dampingFreq: 0.0,
density: 0.5,
bandwidthFreq: 1.0,
decay: 0.5,
predelay: 0.0,
size: 0.25,
gain: 1.0,
mix: 0.35,
earlyLateMix: 0.75),
PresetNames::Dark => Preset.new(dampingFreq: 0.9,
density: 0.5,
bandwidthFreq: 0.1,
decay: 0.5,
predelay: 0.0,
size: 0.5,
gain: 1.0,
mix: 0.5,
earlyLateMix: 0.75),
PresetNames::Halves => Preset.new(dampingFreq: 0.5,
density: 0.5,
bandwidthFreq: 0.5,
decay: 0.5,
predelay: 0.5,
size: 0.75,
gain: 1.0,
mix: 0.5,
earlyLateMix: 0.5),
PresetNames::Hall => Preset.new(dampingFreq: 0.79,
density: 0.785,
bandwidthFreq: 0.555,
decay: 0.675,
predelay: 0.0105,
size: 1.0,
gain: 1.0,
mix: 0.32,
earlyLateMix: 0.69),
PresetNames::SubtleHall => Preset.new(dampingFreq: 0.59,
density: 0.525,
bandwidthFreq: 0.685,
decay: 0.599,
predelay: 0.007,
size: 0.655,
gain: 1.0,
mix: 0.15,
earlyLateMix: 0.78),
}
end
end