wav 파일의 음량을 기반으로 립싱크(Native)

업데이트: 2021/02/17

개요

Cubism SDK for Native 샘플은 립싱크 기능을 사용하여 wav 파일의 오디오 데이터 음량을 기반으로 실시간으로 립싱크를 움직이는 기능을 제공합니다.
이 샘플은 Cubism 4 SDK for Native R2 이상에서 제공됩니다.

사용 방법

준비

모션에 연결된 wav 파일을 .json 파일에 기술합니다. 각 모션의 “Sound” 키에 해당하는 wav 파일 패스를 지정하십시오.

{
	・
	・
	・
		"Motions": {
			"Idle": [
			  {"File":"motions/haru_g_idle.motion3.json" ,"FadeInTime":0.5, "FadeOutTime":0.5, "Sound": "sounds/haru_normal_05.wav"},
			  {"File":"motions/haru_g_m15.motion3.json" ,"FadeInTime":0.5, "FadeOutTime":0.5, "Sound": "sounds/haru_normal_06.wav"}
			],
			"TapBody": [
			  {"File":"motions/haru_g_m06.motion3.json" ,"FadeInTime":0.5, "FadeOutTime":0.5, "Sound": "sounds/haru_normal_01.wav"},
			  {"File":"motions/haru_g_m09.motion3.json" ,"FadeInTime":0.5, "FadeOutTime":0.5, "Sound": "sounds/haru_normal_02.wav"},
			  {"File":"motions/haru_g_m20.motion3.json" ,"FadeInTime":0.5, "FadeOutTime":0.5, "Sound": "sounds/haru_normal_03.wav"},
			  {"File":"motions/haru_g_m26.motion3.json" ,"FadeInTime":0.5, "FadeOutTime":0.5, "Sound": "sounds/haru_normal_04.wav"}
			]
		},
	・
	・
	・
}

위에서 지정한 위치에 wav 파일을 배치합니다. wav 파일의 패스가 올바르지 않으면 립싱크가 이루어지지 않습니다.

음량 취득 시작

샘플에서는 LAppWavFileHandler 클래스를 통해 wav 파일로부터의 정보 취득을 실시하고 있습니다.
LAppWavFileHandler::Start()를 실행하면 wav 파일에서 오디오 데이터를 읽고 립싱크를 수행하는 데 필요한 내부 상태를 초기화합니다.

CubismMotionQueueEntryHandle LAppModel::StartMotion(const csmChar* group, csmInt32 no, csmInt32 priority, ACubismMotion::FinishedMotionCallback onFinishedMotionHandler)
{
    ・
    ・
    ・
    //voice
    csmString voice = _modelSetting->GetMotionSoundFileName(group, no);
    if (strcmp(voice.GetRawString(), "") != 0)
    {
        csmString path = voice;
        path = _modelHomeDir + path;
        LAppPal::PrintLog("[APP]start lipsync:%s .", path.GetRawString());
        _wavFileHandler.Start(path);
    }
    ・
    ・
    ・ 
}

상태 업데이트 및 음량 취득

LAppWavFileHandler::Update()를 실행하면 경과 시간에 해당하는 부분의 음량을 측정합니다. 측정 결과의 음량은 LAppWavFileHandler::GetRms()에서 취득할 수 있습니다. 취득한 음량을 립싱크 값으로서, 모델에 CubismModel::AddParameterValue 함수로 설정합니다.

샘플에서는 취득해 온 음량을 0.8배하여 립싱크 값으로 하고 있습니다. 여기서 사운드 라이브러리 등에서 취득한 음량을 립싱크 값으로 설정할 수도 있습니다.

void LAppModel::Update()
{
    ・
    ・
    ・
    // 립싱크 설정
    if (_lipSync)
    {
        // 실시간으로 립싱크를 수행하는 경우 시스템에서 음량을 취득하여 0~1 범위의 값을 입력합니다.
        csmFloat32 value = 0.0f;

        // 상태 업데이트/RMS 값 취득
        _wavFileHandler.Update(deltaTimeSeconds);
        value = _wavFileHandler.GetRms();

        for (csmUint32 i = 0; i < _lipSyncIds.GetSize(); ++i)
        {
            _model->AddParameterValue(_lipSyncIds[i], value, 0.8f);
        }
    }
    ・
    ・
    ・
}

보충

  • 샘플에는 오디오를 장치에서 재생하는 기능이 없습니다.
  • LAppWavFileHandler::GetRms()는 현재 음량값을 0~1 범위에서 반환합니다.
    • 음량의 단위는 RMS(제곱평균제곱근)입니다.
    • 모든 채널 음성의 평균값을 계산합니다.
      • 예를 들어 스테레오 오디오의 경우 좌우 채널을 포함한 오디오의 평균값을 계산합니다.

제한사항

샘플에서는 이하의 wav 파일의 로드에 대응하고 있습니다. 하기 포맷에 대응하지 않는 파일을 읽어들일 경우 립싱크가 실행되지 않습니다.

  • Microsoft WAV(리틀 엔디안 형식)
  • 리니어 PCM
    • μ-raw, ADPCM 등으로 인코딩된 wav는 미대응입니다.
  • 채널 수: 모노/스테레오
  • 대응 비트 깊이: 8, 16, 24bit 부호 있는 정수
이 기사가 도움이 되었나요?
아니요
이 기사에 관한 의견 및 요청사항을 보내 주시기 바랍니다.