Last active
February 23, 2021 22:58
-
-
Save mortie/53b35fb56a95f82639f927d300c69ad1 to your computer and use it in GitHub Desktop.
Horrible Music
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
| #!/usr/bin/env python3 | |
| import simpleaudio as sa | |
| import numpy as np | |
| import sys | |
| import wave | |
| kick = wave.open("kick.wav") | |
| class Mixer: | |
| def __init__(self, wav, secs): | |
| self.sampwidth = wav.getsampwidth() | |
| self.samprate = wav.getframerate() | |
| self.nframes = wav.getnframes() | |
| self.position = 0 | |
| self.time = 0 | |
| self.progress = 0.2 | |
| self.writers = [] | |
| self.output = np.empty(secs * self.sampwidth * self.samprate, "float") | |
| bs = wav.readframes(self.nframes) | |
| self.data = np.empty(self.nframes, "float") | |
| for i in range(0, self.nframes): | |
| high = bs[i * 2] | |
| low = bs[i * 2 + 1] | |
| self.data[i] = (high << 8 | low) | |
| def add(self): | |
| self.writers.append(self.position) | |
| def proceed(self, secs): | |
| idx = int(self.position) | |
| samps = secs * self.sampwidth * self.samprate | |
| self.position += samps | |
| self.time += secs | |
| self.progress -= secs | |
| if self.progress < 0: | |
| sys.stderr.write(f" {self.time} -- {len(self.writers)} concurrent \r") | |
| self.progress = 0.2 | |
| while idx <= self.position: | |
| for start_pos in self.writers: | |
| offset = int(idx - start_pos) | |
| if offset >= self.nframes: | |
| continue | |
| samp = self.data[offset] | |
| self.output[idx] += samp | |
| idx += 1 | |
| for i, start_pos in enumerate(self.writers): | |
| offset = int(idx - start_pos) | |
| if offset > self.nframes: | |
| if i == len(self.writers) - 1: | |
| self.writers.pop() | |
| else: | |
| self.writers[i] = self.writers.pop() | |
| def play(self): | |
| return sa.play_buffer(np.array(self.output, "byte"), 1, self.sampwidth, self.samprate) | |
| def save(self, name): | |
| f = wave.open(name, "wb") | |
| f.setnchannels(1) | |
| f.setsampwidth(self.sampwidth) | |
| f.setframerate(self.samprate) | |
| f.writeframes(np.array(self.output, "byte")) | |
| m = Mixer(kick, 102) | |
| def playHz(hz, sec): | |
| t = 0 | |
| while t < sec: | |
| m.add() | |
| m.proceed(1 / hz) | |
| t += 1 / hz | |
| for i in range(0, 2): | |
| m.add() | |
| m.proceed(1) | |
| for i in range(0, 4): | |
| m.add() | |
| m.proceed(0.5) | |
| for i in range(0, 8): | |
| m.add() | |
| m.proceed(0.25) | |
| for i in range(0, 15): | |
| m.add() | |
| m.proceed(0.125) | |
| print("\nramping") | |
| hz = 8 | |
| while hz < 98: | |
| m.add() | |
| m.proceed(1 / hz) | |
| hz += 4 / hz | |
| playHz(98, 0.5) | |
| # Frequencies from https://pages.mtu.edu/~suits/notefreqs.html | |
| print("\ngo") | |
| playHz(110, 0.5) | |
| playHz(123.47, 0.5) | |
| playHz(110, 0.5) | |
| playHz(130.81, 0.5) | |
| playHz(146.83, 0.5) | |
| playHz(130.81, 0.5) | |
| playHz(123.47, 1) | |
| # | |
| playHz(110, 0.5) | |
| playHz(123.47, 0.5) | |
| playHz(110, 0.5) | |
| playHz(130.81, 0.5) | |
| playHz(123.47, 2) | |
| # | |
| # | |
| # | |
| playHz(110, 0.5) | |
| playHz(123.47, 0.5) | |
| playHz(110, 0.5) | |
| playHz(130.81, 0.5) | |
| playHz(146.83, 0.5) | |
| playHz(130.81, 0.5) | |
| playHz(123.47, 1) | |
| # | |
| playHz(130.81, 1) | |
| # | |
| playHz(123.47, 1) | |
| # | |
| playHz(110, 2) | |
| # | |
| # | |
| # | |
| print("\nramping 2") | |
| hz = 110 | |
| while hz < 392: | |
| m.add() | |
| m.proceed(1 / hz) | |
| hz += 16 / hz | |
| print("\nA's") | |
| playHz(440, 2) | |
| playHz(220, 2) | |
| playHz(110, 2) | |
| playHz(60, 2) | |
| playHz(30, 2) | |
| playHz(15, 2) | |
| playHz(7.5, 2) | |
| m.proceed(2) | |
| print("\ndone") | |
| m.save("music.wav") | |
| m.play().wait_done() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment