Created
August 5, 2020 16:14
-
-
Save cjhanks/6cebd5ff7a3c248a9d77e95dff7eae8b to your computer and use it in GitHub Desktop.
beat_frequencies
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
from argparse import ArgumentParser | |
import sys | |
import math | |
import matplotlib.pyplot as plt | |
import numpy as np | |
# This variable holds the steps for a minor scale | |
MinorSteps = [ | |
0, # A | |
2, # B | |
3, # C | |
5, # D | |
7, # E | |
8, # F | |
10, # G | |
12, # A | |
] | |
MinorStepNames = [ | |
'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', | |
'E', 'F', 'F#', 'G', 'G#' | |
] | |
Steps = [ 1, 3, 5, 6, 8, 10, 12, | |
13, 15, 17, 18, 20, 22, 24] | |
def notestep_to_frequency(base_frequency, step): | |
return base_frequency * (2 ** (step / 12)) | |
def frequency_to_notestep(base_frequency, frequency): | |
# This is a derivation of the above frequency to solve for notestep | |
if frequency == 0: | |
return 0 | |
else: | |
return 17.3123404906676 * math.log(frequency / base_frequency) | |
def main(): | |
argp = ArgumentParser() | |
argp.add_argument( | |
'--base', | |
type=int, | |
default=220) | |
args = argp.parse_args() | |
# Generate the frequencies of a two octave list of the 12 tone scale. | |
freq24 = [] | |
for i in range(24): | |
freq24.append(notestep_to_frequency(args.base, i)) | |
# Generate the frequencies of a minor scale | |
freq8 = [] | |
for step in MinorSteps: | |
freq8.append(notestep_to_frequency(args.base, step)) | |
# For each note in the minor scale, compute its beat frequency with | |
# each note in the 24 tone scale. | |
beats = [] | |
for freq0 in freq24: | |
row = [] | |
for freq1 in freq8: | |
beat = abs(freq1 - freq0) | |
row.append(beat) | |
beats.append(row) | |
#plt.imshow(np.array(beats), cmap='jet') | |
# Now, derive the number of note steps from the frequency | |
notes = [] | |
for row in beats: | |
new_row = [] | |
for freq in row: | |
note = frequency_to_notestep(args.base, freq) | |
new_row.append(note) | |
notes.append(new_row) | |
#plt.imshow(np.array(beats), cmap='inferno') | |
# The note numbers can be difficult to interpret, so let's convert them | |
# into human readable notes. | |
human = [] | |
for (i, row) in enumerate(notes): | |
human_row = [] | |
for (j, step) in enumerate(row): | |
ideal_step = int(step) | |
ideal_freq = notestep_to_frequency(args.base, ideal_step) | |
ideal_name = MinorStepNames[ideal_step % 12] | |
actual_freq = notestep_to_frequency(args.base, step) | |
octave = ideal_step // 12 | |
freq_shift = ideal_freq - actual_freq | |
name = '{:+2d}{:2s}{:+6.2f}'.format(octave, ideal_name, freq_shift) | |
human_row.append(name) | |
human.append(human_row) | |
# Print it into a CSV friendly format. | |
for row in human: | |
for value in row: | |
sys.stdout.write('%s,' % value) | |
sys.stdout.write('\n') | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment