'''
Base sound waves.
'''

import math
import random
from utils import *


def sin(freq, phase=0.0, amplitude=1.0, **settings):
    '''
sin <freq> [<phase>=0 [<amplitude>=1]]

a sine curve with a frequency, an optional phase (between 0 and 1), and an
optional amplitude (between 0 and 1).
    '''
    freq = float(freq)
    phase = float(phase)
    amplitude = float(amplitude)
    def f(i, *_):
        j = i * freq
        return math.sin(math.pi * (j + phase)) * amplitude
    return f

def sins(*freqs, **settings):
    funs = list(map(sin, freqs))
    def f(i, *_):
        return avg(fun(i) for fun in funs)
    return f

def sins1(*freqs_phases, **settings):
    freqs = filter_index(lambda i: i & 1 == 0, freqs_phases)
    phases = filter_index(lambda i: i & 1 == 1, freqs_phases)
    funs = list(sin(f, p) for f, p in zip(freqs, phases))
    def f(i, *_):
        return avg(fun(i) for fun in funs)
    return f

def sins2(*freqs_phases_amplitudes, **settings):
    freqs = filter_index(lambda i: i % 3 == 0, freqs_phases_amplitudes)
    phases = filter_index(lambda i: i % 3 == 1, freqs_phases_amplitudes)
    amplitudes = filter_index(lambda i: i % 3 == 2, freqs_phases_amplitudes)
    funs = list(sin(f, p, a) for f, p, a in zip(freqs, phases, amplitudes))
    def f(i, *_):
        return avg(fun(i) for fun in funs)
    return f

def random_sins(n, **settings):
    freqs_phases_amplitudes = list(take(int(n), repeat(
        lambda: (random.randint(200, 800), random.random(), random.random()))))
    log('frequencies, phases, and amplitudes:', freqs_phases_amplitudes)
    return sins2(*concat(*freqs_phases_amplitudes))


__sample_functions__ = [
    sin, sins, sins1, sins2, random_sins
]