using System;
using Chernobyl.Extensions;
using Chernobyl.Mathematics.Space;
namespace Chernobyl.Generation
{
///
/// Methods to help with the creation of the audio.
///
public static class Audio
{
///
/// Returns a methods that produces a sin wave with the specified properties.
///
/// Method that returns the number of times the wave repeats in hertz.
/// This value dictates the horizontal squashing and stretching of the wave.
/// The method that returns the number of samples carried per second.
/// Method that returns the volume of the produced wave. This is
/// applied to the wave as a vertical scalar. For example, setting this to .5 reduces the
/// height wave by half, setting this to 2 doubles the height of the wave.
public static Func CreateSinOscillator(Func frequency, Func sampleRate, Func amplitude)
{
// One cycle of a wave includes both the peak and trough and starts at the vertical origin (0 for
// example but can be anything) and ends at the same vertical origin. This can be described
// as the 360 degree circle (2PI radians). The 'sample' decides which wave along the
// horizontal axis we are sampling from. The 'Frequency' dictates how close together or
// how far apart these waves are. Dividing by the sample rate converts the frequency to
// "normalized frequency" or cycles per sample.
var oneCycleInRadians = 2 * Math.PI; // Use radians because Math.Sin takes radians.
var phase = new Func(sample => (oneCycleInRadians * sample * frequency()) / sampleRate())
.Bind(Wave.Step(1, reset: sample => sample >= sampleRate()));
return Wave.Sin.Bind(phase).Select(value => value * amplitude());
}
}
}