Skip to content

Instantly share code, notes, and snippets.

@jiaaro
Created May 23, 2015 17:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jiaaro/79ecb6c1a06095fd3b36 to your computer and use it in GitHub Desktop.
Save jiaaro/79ecb6c1a06095fd3b36 to your computer and use it in GitHub Desktop.
Make a chord progressions
from pydub import AudioSegment
from pydub.generators import Sine, Square, WhiteNoise
from pydub.playback import play
# From https://gist.github.com/jiaaro/339df443b005e12d6c2a
def note_to_freq(note, concert_A=440.0):
'''
from wikipedia: http://en.wikipedia.org/wiki/MIDI_Tuning_Standard#Frequency_values
'''
return (2.0 ** ((note - 69) / 12.0)) * concert_A
def beat_duration_from_bpm(bpm=120.0):
minute = 60 * 1000.0
return minute / bpm
class ChordParsingError(Exception): pass
SCALE_SHAPES = {
""
}
CHORD_SHAPES = {
# major
"": (0, +4, +7),
# minor
"m": (0, +3, +7),
# diminished
"dim": (0, +3, +6),
# diminished
"dim7": (0, +3, +6, +9),
# 7
"7": (0, +4, +7, +10),
# minor 7
"m7": (0, +3, +7, +10),
# maj7
"maj7": (0, +4, +7, +11),
}
# MIDI Note numbers
NOTE_NUMBERS = {
"A": 57,
"A#": 58, "Bb": 58,
"B": 59, "Cb": 59,
"C": 60,
"C#": 61, "Db": 61,
"D": 62,
"D#": 63, "Eb": 63,
"E": 64, "Fb": 64,
"F": 65, "E#": 65,
"F#": 66, "Gb": 66,
"G": 67,
"G#": 68, "Ab": 68,
}
def parse_chord(chord):
"""
returns the frequency of each note in a chord with the
root nearest to near_freq
"""
try:
if len(chord) > 1 and chord[1] in ("#", "b"):
root = chord[:2]
shape = CHORD_SHAPES[chord[2:]]
else:
root = chord[0]
shape = CHORD_SHAPES[chord[1:]]
except IndexError:
raise ChordParsingError
root_note = NOTE_NUMBERS[root]
chord_notes = [root_note + dlta for dlta in shape]
return [note_to_freq(note) for note in chord_notes]
def anchored_chord(chord, anchor_freq=250.0):
freqs = parse_chord(chord)
root = freqs[0] / 8
while freqs[-1] < anchor_freq:
freqs.append(freqs.pop(0) * 2)
while freqs[0] > anchor_freq:
freqs.insert(0, freqs.pop() / 2)
freqs.insert(0, root)
return freqs
def make_chord(chord, duration=1000, generator=Sine):
freqs = anchored_chord(chord)
output = generator(freqs[0]).to_audio_segment(duration=duration, volume=-10)
for freq in anchored_chord(chord):
output *= generator(freq).to_audio_segment(duration=duration, volume=-20)
return output.fade_in(10).fade_out(250)
beats = beat_duration_from_bpm(120)
progression = (
make_chord("Cm", 4*beats)
+ make_chord("G7", 4*beats)
+ make_chord("Fm", 6*beats)
+ make_chord("G7", 2*beats)
)
tick = WhiteNoise().to_audio_segment(5, volume=-15)
for i in range(16*2):
progression = progression.overlay(tick, position=i*(beats/2))
play(progression)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment