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()); } } }