Skip to content

Instantly share code, notes, and snippets.

@salt-die
Last active April 25, 2020 18:30
Show Gist options
  • Save salt-die/8e4d7120803080af055c3f7707fc9a3c to your computer and use it in GitHub Desktop.
Save salt-die/8e4d7120803080af055c3f7707fc9a3c to your computer and use it in GitHub Desktop.
various songs from numpy arrays
from itertools import chain, product, repeat, starmap
from more_itertools import interleave
from functools import lru_cache
import numpy as np
import sounddevice as sd
SAMPLE_RATE = 44100
sd.default.samplerate = SAMPLE_RATE
NOTES = 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'
# ---- Build note to pitch dict ----
a = 2**(1/12)
note_to_pitch = {f'{note}{octave}': 440 * a**(12 * (int(octave) - 4) + i)
for (i, note), octave in product(enumerate(NOTES, start=-9), range(9))}
for note, pitch in list(note_to_pitch.items()):
if '#' in note:
enharmonic = f'{NOTES[NOTES.index(note[0]) + 2]}b{note[-1]}'
note_to_pitch[enharmonic] = pitch
# --------------------------------------
@lru_cache
def sound_array(frequency, duration, rest=0, frequency_by_name=True):
if frequency_by_name: frequency = note_to_pitch[frequency]
samples = np.arange(SAMPLE_RATE * duration, dtype=np.float) / SAMPLE_RATE
sound = (10000 * np.sin(2 * np.pi * frequency * samples)).astype(np.int16)
if rest: sound[-int(SAMPLE_RATE * rest):] = 0
return sound
def compile_song(*note_lists):
return sum(np.concatenate(tuple(starmap(sound_array, note_list))) for note_list in note_lists)
def prelude_constructor(clef):
def measure_builder(notes, note1, note2=None):
interleaved = tuple(interleave(notes, repeat(note1)))
if note2 is not None: return measure_builder(interleaved, note2)
return repeat(interleaved, 2)
measures = chain.from_iterable(measure_builder(notes, note1, note2) for notes, note1, note2 in clef)
return zip(chain.from_iterable(measures), repeat(.2)) # Add duration to all notes
treble = ((( 'C5', 'C4'), 'D4', 'Eb4'), (('Ab4', 'C4'), 'E4', 'F4'),
(( 'B4', 'D4'), 'Eb4', 'F4'), (( 'C5', 'Eb4'), 'F4', 'G4'),
(('Eb5', 'Eb4'), 'G4', 'Ab4'), (( 'D5', 'D4'), 'E4', 'F#4'),
(( 'D5', 'D4'), 'F#4', 'G4'), (( 'C5', 'C4'), 'D4', 'E4'),
(( 'C5', 'C4'), 'E4', 'F4'), (('Bb4', 'D4'), 'Eb4', 'F4'),
(('Bb4', 'Eb4'), 'F4', 'G4'), (('Ab4', 'Eb4'), 'F4', 'G4'),
(('Ab4', 'Bb3'), 'C4', 'D4'), (('G4', 'Eb4'), 'Ab3', 'Bb3'),
(( 'F4', 'A3'), 'Bb3', 'C4'), (('F4', 'B3'), 'C4', 'D4'),
(('F4', 'B3'), 'C4', 'D4'))
bass = ((( 'C3', 'Eb3'), 'F3', 'G3'), (( 'C3', 'F3'), 'G3', 'Ab3'),
(( 'C3', 'F3'), 'G3', 'Ab3'), (( 'C3', 'G3'), 'D3', 'Eb3'),
(( 'C3', 'Ab3'), 'Bb3', 'C4'), (( 'C3', 'F#3'), 'G3', 'A3'),
(('Bb2', 'G3'), 'A3', 'Bb3'), (('Bb2', 'E3'), 'F3', 'G3'),
(('Ab2', 'F3'), 'G3', 'Ab3'), (('Ab2', 'F3'), 'C3', 'D3'),
(( 'G2', 'G3'), 'D3', 'Eb3'), (( 'C3', 'Ab3'), 'D3', 'Eb3'),
(( 'D3', 'Ab3'), 'Eb3', 'F3'), (('Eb3', 'Ab3'), 'F3', 'G3'),
(('Eb3', 'F3'), 'G3', 'A3'), (( 'D3', 'Ab3'), 'Eb3', 'F3'),
(( 'C3', 'Ab3'), 'E3', 'F3'))
sound = compile_song(*map(prelude_constructor, (treble, bass)))
sd.play(sound, blocking=True)
from itertools import starmap, product
from functools import lru_cache
import numpy as np
import sounddevice as sd
SAMPLE_RATE = 44100
sd.default.samplerate = SAMPLE_RATE
NOTES = ('C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B')
a = 2**(1/12)
note_to_pitch = {f'{note}{octave}': 440 * a**(12 * (int(octave) - 4) + i)
for (i, note), octave in product(enumerate(NOTES, start=-9), range(9))}
@lru_cache
def sound_array(frequency, duration, rest=.05, frequency_by_name=True):
if frequency_by_name:
frequency = note_to_pitch[frequency]
samples = np.arange(SAMPLE_RATE * duration, dtype=np.float) / SAMPLE_RATE
sound = (10000 * np.sin(2 * np.pi * frequency * samples)).astype(np.int16)
if rest:
sound[-int(SAMPLE_RATE * rest):] = 0
return sound
twinkle = [('C4', .5), ('C4', .5),
('G4', .5), ('G4', .5),
('A4', .5), ('A4', .5),
('G4', 1),
('F4', .5), ('F4', .5),
('E4', .5), ('E4', .5),
('D4', .5), ('D4', .5),
('C4', 1)]
sound = np.concatenate(tuple(starmap(sound_array, twinkle)))
sd.play(sound, blocking=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment