import gradio as gr import math import tempfile import os # notes.py 내용을 직접 포함 A4_INDEX = 48 TOTAL_KEYS = 88 NOTE_NAMES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'] ENHARMONIC_EQUIVS = { 'C#': 'Db', 'D#': 'Eb', 'F#': 'Gb', 'G#': 'Ab', 'A#': 'Bb', 'Db': 'C#', 'Eb': 'D#', 'Gb': 'F#', 'Ab': 'G#', 'Bb': 'A#', 'Cb': 'B', 'B#': 'C', 'E#': 'F', 'Fb': 'E', } # 주파수 딕셔너리 생성 freqs = {} for i in range(TOTAL_KEYS): n = i - A4_INDEX freq = 440 * (2 ** (n / 12)) freq = round(freq, 2) note_index = (i + 9) % 12 octave = (i + 9) // 12 note = NOTE_NAMES[note_index] note_name = f"{note}{octave}" freqs[note_name] = freq if note in ENHARMONIC_EQUIVS: enharmonic = ENHARMONIC_EQUIVS[note] enharmonic_name = f"{enharmonic}{octave}" freqs[enharmonic_name] = freq special_equivs = { 'Cb': 'B', 'B#': 'C', 'Fb': 'E', 'E#': 'F', } for key in list(freqs.keys()): note = key[:-1] octave = int(key[-1]) if note in special_equivs: mapped_note = special_equivs[note] if note == 'Cb': mapped_octave = octave - 1 elif note == 'B#': mapped_octave = octave + 1 else: mapped_octave = octave mapped_key = f"{mapped_note}{mapped_octave}" if mapped_key in freqs: freqs[key] = freqs[mapped_key] def convert_music_to_arduino(text_input): """텍스트 입력을 받아 Arduino 코드로 변환하고 파일을 생성""" try: if not text_input.strip(): return "입력이 비어있습니다.", None lines = text_input.strip().split('\n') lines = [line.split() for line in lines if line.strip()] lines = [x for x in lines if x] if len(lines) < 3: return "최소 3줄의 설정이 필요합니다 (PIN, REPEAT, BPM).", None PIN = lines[0][1] REPEAT = lines[1][1] == 'TRUE' BPM = lines[2][1] SPB = 60 / float(BPM) arduino_code = "" if REPEAT: arduino_code += 'void setup() {\n' arduino_code += f' pinMode({PIN}, OUTPUT);\n' arduino_code += ' Serial.begin(9600);\n' arduino_code += '}\n' arduino_code += 'void loop() {\n' else: arduino_code += 'void setup() {\n' arduino_code += f' pinMode({PIN}, OUTPUT);\n' arduino_code += f' Serial.begin(9600);\n' for line in lines[3:]: if len(line) < 2: continue note = line[0] duration = SPB * float(line[1]) * 1000 # Convert to milliseconds if note in freqs: freq = freqs[note] arduino_code += f' tone({PIN}, {freq}, {duration});\n' elif note == 'W': arduino_code += f' delay({int(duration)});\n' elif note == 'BPM': # set new BPM BPM = float(line[1]) SPB = 60 / float(BPM) if REPEAT: arduino_code += '}\n' else: arduino_code += '}\n' arduino_code += 'void loop() {}\n' # 임시 파일 생성 temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.ino', delete=False) temp_file.write(arduino_code) temp_file.close() return arduino_code, temp_file.name except Exception as e: return f"오류 발생: {str(e)}", None # Gradio 인터페이스 구성 with gr.Blocks(title="이우진의 아두이노 작곡 웹사이트", theme=gr.themes.Soft()) as demo: with gr.Row(): # 왼쪽: 입력 with gr.Column(): text_input = gr.Textbox( label="음악 데이터", placeholder="PIN 13\nREPEAT TRUE\nBPM 120\nC4 1\nD4 1\nE4 1", lines=8, max_lines=8 ) with gr.Row(): example1_btn = gr.Button("도레미파", size="sm") example2_btn = gr.Button("생일축하", size="sm") example3_btn = gr.Button("비프음", size="sm") convert_btn = gr.Button("변환하기", variant="primary", size="lg") # 오른쪽: 결과 with gr.Column(): output_text = gr.Code( label="Arduino 코드", language="cpp", lines=8 ) download_file = gr.File( label="다운로드", interactive=False ) # 하단: 사용법 with gr.Accordion("사용법", open=False): gr.Markdown(""" **입력 형식:** ``` PIN 13 ← Arduino 핀 번호 REPEAT TRUE ← 반복 재생 여부 (TRUE/FALSE) BPM 120 ← 분당 비트 수 C4 1 ← 노트명 지속시간 D4 1 E4 1 W 0.5 ← W는 무음(쉼표) ``` """) # 이벤트 처리 convert_btn.click( fn=convert_music_to_arduino, inputs=[text_input], outputs=[output_text, download_file] ) # 예시 버튼 이벤트 def load_example1(): return """PIN 13 REPEAT TRUE BPM 120 C4 1 D4 1 E4 1 F4 1 G4 1 A4 1 B4 1 C5 1""" def load_example2(): return """PIN 13 REPEAT FALSE BPM 140 C4 0.5 C4 0.5 D4 1 C4 1 F4 1 E4 2""" def load_example3(): return """PIN 13 REPEAT TRUE BPM 200 C6 0.25 W 0.25 C6 0.25 W 0.25""" example1_btn.click(fn=load_example1, outputs=[text_input]) example2_btn.click(fn=load_example2, outputs=[text_input]) example3_btn.click(fn=load_example3, outputs=[text_input]) if __name__ == "__main__": demo.launch()