diff options
Diffstat (limited to 'yue.py')
-rw-r--r-- | yue.py | 69 |
1 files changed, 69 insertions, 0 deletions
@@ -0,0 +1,69 @@ +import bisect +import math +import struct +import sys + +# Number of times to sample each second +bitrate = 44100 +music = [] + + +def process(notes, start, speed=1, gain=1, blend=0): + """ + Adds a list of notes to the music list + """ + t = start + for note in notes: + vol = 1 + if len(note) == 4: + vol = note[3] + start = min(t, t + note[0] / speed) + end = max(t, t + note[0] / speed) + music.append((start, end + 16 * int(blend), note[1], note[2], vol * gain)) + t = end + + +def freq(octave, step): + """ + Returns the frequency of a note + """ + return 55 * 2 ** (octave + step / 12 - 1) + + +def tone(f, t): + """ + Returns the intensity of a tone of frequency f sampled at time t + https://dsp.stackexchange.com/questions/46598/mathematical-equation-for-the-sound-wave-that-a-piano-makes + https://youtu.be/ogFAHvYatWs?t=254 + """ + w = 2 * math.pi * f + Y = 0.6 * math.sin(w * t) * math.exp(-0.001 * w * t) + Y += 0.2 * math.sin(2 * w * t) * math.exp(-0.001 * w * t) + Y += 0.05 * math.sin(3 * w * t) * math.exp(-0.001 * w * t) + Y += Y * Y * Y + Y *= 1 + 16 * t * math.exp(-6 * t) + return Y + + +def at(t): + """ + Returns the total intensity of music sampled at time t + This is actually pretty efficient ngl + Because people usually don't have that many overlapping notes + """ + i = bisect.bisect(music, (t, 2**31)) + ret = 0 + for j in range(max(i - 32, 0), i): + m = music[j] + if m[1] > t: + ret += m[4] * tone(freq(m[2], m[3]), t - m[0]) + return int(2**28 * ret) + + +def play(start, end): + """ + Print music from the start time to end time encoded in s32 to standard output + """ + music.sort() + for i in range(start * bitrate, end * bitrate): + sys.stdout.buffer.write(struct.pack("i", at(i / bitrate))) |