Spaces:
Runtime error
Runtime error
File size: 6,713 Bytes
360737a 24ed670 360737a 81eb7cf 360737a 81eb7cf 24ed670 6c6e316 24ed670 360737a 81eb7cf 360737a 24ed670 360737a 24ed670 77cfd66 360737a 77cfd66 360737a 77cfd66 360737a 77cfd66 360737a 77cfd66 360737a 77cfd66 360737a 6c6e316 24ed670 360737a 6c6e316 24ed670 6c6e316 360737a 24ed670 6c6e316 81eb7cf 77cfd66 24ed670 77cfd66 24ed670 77cfd66 6c6e316 24ed670 6c6e316 77cfd66 6c6e316 77cfd66 6c6e316 77cfd66 6c6e316 77cfd66 24ed670 6c6e316 77cfd66 24ed670 360737a 81eb7cf 360737a 81eb7cf 77cfd66 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
from interactive_pipe import interactive_pipeline, interactive, Control, Image
from synthetizer import NOTE_FREQUENCIES, get_note
from interactive_pipe.data_objects.audio import Audio
from pathlib import Path
from typing import Tuple
from time import sleep
import argparse
import cv2
import numpy as np
import logging
SONG_1 = "Au clair de la lune"
SONG_2 = "Ainsi font, font, font"
SONG_3 = "Dodo l'enfant do"
SONG_4 = "A la claire fontaine"
SONG = {
SONG_1: "fa fa fa sol la - sol - fa la sol sol fa - fa fa fa sol la - sol - fa la sol sol fa - - sol sol sol sol re - re - sol fa mi re do - fa fa fa sol la - sol - fa la sol sol fa",
SONG_2: "mi mi do - mi - sol - sol - la sol fa mi re mi do mi mi do - mi - sol - sol - la sol fa mi re do",
SONG_3: "mi - do - mi mi do - re mi fa mi re sol mi do - mi - do - mi mi do - re mi fa mi re sol do",
SONG_4: "fa - fa la la sol la sol - fa - fa la la sol la - la - la sol fa la do la do - do la fa la sol - fa - fa la la sol fa la fa la - la sol fa la sol fa"
}
def select_song(song: str = SONG_1, context={}):
previous_song = context.get("song", None)
if previous_song != song:
# reset time index
context["time_index"] = 0
context["song"] = song
def select_note(note="C4", context={}):
context["note"] = note
def create_note(context={}):
note = context.get("note", "C4")
audio_signal = get_note(note)
return audio_signal
def play_note(audio_signal: np.ndarray, context={}):
note = context.get("note", "C4")
file_name = Path(f"__{note}.wav")
if not file_name.exists():
Audio.save_audio(audio_signal, str(file_name), 44100)
while not file_name.exists():
sleep(0.01)
print("waiting for file")
assert file_name.exists()
try:
if context["time_index"] == 0:
context["__stop"]()
else:
context["__set_audio"](file_name)
context["__play"]()
except Exception as e:
logging.warning(
f"Error playing note {note}: {e}, not expected to work with MPL backend for instance")
def display_current_color(context={}):
if context["time_index"] == 0:
return np.zeros((256, 256, 3))
note = context.get("note", "C4")
return get_color(note, size=(256, 256))
def display_next_color(context={}):
target_note = context.get("target_note", None)
if target_note is None:
return np.zeros((256, 256, 3))
return get_color(target_note, size=(256, 256))
NOTES_TRANSLATION = ["do", "re", "mi", "fa", "sol", "la", "si", "do2"]
NOTES_CORRESPONDANCE = {
NOTES_TRANSLATION[i]: note for i, note in enumerate(list(NOTE_FREQUENCIES.keys()))}
def get_color(note, size=(256, 256)):
colors = {
"red": (1.0, 0.0, 0.0),
"orange": (1.0, 0.65, 0.0),
"yellow": (0.9, 0.9, 0.0),
"green": (0.0, 0.5, 0.0),
"cyan": (0.0, 0.7, 1.0),
"dark blue": (0.0, 0.0, 0.7),
"purple": (0.5, 0.0, 0.5),
"pink": (1.0, 0.75, 0.8),
}
index = list(NOTE_FREQUENCIES.keys()).index(note)
color = colors.get(list(colors.keys())[index], [0., 0., 0.])
img = np.ones((size[1], size[0], 3)) * np.array(color)[None, None, :]
text = NOTES_TRANSLATION[index].upper()
font_scale = size[0] // 64
thickness = 2
text_size = cv2.getTextSize(
text, cv2.FONT_HERSHEY_SIMPLEX, font_scale, thickness)[0]
text_x = (size[0] - text_size[0]) // 2
text_y = (size[1] + text_size[1]) // 2
cv2.putText(
img,
text,
(text_x, text_y),
cv2.FONT_HERSHEY_SIMPLEX, font_scale, (255, 255, 255), thickness
)
return img
def add_border(img, border_size=10, color=(0.2, 0.2, 0.2)):
border_size = 4
img[:border_size, :] = color
img[-border_size:, :] = color
img[:, :border_size] = color
img[:, -border_size:] = color
def increment_time(context: dict = {}) -> None:
time_index = context.get("time_index", None)
if time_index is not None:
context["time_index"] += 1
else:
context["time_index"] = 0
def xylo_player():
select_song()
select_note()
full_song = song_player()
audio = create_note()
play_note(audio)
# current_note = display_current_color()
target_note = display_next_color()
increment_time()
return [full_song, target_note]
def song_player(context={}):
song = context["song"]
song_str = SONG.get(song, "")
image_song, target_note = generate_song(
song_str, current_time=context.get("time_index", 0))
context["target_note"] = target_note
return image_song
def generate_song(song_str, current_time=None) -> Tuple[np.ndarray, str]:
notes = song_str.split(" ")
all_notes = []
size = (64, 128)
index_no_silence = -1
target_note = None
for idx, note in enumerate(notes):
if note in ["-", "."]:
img_note = np.zeros((size[1], size[0], 3))
color = (0.2, 0.2, 0.2)
else:
note_classic = NOTES_CORRESPONDANCE.get(note, None)
index_no_silence += 1
if note_classic is None:
print(f"Note {note} not found")
continue
img_note = get_color(note_classic, size=size)
if current_time == index_no_silence:
target_note = note_classic
color = (0.8, 0., 0.)
else:
color = (0.2, 0.2, 0.2)
add_border(img_note, color=color)
all_notes.append(img_note)
max_notes_per_line = 12
remainder = max_notes_per_line - len(all_notes) % max_notes_per_line
for _ in range(remainder):
all_notes.append(np.zeros_like(all_notes[0]))
note_lines = [all_notes[i:i + max_notes_per_line]
for i in range(0, len(all_notes), max_notes_per_line)]
out_image = np.vstack([np.hstack(line) for line in note_lines])
return out_image, target_note
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Xylophone synthesizer')
parser.add_argument('-b', '--backend', type=str,
default='gradio', choices=['gradio', 'qt', 'mpl'])
args = parser.parse_args()
all_notes = list(NOTE_FREQUENCIES.keys())
icon_list = [Path(f"__{note}.jpg") for note in all_notes]
for note, icon in zip(all_notes, icon_list):
img = get_color(note, size=(512, 512))
Image.save_image(img, icon)
interactive(note=Control("C4", all_notes, icons=icon_list))(select_note)
interactive(song=(SONG_1, list(SONG.keys())))(select_song)
interactive_pipeline(
gui=args.backend,
cache=False,
audio=True
)(xylo_player)()
|