fix: [sound-logo] Lyria WebSocket 메시지 키 형식 수정
- client_content → clientContent (camelCase) - music_generation_config 중첩 제거 → musicGenerationConfig 최상위 - playback_control 중첩 제거 → playbackControl 최상위 - WAV 헤더 감지 시 decodeAudioData fallback 추가
This commit is contained in:
@@ -1836,25 +1836,23 @@ function soundLogo() {
|
|||||||
this.bgmProgress = '프롬프트 설정 중...';
|
this.bgmProgress = '프롬프트 설정 중...';
|
||||||
|
|
||||||
ws.send(JSON.stringify({
|
ws.send(JSON.stringify({
|
||||||
client_content: {
|
clientContent: {
|
||||||
weightedPrompts: [{ text: this.bgmPrompt, weight: 1.0 }]
|
weightedPrompts: [{ text: this.bgmPrompt, weight: 1.0 }]
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
ws.send(JSON.stringify({
|
ws.send(JSON.stringify({
|
||||||
music_generation_config: {
|
musicGenerationConfig: {
|
||||||
musicGenerationConfig: {
|
bpm: this.bgmBpm,
|
||||||
bpm: this.bgmBpm,
|
density: this.bgmDensity / 100,
|
||||||
density: this.bgmDensity / 100,
|
brightness: this.bgmBrightness / 100,
|
||||||
brightness: this.bgmBrightness / 100,
|
scale: this.bgmScale,
|
||||||
scale: this.bgmScale,
|
temperature: 1.0,
|
||||||
temperature: 1.0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
ws.send(JSON.stringify({
|
ws.send(JSON.stringify({
|
||||||
playback_control: { playbackControl: 'PLAY' }
|
playbackControl: 'PLAY'
|
||||||
}));
|
}));
|
||||||
playStartTime = Date.now();
|
playStartTime = Date.now();
|
||||||
this.bgmProgress = '음악 생성 중... 0/' + duration + '초';
|
this.bgmProgress = '음악 생성 중... 0/' + duration + '초';
|
||||||
@@ -1920,7 +1918,7 @@ function soundLogo() {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (ws.readyState === WebSocket.OPEN) {
|
if (ws.readyState === WebSocket.OPEN) {
|
||||||
ws.send(JSON.stringify({
|
ws.send(JSON.stringify({
|
||||||
playback_control: { playbackControl: 'STOP' }
|
playbackControl: 'STOP'
|
||||||
}));
|
}));
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (ws.readyState === WebSocket.OPEN) ws.close();
|
if (ws.readyState === WebSocket.OPEN) ws.close();
|
||||||
@@ -1937,7 +1935,8 @@ function soundLogo() {
|
|||||||
|
|
||||||
async decodeBgmChunks(chunks) {
|
async decodeBgmChunks(chunks) {
|
||||||
try {
|
try {
|
||||||
// base64 청크들을 합쳐서 하나의 PCM 데이터로 변환
|
console.log('[Lyria] 오디오 디코딩 시작: ' + chunks.length + '개 청크');
|
||||||
|
// base64 청크들을 합쳐서 하나의 바이트 배열로 변환
|
||||||
const allBytes = [];
|
const allBytes = [];
|
||||||
for (const chunk of chunks) {
|
for (const chunk of chunks) {
|
||||||
const binaryStr = atob(chunk);
|
const binaryStr = atob(chunk);
|
||||||
@@ -1946,8 +1945,28 @@ function soundLogo() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const pcmData = new Uint8Array(allBytes);
|
const pcmData = new Uint8Array(allBytes);
|
||||||
|
console.log('[Lyria] 전체 PCM 크기:', pcmData.length, 'bytes');
|
||||||
|
|
||||||
// Lyria RealTime: 16-bit PCM, stereo, 48kHz (little-endian)
|
if (pcmData.length < 4) {
|
||||||
|
this.bgmError = '유효한 오디오 데이터가 없습니다.';
|
||||||
|
this.bgmLoading = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = this.getAudioCtx();
|
||||||
|
|
||||||
|
// WAV 헤더 감지 (RIFF 매직넘버) → decodeAudioData 사용
|
||||||
|
const hasWavHeader = pcmData[0] === 0x52 && pcmData[1] === 0x49 && pcmData[2] === 0x46 && pcmData[3] === 0x46;
|
||||||
|
if (hasWavHeader) {
|
||||||
|
console.log('[Lyria] WAV 헤더 감지, decodeAudioData 사용');
|
||||||
|
const buffer = await ctx.decodeAudioData(pcmData.buffer.slice(0));
|
||||||
|
this.bgmBuffer = buffer;
|
||||||
|
this.toast('배경음악 생성 완료 (' + buffer.duration.toFixed(1) + '초)');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw PCM: Lyria RealTime — 16-bit PCM, stereo, 48kHz (little-endian)
|
||||||
|
console.log('[Lyria] Raw PCM 디코딩: 48kHz, stereo, 16-bit LE');
|
||||||
const sampleRate = 48000;
|
const sampleRate = 48000;
|
||||||
const numChannels = 2;
|
const numChannels = 2;
|
||||||
const bytesPerSample = 2;
|
const bytesPerSample = 2;
|
||||||
@@ -1959,7 +1978,6 @@ function soundLogo() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ctx = this.getAudioCtx();
|
|
||||||
const buffer = ctx.createBuffer(numChannels, numSamples, sampleRate);
|
const buffer = ctx.createBuffer(numChannels, numSamples, sampleRate);
|
||||||
const view = new DataView(pcmData.buffer);
|
const view = new DataView(pcmData.buffer);
|
||||||
|
|
||||||
@@ -1968,7 +1986,7 @@ function soundLogo() {
|
|||||||
for (let i = 0; i < numSamples; i++) {
|
for (let i = 0; i < numSamples; i++) {
|
||||||
const byteOffset = (i * numChannels + ch) * bytesPerSample;
|
const byteOffset = (i * numChannels + ch) * bytesPerSample;
|
||||||
if (byteOffset + 1 < pcmData.length) {
|
if (byteOffset + 1 < pcmData.length) {
|
||||||
channelData[i] = view.getInt16(byteOffset, true) / 32768; // little-endian
|
channelData[i] = view.getInt16(byteOffset, true) / 32768;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1976,6 +1994,7 @@ function soundLogo() {
|
|||||||
this.bgmBuffer = buffer;
|
this.bgmBuffer = buffer;
|
||||||
this.toast('배경음악 생성 완료 (' + buffer.duration.toFixed(1) + '초)');
|
this.toast('배경음악 생성 완료 (' + buffer.duration.toFixed(1) + '초)');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.error('[Lyria] 오디오 디코딩 실패:', e);
|
||||||
this.bgmError = '오디오 디코딩 실패: ' + e.message;
|
this.bgmError = '오디오 디코딩 실패: ' + e.message;
|
||||||
this.toast('배경음악 오디오 처리에 실패했습니다.', 'error');
|
this.toast('배경음악 오디오 처리에 실패했습니다.', 'error');
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user