import bisect import math import struct import sys # Number of times to sample each second bitrate = 44100 intro = [ (1,3,3), (1,3,7), (1,3,10), (6,4,2), (1,3,1), (1,3,5), (1,3,8), (3,4,0), (1,2,11), (1,3,3), (1,3,6), (3,3,10), (1,2,8), (1,3,0), (1,3,3), (8,3,7), ] melody = [ (1,3,3), (1,3,7), (1,3,10), (1,4,2), (1,4,3), (1,4,7), (2,4,8), (1,3,1), (1,3,5), (1,3,8), (1,4,0), (1,4,1), (1,4,5), (2,4,8), (1,3,3), (1,3,7), (1,3,10), (1,4,2), (1,4,3), (1,4,10), (2,4,3), (1,3,1), (1,3,5), (1,3,8), (1,4,0), (1,4,10), (1,4,8), (2,4,10), (1,3,3), (1,3,7), (1,3,10), (1,4,2), (1,4,3), (1,4,7), (2,4,8), (1,3,1), (1,3,5), (1,3,8), (1,4,0), (1,4,1), (1,4,5), (2,4,1), (1,3,3), (1,3,7), (1,3,10), (1,4,2), (1,4,3), (1,4,10), (1,4,8), (1,4,7), (1,3,1), (1,3,5), (1,3,8), (1,4,0), (1,4,10), (1,4,8), (2,4,10), ] bass = [ (1,1,3), (1,1,10), (1,1,1), (1,1,8), (1,1,3), (1,2,3), (1,1,1), (1,1,10), ] melody2 = [ (1,0,0), (1,5,10), (1,5,8), (1,5,7), (1,5,8), (3,5,7,2), (1,5,3), (1,4,10), (6,5,1,2), (1/2,5,0,2), (1/2,5,1,2), (3,5,3,2), (1/2,5,10,2), (7/2,5,3,2), (8,0,0), (1,0,0), (1,5,3), (1,5,10), (1,5,10), (4/3,5,10), (4/3,5,8), (4/3,5,7), (1,0,0), (1,5,1), (1,5,8), (1,5,8), (4/3,5,8), (4/3,5,8), (4/3,5,10), (8,0,0), (1,0,0), (5,5,3,2), (2,5,10,2), ] melody3 = [ (1,0,0), (1,5,10), (1/2,5,8,2/3), (1/2,5,7,2/3), (1/4,5,8,1/2), (1/4,5,7,1/2), (1/4,5,8,1/2), (1/4,5,7,1/2), (1,5,8), (3,5,7,2), (1,5,3), (1,4,10), (1,5,1), (5,5,7,2), (1/2,5,7), (1/2,5,10), (1/4,5,7), (1/4,5,10), (1/4,5,7), (1/4,5,10), (1,6,3), (2,5,3,2), (1/2,6,3), (5/2,5,3,2), (1/2,5,10), (1/2,5,8), (1/2,5,7), (1/2,5,8), (1/2,5,7), (1/2,5,3), (1/2,4,10), (1/2,5,1), (1/2,5,0), (1/2,4,10), (1/2,4,8), (1/2,4,10), (1/2,5,3), (1/2,5,7), (1/2,5,3), (1/2,5,10), (4/3,5,7), (4/3,6,3), (4/3,6,3), (4/3,6,2), (4/3,5,10), (4/3,5,7), (3,5,5), (2,5,7), (2,5,8), (1,6,1), (1,5,3), (1,5,5), (2,5,7), (1,5,3), (1,5,8), (2,5,10), (3/2,6,0), (3/2,6,1), (5,6,3,2), ] outro = [ (1,3,3), (1,3,7), (1,3,10), (1,4,2), (1,4,3), (1,4,7), (2,4,8), (1,3,1), (1,3,5), (1,3,8), (1,4,0), (1,4,1), (1,4,5), (2,4,8), (1,2,11), (1,3,3), (1,3,6), (1,3,10), (1.5,3,11), (1.5,4,3), (3,4,8), (1.5,2,8), (1.5,3,0), (2,3,3), (16,3,7,2), ] def process(notes, start, speed=1, gain=1): """ 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, note[1], note[2], vol * gain)) t = end # Process all lists of notes music = [] process(intro, 0, 4) process(melody, 8, 4) process(melody, 24, 4) process(bass, 24, gain=1.5) process(bass, 32, gain=1.5) process(melody, 40, 4) process(melody2, 40, 4) process(bass, 40, gain=1.5) process(bass, 48, gain=1.5) process(melody, 56, 4) process(melody3, 56, 4) process(bass, 56, gain=1.5) process(bass, 64, gain=1.5) process(outro, 72, 4) music.sort() 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 # return int(2**13*(1+square(t, 440*2**(math.floor(5*t)/12)))) # Y = sum([math.sin(2 * i * math.pi * t * f) * math.exp(-0.0004 * 2 * math.pi * t * f) / 2**i for i in range(1, 4)]) # Y += Y * Y * Y # Y *= 1 + 16 * t * math.exp(-6 * t) 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 """ i = bisect.bisect(music, (t, 2**31)) # This is actually pretty efficient ngl # Because people usually don't have that many overlapping notes ret = 0 for j in range(max(i - 32, 0), i): m = music[j] # if m[0] + m[1] > t: ret += m[4] * tone(freq(m[2], m[3]), t - m[0]) return int(2**28 * ret) # Print out music encoded in s16 to standard output for i in range(0 * bitrate, 84 * bitrate): sys.stdout.buffer.write(struct.pack('i', at(i / bitrate)))