public static double Sine(int index, double frequency) { return Math.Sin(frequency * index); }
class Program { public static void Main(string[] args) { double[] data = new double[75]; // . for (int index = 1; index < 76; index++) { // . data[index-1] = Sine(index, Math.PI * 2 * 2.0 / 75); // . } Console.ReadKey(true); // . } public static double Sine(int index, double frequency) { return Math.Sin(frequency * index); } }
public static void Draw (double[] data) { Console.BufferHeight = 25; // . Console.CursorVisible = false; // . for (int y = 0; y < 19; y++) {// . Console.SetCursorPosition(77, y + 5);// . Console.Write(9 - y); // . } for (int x = 0; x < 75; x++) { // Console.SetCursorPosition(x, x % 3); // . Console.Write(x + 1); // . int point = (int)(data[x] * 9); // -9 9. int step = (point > 0)? -1 : 1; // 0. for (int y = point; y != step; y += step) {// Console.SetCursorPosition(x, point + 14 - y); // . Console.Write("█"); // . } } }
private static double Saw(int index, double frequency) { return 2.0 * (index * frequency - Math.Floor(index * frequency )) -1.0; }
private static double Triangle(int index, double frequency) { return 2.0 * Math.Abs (2.0 * (index * frequency - Math.Floor(index * frequency + 0.5))) - 1.0; }
private static double Flat(int index, double frequency) { if (Math.Sin(frequency * index ) > 0) return 1; else return -1; }
public static void SaveWave(Stream stream, short[] data, int sampleRate) { BinaryWriter writer = new BinaryWriter(stream); short frameSize = (short)(16 / 8); // (16 8). writer.Write(0x46464952); // "RIFF". writer.Write(36 + data.Length * frameSize); // . writer.Write(0x45564157); // "WAVE". writer.Write(0x20746D66); // "frm ". writer.Write(16); // . writer.Write((short)1); // 1 PCM. writer.Write((short)1); // . writer.Write(sampleRate); // . writer.Write(sampleRate * frameSize); // ( ). writer.Write(frameSize); // . writer.Write((short)16); // . writer.Write(0x61746164); // "DATA". writer.Write(data.Length * frameSize); // . for (int index = 0; index < data.Length; index++) { // . foreach (byte element in BitConverter.GetBytes(data[index])) { // . stream.WriteByte(element); // . } } }
public static void Main(string[] args) { int sampleRate = 8000; // . short[] data = new short[sampleRate]; // 16 . double frequency = Math.PI * 2 * 440.0 / sampleRate; // . for (int index = 0; index < sampleRate; index++) { // . data[index] = (short)(Sine(index, frequency) * short.MaxValue); // 32767 -32767. } Stream file = File.Create("test.wav"); // . SaveWave(file, data, sampleRate); // . file.Close(); // . }
public static double Length(double compressor, double frequency, double position, double length, int sampleRate){ return Math.Exp(((compressor / sampleRate) * frequency * sampleRate * (position / sampleRate)) / (length / sampleRate)); }
data[index] = (short)(Sine(index, frequency) * Length(-0.0015, frequency, index, 1.0, sampleRate) * short.MaxValue);
private static double GetNote(int key, int octave) { return 27.5 * Math.Pow(2, (key + octave * 12.0) / 12.0); }
public class Element { int length; int start; double frequency; double compressor; public Element(double frequency, double compressor, double start, double length, int sampleRate) { this.frequency = Math.PI * 2 * frequency / sampleRate ; this.start = (int)(start * sampleRate); this.length = (int)(length * sampleRate); this.compressor = compressor / sampleRate; } public void Get(ref short[] data, int sampleRate) { double result; int position; for (int index = start; index < start + length * 2; index++) { position = index - start; result = 0.5 * Sine(position, frequency) ; result += 0.4 * Sine(position, frequency / 4); result += 0.2 * Sine(position, frequency / 2); result *= Length(compressor, frequency, position, length, sampleRate) * short.MaxValue * 0.25; result += data[index]; if (result > short.MaxValue) result = short.MaxValue; if (result < -short.MaxValue) result = -short.MaxValue; data[index] = (short)(result); } } private static double Length(double compressor, double frequency, double position, double length, int sampleRate){ return Math.Exp((compressor * frequency * sampleRate * (position / sampleRate)) / (length / sampleRate)); } private static double Sine(int index, double frequency) { return Math.Sin(frequency * index); } }
public class Track { private int sampleRate; private List<Element> elements = new List<Element>(); private short[] data; private int length; private static double GetNote(int key, int octave) { return 27.5 * Math.Pow(2, (key + octave * 12.0) / 12.0); } public Track(int sampleRate) { this.sampleRate = sampleRate; } public void Add(double frequency, double compressor, double start, double length) { if (this.length < (start+ length * 2 + 1) * sampleRate) this.length = (int)(start + length * 2 +1) * sampleRate; elements.Add(new Element(frequency, compressor, start, length, sampleRate)); } public void Synthesize() { data = new short[length]; foreach (var element in elements) { element.Get(ref data, sampleRate); } } }
public void Music (string melody, double temp = 60.0) { string[] words = melody.Split(' '); foreach (string word in words) { int note = notes[word.Substring(0, word.Length - 1)]; int octave = Convert.ToInt32(word.Substring(word.Length - 1, 1)); if (note > 2){ switch (note) { case 3: dtime = Math.Pow(0.5, octave + 1) * 8 * (60.0 / temp); break; case 4: length += (int)(Math.Pow(0.5, octave + 1) * 8 * (60.0 / temp)); position += Math.Pow(0.5, octave + 1) * 8 * (60.0 / temp); break; } } else { Add(GetNote(note, octave), -0.51, position, dtime); position += dtime; } } }
L4 B6 S4 D7 B6 F#6 S4 B6 F#6
Where L is a command that specifies the length of a note, and S creates a pause, the remaining characters are notes. Actually, the writing of the software synthesizer is completed on this, and we can check the result by listening to the segment “Bach’s joke”Source: https://habr.com/ru/post/178915/
All Articles