Wave Generator (WG)
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © peacefulLizard50262

//@version=5
indicator("Wave Generator")

n = bar_index

max(source)=>
    var float max = na
    src = array.new<float>()
    array.push(src, source)
    max := math.max(nz(max[1]), array.get(src, 0))

min(source)=>
    var float min = na
    src = array.new<float>()
    array.push(src, source)
    min := math.min(nz(min[1]), array.get(src, 0))

min_max(src)=>
    ((src - min(src))/(max(src) - min(src)) - 0.5) * 2 

f_sine_wave(_wave_height, _wave_duration, _phase_shift, _phase_shift_2) =>
    _pi = math.pi
    _w = 2 * _pi / _wave_duration
    _sine_wave = _wave_height * math.sin(_w * n + _phase_shift + _phase_shift_2)
    _sine_wave
    
triangle_wave(_wave_height, _wave_duration, _num_harmonics, _phase_shift) =>
    _pi = math.pi
    sine_waves = array.new<float>()
    for i = 1 to _num_harmonics
        array.push(sine_waves, f_sine_wave(_wave_height / math.pow(2 * i - 1, 2), _wave_duration / (2 * i - 1), (i - 1) * _pi, int(_phase_shift) * _pi))
    _triangle_wave = array.avg(sine_waves)
    min_max(_triangle_wave)

saw_wave(_wave_height, _wave_duration, _num_harmonics, _phase_shift_2) =>
    _pi = math.pi
    sine_waves = array.new<float>()
    for i = 1 to _num_harmonics
        array.push(sine_waves, f_sine_wave(_wave_height / (i), _wave_duration / (i), i * _phase_shift_2 * _pi, 0))
    _saw_wave = array.avg(sine_waves)
    min_max(_saw_wave)

ramp_saw_wave(_wave_height, _wave_duration, _num_harmonics, _phase_shift_2) =>
    _pi = math.pi
    sine_waves = array.new<float>()
    for i = 1 to _num_harmonics
        array.push(sine_waves, f_sine_wave(_wave_height / (i), _wave_duration / (i), i * _phase_shift_2 * _pi, 66))
    _ramp_saw_wave = array.sum(sine_waves)
    min_max(_ramp_saw_wave)

square_wave(_wave_height, _wave_duration, _num_harmonics, _phase_shift_2) =>
    _pi = math.pi
    sine_waves = array.new<float>()
    for i = 1 to _num_harmonics
        array.push(sine_waves, f_sine_wave(_wave_height / (2 * i - 1), _wave_duration / (2 * i - 1), (i * 2 - 1) * _phase_shift_2  * _pi, 0))
    _square_wave = array.avg(sine_waves)
    min_max(_square_wave)

wave_select(style, _wave_height, _wave_duration, _num_harmonics, _phase_shift_2)=>
    switch style
        "Sine"     => f_sine_wave(_wave_height, _wave_duration, 0, _phase_shift_2)
        "Triangle" => triangle_wave(_wave_height, _wave_duration, _num_harmonics, _phase_shift_2)
        "Saw"      => saw_wave(_wave_height, _wave_duration, _num_harmonics, _phase_shift_2)
        "Ramp Saw" => ramp_saw_wave(_wave_height, _wave_duration, _num_harmonics, _phase_shift_2)
        "Square"   => square_wave(_wave_height, _wave_duration, _num_harmonics, _phase_shift_2)

fun = input.int(217, "Fundimental", 1)
harmonics = input.int(1024)
_phase_shift_2 = input.float(0, "Phase Rotation", step = 0.5)
style = input.string("Sine", "Wave Select", ["Sine","Triangle","Saw","Ramp Saw","Square"])
 
wave = wave_select(style, 1, fun, harmonics, _phase_shift_2)

plot(wave)