# 사운드 로고 스튜디오 > **작성일**: 2026-03-08 > **상태**: 운영 중 > **라우트**: `/rd/sound-logo` > **뷰**: `resources/views/rd/sound-logo/index.blade.php` --- ## 1. 개요 사운드 로고 스튜디오는 기업 시그니처 사운드(사운드 로고)를 제작하는 올인원 도구이다. Web Audio API 기반 시퀀서, Gemini AI 어시스트, TTS 음성 오버레이, Lyria RealTime BGM 생성을 하나의 SPA에서 통합 제공한다. **핵심 기능:** - 시퀀서 기반 사운드 로고 수동/프리셋 제작 - Gemini AI가 프롬프트 기반으로 음표 시퀀스 자동 설계 - Gemini TTS로 나레이션 음성 생성 (여성/남성/아이, 30종 음성, 속도 조절) - Lyria RealTime WebSocket으로 AI 배경음악 실시간 생성 - 시퀀서/BGM 상호 배타적 재생 + TTS 공통 합성 - WAV 내보내기 --- ## 2. 아키텍처 ### 2.1 3레이어 오디오 구조 ``` ┌─────────────────────────────────────────────────────────┐ │ Layer 1: 사운드 로고 (시퀀서 또는 AI BGM — 상호 배타적) │ │ ├── A) 시퀀서 (수동 편집 / 프리셋 / AI 생성) │ │ └── B) AI 배경음악 (Lyria RealTime) │ ├─────────────────────────────────────────────────────────┤ │ Layer 2: 음성 TTS (Gemini) ─── 양쪽 모드 공통 │ ├─────────────────────────────────────────────────────────┤ │ DynamicsCompressor (클리핑 방지) → AudioContext.dest │ └─────────────────────────────────────────────────────────┘ ``` - **시퀀서 모드**: 수동/프리셋/AI 생성 음표 + TTS 합성. BGM 제외. - **BGM 모드**: AI 배경음악 + TTS 합성. 시퀀서 음표 제외. - 판단 기준: `bgmBuffer` 존재 여부 ### 2.2 기술 스택 | 계층 | 기술 | 설명 | |------|------|------| | 프론트엔드 | Blade + Alpine.js | 단일 SPA | | 오디오 엔진 | Web Audio API | OscillatorNode, BufferSourceNode, DynamicsCompressorNode | | AI 시퀀서 | Gemini 2.5 Flash | 프롬프트 → JSON 음표 시퀀스 | | TTS | `gemini-2.5-flash-preview-tts` | 30종 음성, Director's Note 스타일 제어 | | BGM | Lyria RealTime (WebSocket) | `models/lyria-realtime-exp`, 48kHz 스테레오 PCM | | 저장 | 없음 (클라이언트 전용) | WAV 내보내기로 결과물 보존 | --- ## 3. 시퀀서 (Layer 1-A) ### 3.1 입력 모드 | 모드 | 설명 | |------|------| | **수동** | 음표 그리드에서 직접 추가/삭제/편집 | | **프리셋** | 사전 정의된 사운드 패턴 선택 (기업 시그널, 알림음 등) | | **AI 생성** | 프롬프트 입력 → Gemini가 음표 시퀀스 JSON 반환 | ### 3.2 음표 데이터 구조 ```json { "type": "note | chord | rest", "note": "C5", "chord": ["C4", "E4", "G4"], "duration": 0.2, "velocity": 0.8 } ``` ### 3.3 신디사이저 설정 | 파라미터 | 범위 | 설명 | |---------|------|------| | `synth` | sine, triangle, square, sawtooth | 파형 | | `volume` | 0~1 | 마스터 볼륨 | | `adsr.attack` | 1~500ms | 어택 | | `adsr.decay` | 10~1000ms | 디케이 | | `adsr.sustain` | 0~1.0 | 서스테인 | | `adsr.release` | 10~3000ms | 릴리즈 | | `reverb` | 0~1 | 리버브 양 | --- ## 4. 음성 오버레이 — TTS (Layer 2) ### 4.1 음성 카테고리 | 카테고리 | 음성 수 | 주요 음성 | |---------|---------|----------| | **여성** | 9종 | Kore(단정), Aoede(산뜻), Leda(따뜻), Zephyr(차분) 등 | | **남성** | 9종 | Puck(밝음), Charon(깊음), Orus(안정), Fenrir(무게) 등 | | **아이** | 5종 | Leda 기반(여아), Puck 기반(남아) 등 | ### 4.2 속도 조절 | 단계 | Director's Note | |------|----------------| | 1 (매우 느림) | "아주 천천히 또박또박 말해주세요." | | 2 (느림) | "조금 느린 속도로 말해주세요." | | 3 (보통) | (지시문 없음) | | 4 (빠름) | "조금 빠른 속도로 말해주세요." | | 5 (매우 빠름) | "아주 빠른 속도로 말해주세요." | ### 4.3 오디오 형식 - 출력: `audio/L16;rate=24000` (16-bit PCM, 24kHz, 모노, little-endian) - 디코딩: `DataView.getInt16(offset, true)` → Float32 변환 --- ## 5. AI 배경음악 — Lyria (Layer 1-B) ### 5.1 WebSocket 프로토콜 ``` 브라우저 ──WebSocket──→ Google Lyria RealTime API (wss://generativelanguage.googleapis.com/ws/...BidiGenerateMusic) ``` 서버는 API 키만 전달(`GET /lyria-config`), 실제 WebSocket 통신은 브라우저에서 직접 수행한다. ### 5.2 메시지 흐름 ``` 1. setup → { setup: { model: "models/lyria-realtime-exp" } } 2. (수신) ← { setupComplete: {} } 3. 프롬프트 → { clientContent: { weightedPrompts: [...] } } 4. 설정 → { musicGenerationConfig: { bpm, density, brightness, scale, temperature } } 5. 재생 → { playbackControl: "PLAY" } 6. (수신 반복) ← { serverContent: { audioChunks: [{ data: "base64..." }] } } 7. 정지 → { playbackControl: "STOP" } 8. (종료) ← WebSocket close ``` ### 5.3 BGM 파라미터 | 파라미터 | 범위 | 설명 | |---------|------|------| | `bgmPrompt` | 텍스트 | 음악 분위기 설명 | | `bgmBpm` | 60~180 | BPM | | `bgmDensity` | 0~100 | 밀도 (0~1 변환) | | `bgmBrightness` | 0~100 | 밝기 (0~1 변환) | | `bgmScale` | C_MAJOR 등 | 음계 | | `bgmDuration` | 5~60초 | 생성 길이 | ### 5.4 오디오 형식 - 출력: 16-bit PCM, 48kHz, 스테레오, little-endian - WAV 헤더 감지 시 `decodeAudioData` fallback --- ## 6. API 엔드포인트 ### 6.1 사운드 로고 (RdController) | HTTP | URI | 메서드 | 설명 | |------|-----|--------|------| | GET | `/rd/sound-logo` | `soundLogo()` | 스튜디오 페이지 | | POST | `/rd/sound-logo/generate` | `soundLogoGenerate()` | AI 음표 시퀀스 생성 (Gemini) | | POST | `/rd/sound-logo/tts` | `soundLogoTts()` | TTS 음성 생성 (Gemini TTS) | | GET | `/rd/sound-logo/lyria-config` | `soundLogoLyriaConfig()` | Lyria WebSocket 접속 설정 반환 | ### 6.2 CM송/나레이션 (CmSongController) | HTTP | URI | 메서드 | 설명 | |------|-----|--------|------| | GET | `/rd/cm-song` | `index()` | 나레이션 목록 | | GET | `/rd/cm-song/create` | `create()` | 나레이션 제작 | | POST | `/rd/cm-song` | `store()` | 나레이션 저장 | | GET | `/rd/cm-song/{id}` | `show()` | 나레이션 상세 | | DELETE | `/rd/cm-song/{id}` | `destroy()` | 나레이션 삭제 | | GET | `/rd/cm-song/{id}/download` | `download()` | 음성 파일 다운로드 | | POST | `/rd/cm-song/generate-lyrics` | `generateLyrics()` | AI 가사 생성 (Gemini) | | POST | `/rd/cm-song/generate-audio` | `generateAudio()` | TTS 음성 생성 | ### 6.3 CM송 데이터 모델 | 모델 | 테이블 | 설명 | |------|--------|------| | `CmSong` | `cm_songs` | 나레이션 (회사명, 업종, 가사, 음성파일) | **저장 경로**: `tenant` 디스크 → `cm-songs/{tenant_id}/{filename}.wav` --- ## 7. 오디오 엔진 상세 ### 7.1 마스터 출력 체인 ``` 각 소스 (Oscillator / BufferSource) → GainNode (개별 볼륨) → DynamicsCompressorNode (마스터 리미터) → AudioContext.destination ``` **컴프레서 설정:** - threshold: -6dB - knee: 10dB - ratio: 12:1 - attack: 3ms - release: 150ms ### 7.2 WAV 내보내기 `OfflineAudioContext`로 오프라인 렌더링 후 `bufferToWav()` 변환. - 샘플레이트: 44,100Hz - 채널: 2 (스테레오) - 비트: 16-bit PCM - 오프라인 컨텍스트에도 동일한 DynamicsCompressor 적용 --- ## 8. 관련 파일 | 파일 | 설명 | |------|------| | `resources/views/rd/sound-logo/index.blade.php` | SPA 뷰 (Alpine.js, ~2100줄) | | `app/Http/Controllers/RdController.php` | 사운드 로고 API (4 메서드) | | `app/Http/Controllers/Rd/CmSongController.php` | CM송/나레이션 CRUD (8 메서드) | | `app/Models/Rd/CmSong.php` | CM송 모델 | | `app/Helpers/AiTokenHelper.php` | Gemini 토큰 사용량 추적 | --- ## 관련 문서 - [R&D 메뉴 개요](README.md) — R&D 전체 메뉴 구조 - [AI 분석 리포트](../ai/README.md) — Gemini API 활용 패턴 참고 - [사운드 로고 생성기 기획서](../../plans/sound-logo-generator-plan.md) — 초기 기획 --- **최종 업데이트**: 2026-03-08