Share via


에코 효과 만들기

[이 페이지와 연결된 기능인 Windows 미디어 플레이어 SDK는 레거시 기능입니다. MediaPlayer로 대체되었습니다. MediaPlayer는 Windows 10 및 Windows 11 최적화되었습니다. 가능한 경우 새 코드에서 Windows 미디어 플레이어 SDK 대신 MediaPlayer를 사용하는 것이 좋습니다. 가능한 경우 레거시 API를 사용하는 기존 코드를 다시 작성하여 새 API를 사용하도록 제안합니다.]

먼저 오디오 크기를 조정하는 마법사 샘플에서 코드를 제거해야 합니다. 8비트 섹션에서 다음 코드를 제거합니다.

// Apply scale factor to sample.
i = int( ((double) i) * m_dwDelayTime );

(m_fScaleFactor m_dwDelayTime 대체되었습니다.)

16비트 섹션에서 다음 코드를 제거합니다.

// Apply scale factor to sample.
i = int( ((double) i) * m_dwDelayTime );

플러그 인 마법사 샘플 코드에서 제공하는 DoProcessOutput 구현은 Windows 미디어 플레이어 제공된 입력 버퍼의 각 샘플에 대해 한 번 반복하는 while 루프를 만듭니다. 이 루프는 각각에 대해 별도의 루프가 필요하지만 8비트 및 16비트 오디오 모두에 대해 동일한 방식으로 작동합니다. 각 경우에 루프는 다음 테스트를 시작합니다.

while (dwSamplesToProcess--)

루프 내에서 처리 루틴은 8비트 및 16비트 오디오와 매우 유사합니다. 기본 차이점은 8비트 섹션의 코드가 데이터 값 범위를 -128에서 127로 변경한 다음, 데이터를 출력 버퍼에 쓰기 전에 범위를 다시 변환한다는 것입니다. 처리 중에 오디오 파형의 대칭을 유지하는 것이 중요합니다.

이제 처리 루프에서 코드를 추가하고 바꿀 수 있습니다.

입력 버퍼에서 샘플 검색

루프를 반복할 때마다 입력 버퍼에서 단일 샘플이 검색됩니다. 8비트 오디오의 경우 샘플이 새 범위로 이동된 다음 입력 버퍼에 대한 포인터가 다음 샘플로 진행됩니다. 다음 코드는 플러그 인 마법사의 코드입니다.

// Get the input sample and normalize to -128 .. 127
int i = (*pbInputData++) - 128;

16비트 오디오의 경우 정규화를 제외하고 프로세스는 동일합니다.

// Get the input sample.
int i = *pwInputData++;

16비트 코드의 포인터가 short 형식으로 변환되었습니다.

지연 버퍼에서 샘플 검색

다음으로, 지연 버퍼에서 단일 샘플을 검색합니다. 8비트 코드의 경우 지연 샘플은 기본 범위인 0~255에 저장됩니다. 추가해야 하는 다음 코드는 8비트 지연 샘플을 검색합니다.

// Get the delay sample and normalize to -128 .. 127
int delay = m_pbDelayPointer[0] - 128;

16비트 오디오의 경우 프로세스는 비슷합니다.

// Get the delay sample.
int delay = *pwDelayPointer;

지연 버퍼에 입력 샘플 작성

이제 지연 샘플을 검색한 동일한 위치에 있는 지연 버퍼에 입력 샘플을 저장해야 합니다. 다음은 8비트 오디오에 대해 추가해야 하는 코드입니다.

// Write the input sample into the delay buffer.
m_pbDelayPointer[0] = i + 128;

16비트 섹션에 추가할 코드입니다.

// Write the input sample to the delay buffer.
*pwDelayPointer = i;

지연 버퍼 포인터 이동

이 반복을 위해 지연 버퍼의 작업이 완료되었으므로 이동 가능한 포인터를 지연 버퍼로 진행할 수 있습니다. 포인터가 순환 버퍼의 끝에 도달하면 버퍼의 헤드를 가리키도록 값을 변경해야 합니다. 8비트 오디오에 대해 이 작업을 수행하려면 다음 코드를 사용합니다.

// Increment the delay pointer.
// If it has passed the end of the buffer,
// then move it to the head of the buffer.
if (++m_pbDelayPointer > pbEOFDelayBuffer)
    m_pbDelayPointer = m_pbDelayBuffer;

다음은 16비트 섹션에 대한 코드입니다.

// Increment the local delay pointer.
// If it is past the end of the buffer,
// then move it to the head of the buffer.
if (++pwDelayPointer > pwEOFDelayBuffer)
    pwDelayPointer = pwDelayBuffer;

16비트 섹션의 포인터는 실제로 멤버 변수의 복사본이므로 멤버 변수의 값을 새 주소로 업데이트해야 합니다. 이 작업을 수행하지 못하면 지연 버퍼 포인터가 버퍼의 헤드를 반복적으로 가리키고 에코 효과가 예상대로 작동하지 않습니다. 16비트 섹션에 다음 코드를 추가합니다.

// Move the global delay pointer.
m_pbDelayPointer = (BYTE *) pwDelayPointer;

입력 샘플을 지연 샘플과 혼합

여기서 습식 혼합 및 드라이 믹스 값을 사용하여 최종 출력 샘플을 만듭니다. 각 샘플을 샘플에 대한 최종 신호의 백분율을 나타내는 부동 소수점 값을 곱하기만 하면 됩니다. 입력 샘플을 m_fDryMix 저장된 값으로 곱합니다. 지연 샘플을 m_fWetMix 저장된 값과 곱합니다. 그런 다음, 두 값을 추가합니다. 추가해야 하는 코드는 8비트 및 16비트 섹션에 대해 동일합니다.

// Mix the delay with the dry signal.
i = (int)((i * m_fDryMix ) + (delay * m_fWetMix));   

출력 버퍼에 데이터 쓰기

마지막으로 혼합 샘플을 출력 버퍼에 복사한 다음 출력 버퍼 포인터를 진행합니다. 8비트 오디오의 경우 플러그 인 마법사는 다음 코드를 사용하여 샘플을 원래 범위로 반환합니다.

// Convert back to 0..255 and write to output buffer.
*pbOutputData++ = (BYTE)(i + 128);

16비트 오디오의 경우 마법사는 다음 코드를 처리 루프의 마지막 단계로 사용합니다.

// Write to output buffer.
*pwOutputData++ = i;

CEcho::D oProcessOutput 구현