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