Last active
January 25, 2016 09:45
-
-
Save xoposhiy/fc08d29516b7c13149b9 to your computer and use it in GitHub Desktop.
Play C# Theme
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Threading; | |
using NAudio.Wave; | |
namespace StarWarsTheme | |
{ | |
public class Program | |
{ | |
private static void Main() | |
{ | |
var melody = new Melody() | |
.Add("C#/4 C#/4 C#/4") | |
.Add("a/8. E/16 C#/4") | |
.Add("a/8. E/16 C#/2") | |
.Add("G#/4 G#/4 G#/4") | |
.Add("A/8. E/16 C/4") | |
.Add("a/8. E/16 C#/2"); | |
new MelodyPlayer().Octave(0) | |
.Tempo(2).Play(melody); | |
} | |
} | |
public class Note | |
{ | |
private readonly int beat; | |
private readonly bool isLong; | |
private readonly string name; | |
public Note(string name, int beat, bool isLong) | |
{ | |
this.beat = beat; | |
this.name = name; | |
this.isLong = isLong; | |
} | |
public double GetFrequency(int octave) | |
{ | |
var notesLine = "c c# d d# e f f# g g# a a# b"; | |
var notes = (notesLine + " " + notesLine.ToUpper()).Split(); | |
var n = Array.IndexOf(notes, name); | |
return 27.5 * Math.Pow(2, octave + (n + 27) / 12.0); | |
} | |
public double GetLength() | |
{ | |
return (isLong ? 3.0/2 : 1) / beat; | |
} | |
public override string ToString() | |
{ | |
return name + "/" + beat + (isLong ? "." : ""); | |
} | |
} | |
public class Melody | |
{ | |
private readonly List<Note> notes = new List<Note>(); | |
public IReadOnlyList<Note> Notes { get { return notes; } } | |
public Melody Add(string notesText) | |
{ | |
notes.AddRange( | |
from note in notesText.Split() | |
let parts = note.Split('/', '.') | |
let name = parts[0] | |
let len = int.Parse(parts[1]) | |
let isLong = note.EndsWith(".") | |
select new Note(name, len, isLong)); | |
return this; | |
} | |
} | |
public class MelodyPlayer | |
{ | |
private int octave; | |
private double tempo; | |
public MelodyPlayer Octave(int value) | |
{ | |
octave = value; | |
return this; | |
} | |
public MelodyPlayer Tempo(double value) | |
{ | |
tempo = value; | |
return this; | |
} | |
public void Play(Melody melody) | |
{ | |
foreach (var note in melody.Notes) | |
{ | |
Console.WriteLine(note); | |
Beep(note.GetFrequency(octave), tempo * note.GetLength()); | |
} | |
} | |
public static void Beep(double freq, double seconds) | |
{ | |
var sineWaveProvider = new SineWaveProvider32 | |
{ | |
Amplitude = 0.25f, | |
Frequency = (float) freq | |
}; | |
var waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()); | |
waveOut.Init(sineWaveProvider); | |
waveOut.Play(); | |
Thread.Sleep((int) (seconds*1000)); | |
waveOut.Stop(); | |
waveOut.Dispose(); | |
} | |
} | |
public class SineWaveProvider32 : WaveProvider32 | |
{ | |
private int sample; | |
public SineWaveProvider32() | |
{ | |
Frequency = 1000; | |
Amplitude = 0.25f; // Let's not hurt our ears | |
} | |
public float Frequency { get; set; } | |
public float Amplitude { get; set; } | |
public override int Read(float[] buffer, int offset, int sampleCount) | |
{ | |
var sampleRate = WaveFormat.SampleRate; | |
for (var n = 0; n < sampleCount; n++) | |
{ | |
buffer[n + offset] = (float) (Amplitude*Math.Sin((2*Math.PI*sample*Frequency)/sampleRate)); | |
sample++; | |
if (sample >= sampleRate) | |
sample = 0; | |
} | |
return sampleCount; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment