OpenAL 사용법 정리

by digipine posted Nov 01, 2017
?

Shortcut

PrevPrev Article

NextNext Article

ESCClose

Larger Font Smaller Font Up Down Go comment Print

OpenAL이란?

○ 게임이나 또 다른 오디오 어플리케이션을 위해 고안된 3D Audio API로 플랫폼 독립적인 라이브러리다.

○ 사용법이 그리 어렵지 않기 때문에 누구나 조금만 보면 금방 사용할 수 있다.

○ 공식 사이트 : http://connect.creativelabs.com/openal/default.aspx

 

 

 

 OpenAL 사용을 위한 사전 작업

○ OpenAL을 사용하기 위해서는 먼저 사이트로부터 oalinst.exe 를 다운받아 설치해줘야 한다.

○ oalinst.exe  다운로드 :

http://connect.creativelabs.com/openal/Downloads/Forms/AllItems.aspx

 

 

 

 

 공통된 작업

 

 생성 : OpenAL을 사용하기 위한 초기화 작업이다. 부가적인 코드는 모두 생략했다.

 

bool OpenAlInterface::Create()

{

    ALFWInit();

    if( AL_FALSE == ALFWInitOpenAL() )

    {

           ALFWShutdown();

           return false;

    }

 

    return true;

}

 

 해제 : OpenAL을 해제한다. 어플리케이션이 끝나기 전에 반드시 해줘야 한다.

 

void OpenAlInterface::Destroy()

{

    UnloadWave();  // 로드된 Wave데이터가 있다면 해제 시켜주는 함수다.

 

    ALFWShutdownOpenAL();

    ALFWShutdown();

}

 

// 로드된 Wave데이터가 있다면 해제 시켜주는 함수다.

void OpenAlInterface::UnloadWave()

{

    // Stream Data 해제

    if( m_pStreamData )

    {

           delete m_pStreamData;

           m_pStreamData = 0;

    }

 

    // Stream Play에 사용된 Wave Loader 해제

    if( m_pWaveLoader )

    {

           m_pWaveLoader->DeleteWaveFile(m_waveID);

           delete m_pWaveLoader;

           m_pWaveLoader = 0;

    }

 

    // OpenAL은 각 사운드를 ID로 관리한다.

// 하나의 Sound Data가 생성되면 그 Sound Data를 대표하는 하나의 ID가 보여되고,

// 그 ID를 통해 접근 할 수 있다.

// 현재 로드된 Sound Data가 있다면 해제한다.

    if( m_uiSourceID )

    {

           alDeleteSources(m_uiSourceSize, &m_uiSourceID);

           m_uiSourceID = 0;

           m_uiSourceSize = 1;

    }

 

    // Sound Data가 채워질 버퍼를 대표하는 ID들의 리스트를 해제한다.

    if( m_pBuffersID )

    {

           alDeleteBuffers(m_uiBufferSize, m_pBuffersID);

           delete[] m_pBuffersID;

           m_pBuffersID = 0;

           m_uiBufferSize = 1;

    }

}

 

 

 

 Static Play를 위한 작업 : Static Play에 필요한 기본적인 함수들이다.

 

// Wave 파일을 로드한다.

bool OpenAlInterface::LoadWaveStatic(std::string strFilename)

{

    m_pBuffersID = new unsigned int[m_uiBufferSize];

 

    alGenBuffers(m_uiBufferSize, m_pBuffersID);

    alGenSources(m_uiSourceSize, &m_uiSourceID);

 

    if( AL_FALSE == ALFWLoadWaveToBuffer(strFilename.c_str(), m_pBuffersID[0]) )

           return false;

 

    // Source ID의 Sound Data가 채워질 BufferID를 설정한다.

    alSourcei(m_uiSourceID, AL_BUFFER, m_pBuffersID[0]);

 

    return true;

}

 

bool OpenAlInterface::UpdateStatic()

{

    if( m_iState != AL_PLAYING )

           return false;

 

    Sleep(100);

 

    // 현재 Source의 상태를 플레이 중인지 아닌지를 얻는다.

    alGetSourcei( m_uiSourceID, AL_SOURCE_STATE, &m_iState);

 

    return true;

}

 

// 플레이 시키는 함수

void OpenAlInterface::PlayStatic()

{

    // Play Source

    alSourcePlay( m_uiSourceID );

    m_iState = AL_PLAYING;

}

 

// 스톱 시키는 함수

void OpenAlInterface::StopStatic()

{

    alSourceStop(m_uiSourceID);

    m_iState = AL_INITIAL;

}

 

 

 

 Stream Play를 위한 작업 : 다음은 Stream Play를 위한 함수들이다. 아무래도 기본적인 Static Play보다는 좀더 복잡하다.

 

bool OpenAlInterface::LoadWaveStream(std::string strFilename, unsigned int uiBufferSize)

{

    // static에서는 BufferID가 하나만 잇으면 되엇지만

    // Stream Play시는 적어도 4개 정도의 Buffer가 필요하다.

    m_uiBufferSize = uiBufferSize;

    m_pBuffersID = new unsigned int[m_uiBufferSize];

   

    alGenBuffers(m_uiBufferSize, m_pBuffersID);

    alGenSources(m_uiSourceSize, &m_uiSourceID);

 

    m_pWaveLoader = new CWaves();

   

    // WaveLoader를 통해 WaveFile을 오픈한다.

    // WaveLoader는 직접 만들어도 되고 OpenAL 샘플에서 제공하는 것을 가져다 써도 된다.

    if( WR_OK != m_pWaveLoader->OpenWaveFile(strFilename.c_str(), &m_waveID) )

           return false;

 

    // WaveLoader의 임무 중 하나는 이렇게 Wave의 정보를 얻는대 있다.

    m_pWaveLoader->GetWaveSize(m_waveID, &m_ulStreamDataSize);

    m_pWaveLoader->GetWaveFrequency(m_waveID, &m_ulStreamFrequency);

    m_pWaveLoader->GetWaveALBufferFormat(m_waveID, &alGetEnumValue, &m_ulStreamFormat);

    m_pWaveLoader->GetWaveFormatExHeader(m_waveID, &m_waveFormatEx);

 

    m_uiStreamBufferSize = m_waveFormatEx.nAvgBytesPerSec >> 2;

    m_uiStreamBufferSize -= (m_uiStreamBufferSize % m_waveFormatEx.nBlockAlign);

 

    if( 0 == m_ulStreamFormat )

           return false;

 

    m_pStreamData = malloc(m_uiStreamBufferSize);

    if( 0 == m_pStreamData )

           return false;

 

    // Audio Data의첫번째부터읽도록세팅

    m_pWaveLoader->SetWaveDataOffset(m_waveID, 0);

 

    // Buffer를audio data로채운다.

    unsigned long ulBytesWritten;

    for(int index=0 ; index<m_uiBufferSize ; ++index)

    {

           if( WR_OK == m_pWaveLoader->ReadWaveData(m_waveID, m_pStreamData, m_uiStreamBufferSize, &ulBytesWritten) )

           {

                   alBufferData(m_pBuffersID[index], m_ulStreamFormat, m_pStreamData, ulBytesWritten, m_ulStreamFrequency);

                   alSourceQueueBuffers(m_uiSourceID, 1, &m_pBuffersID[index]);

           }

    }

 

    m_bStreamPlay = false;

 

    return true;

}

 

// 다음은 매 틱마다 플레이시켜주기 위한 함수다.

bool OpenAlInterface::UpdateStream()

{

    if( false == m_bStreamPlay )

           return false;

 

    if( m_iState != AL_PLAYING )

           return false;

 

    Sleep(20);

 

    int iBuffersProcessed = 0;

    alGetSourcei(m_uiSourceID, AL_BUFFERS_PROCESSED, &iBuffersProcessed);

 

    unsigned long ulBytesWritten;

    while( iBuffersProcessed )

    {

           unsigned int uiBuffer = 0;

           alSourceUnqueueBuffers(m_uiSourceID, 1, &uiBuffer);

 

           m_pWaveLoader->ReadWaveData(m_waveID, m_pStreamData, m_uiStreamBufferSize, &ulBytesWritten);

           if( ulBytesWritten )

           {

                   alBufferData(uiBuffer, m_ulStreamFormat, m_pStreamData, ulBytesWritten, m_ulStreamFrequency);

                   alSourceQueueBuffers(m_uiSourceID, 1, &uiBuffer);

           }

 

           iBuffersProcessed--;

    }

 

    alGetSourcei(m_uiSourceID, AL_SOURCE_STATE, &m_iState);

    if( m_iState != AL_PLAYING )

    {

           int iQueuedBuffers;

           alGetSourcei(m_uiSourceID, AL_BUFFERS_QUEUED, &iQueuedBuffers);

           if( iQueuedBuffers )

           {

                   alSourcePlay(m_uiSourceID);

                   m_iState = AL_PLAYING;

           }

           else

           {

                   StopStream();

           }

    }

 

    return true;

}

 

// 플레이 시켜주는 함수.

void OpenAlInterface::PlayStream()

{

    alSourcePlay(m_uiSourceID);

 

    m_bStreamPlay = true;

    m_iState = AL_PLAYING;

}

 

// 스톱 시켜주는 함수

void OpenAlInterface::StopStream()

{

    alSourceStop(m_uiSourceID);

    alSourcei(m_uiSourceID, AL_BUFFER, 0);

 

    m_bStreamPlay = false;

    m_iState = AL_INITIAL;

}

TAG •