Created
October 19, 2016 00:28
-
-
Save RavuAlHemio/494326df7688412e68165f3b8ccdc1ab to your computer and use it in GitHub Desktop.
Not Deep Note (the THX sound)
This file contains hidden or 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
// Not Deep Note | |
// | |
// Released into the public domain. | |
// http://creativecommons.org/publicdomain/zero/1.0/ | |
using System; | |
using System.IO; | |
static class NotDeepNote | |
{ | |
static readonly double[] TargetFrequencies = | |
{ | |
// C | |
65.406, | |
// E | |
82.407, | |
// G | |
97.999, | |
// c | |
130.813, | |
// e | |
164.814, | |
// g | |
195.998, | |
// c' | |
261.626, | |
// e' | |
329.628, | |
// g' | |
391.995, | |
// c'' | |
523.251, | |
// e'' | |
659.255, | |
// g'' | |
783.991, | |
// c''' | |
1046.502, | |
// e''' | |
1318.51, | |
// g''' | |
1567.982 | |
}; | |
static ulong LfsrState; | |
static void AdvanceLfsr() | |
{ | |
ulong newState = (LfsrState >> 1); | |
// top bit: 64 ^ 63 ^ 61 ^ 60 | |
ulong topBit = | |
((LfsrState >> 63) & 0x1) ^ | |
((LfsrState >> 62) & 0x1) ^ | |
((LfsrState >> 60) & 0x1) ^ | |
((LfsrState >> 59) & 0x1) | |
; | |
LfsrState = (newState | (topBit << 63)); | |
} | |
/// <return>A pseudorandom value between 0.0 and 1.0 inclusive.</return> | |
static double ObtainRandom() | |
{ | |
ulong numerator = LfsrState; | |
for (int i = 0; i < 4; ++i) | |
{ | |
AdvanceLfsr(); | |
} | |
return numerator/((double)ulong.MaxValue); | |
} | |
public static void Main() | |
{ | |
//LfsrState = (ulong) DateTime.Now.Ticks; | |
//LfsrState = 0x1234567812345678UL; | |
LfsrState = 0x1337133713371337UL; | |
const double minOffset = 100.0; | |
const double maxOffset = 200.0; | |
const int bytesPerSample = 4; | |
const int samplingRateHz = 192000; | |
const int buildTimeS = 10; | |
const int holdTimeS = 10; | |
var current = new double[TargetFrequencies.Length]; | |
var step = new double[TargetFrequencies.Length]; | |
var cumulative = new double[TargetFrequencies.Length]; | |
// find starting values and step sizes | |
for (int i = 0; i < current.Length; ++i) | |
{ | |
current[i] = 200 + ObtainRandom() * 200; | |
step[i] = (TargetFrequencies[i] - current[i]) / ((double)buildTimeS * samplingRateHz); | |
} | |
using (var oot = new FileStream("out.wav", FileMode.Create, FileAccess.Write)) | |
{ | |
// output the WAV boilerplate | |
oot.WriteNaiveEncoding("RIFF"); | |
oot.WriteIntLE(36 + bytesPerSample * samplingRateHz * 1 /* channel */ * (buildTimeS + holdTimeS)); | |
oot.WriteNaiveEncoding("WAVE"); | |
oot.WriteNaiveEncoding("fmt "); | |
oot.WriteIntLE(16); | |
oot.WriteShortLE(1); // PCM | |
oot.WriteShortLE(1); // 1 channel | |
oot.WriteIntLE(samplingRateHz); | |
oot.WriteIntLE(samplingRateHz * 1 /* channel */ * bytesPerSample); | |
oot.WriteShortLE(1 /* channel */ * bytesPerSample); | |
oot.WriteShortLE(bytesPerSample * 8); | |
oot.WriteNaiveEncoding("data"); | |
oot.WriteIntLE(bytesPerSample * samplingRateHz * 1 /* channel */ * (buildTimeS + holdTimeS)); | |
// build the convergence | |
for (int t = 0; t < (buildTimeS + holdTimeS) * samplingRateHz; ++t) | |
{ | |
double td = t / ((double)samplingRateHz); | |
double currentSample = 0.0; | |
for (int i = 0; i < current.Length; ++i) | |
{ | |
cumulative[i] += current[i]; | |
currentSample += Math.Sin(2 * Math.PI * cumulative[i] / samplingRateHz); | |
if (t < buildTimeS * samplingRateHz) | |
{ | |
// keep approaching | |
current[i] += step[i]; | |
} | |
} | |
// volume control | |
currentSample /= current.Length; | |
if (t < buildTimeS * samplingRateHz) | |
{ | |
// fade in | |
currentSample *= td / buildTimeS; | |
} | |
// output the sample | |
int actualSample = (int)(currentSample * int.MaxValue); | |
oot.WriteIntLE(actualSample); | |
} | |
} | |
} | |
public static void WriteNaiveEncoding(this Stream stream, string str) | |
{ | |
foreach (char c in str) | |
{ | |
if (c > 0xFF) | |
{ | |
throw new ArgumentOutOfRangeException("str has character out of range"); | |
} | |
stream.WriteByte((byte) c); | |
} | |
} | |
public static void WriteShortLE(this Stream stream, short val) | |
{ | |
var uval = unchecked((ushort)val); | |
stream.WriteByte((byte)((uval >> 0) & 0xFF)); | |
stream.WriteByte((byte)((uval >> 8) & 0xFF)); | |
} | |
public static void WriteIntLE(this Stream stream, int val) | |
{ | |
var uval = unchecked((uint)val); | |
stream.WriteByte((byte)((uval >> 0) & 0xFF)); | |
stream.WriteByte((byte)((uval >> 8) & 0xFF)); | |
stream.WriteByte((byte)((uval >> 16) & 0xFF)); | |
stream.WriteByte((byte)((uval >> 24) & 0xFF)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment