*** 공부 방법 ***
1. 코딩을 해야 하는 부분은 첫 부분에 변수나 함수, 메소드에 대한 선언이 코드블럭으로 표시되어 있다. //ex) MakeFunction(); 2. 코드블럭 하단에는 해당 선언에 대한 구현 로직이 작성되어 있다. 처
hyrule.tistory.com
- 사운드 시스템은, WIN32API에서 기본으로 지원하는 시스템을 사용할 수 있다. 다만 wav 파일만 재생할 수 있어 효율성이 떨어진다.
그러므로, 외부 사운드 라이브러리를 링크하여 사용하는게 더 낫다.
- 외부 사운드 라이브러리인 FMOD를 사용하여 사운드를 출력해보자.
다운로드는 여기서 받을 수 있다.
FMOD
The sonic universe of Creaks We talked to the creative team responsible for the audio of Creaks, the latest game from renowned Czech game developer, Amanita Design. Visit blog
www.fmod.com
- 자세한 설명은 여기서 볼 수 있다.
https://documentation.help/FMOD-API/lowlevel_introduction.html
FMOD Low Level API - An Overview - FMOD Low Level API Documentation
documentation.help
- 위에서 FMOD Engine을 받아서 설치하고,
설치된 주소의 FMOD Studio API Windows\api\core로 들어가서
- bin 폴더 안에 있는 Bin/ 안에 넣어 주고,
inc 폴더 안의 파일들은 Include/ 안에 넣어 준다.
GameInfo.h
- 여기서 이미지 출력 라이브러리를 링크했던 것과 동일한 방법으로 링크를 해 준다.
- "fmod.hpp"를 포함시켜 준다.
- 이제 사운드 리소스로의 접근도 해야 하므로,
"SoundPath"를 SOUND_PATH로 정의해 주자.
- 앞으로 사운드 리소스는 Bin/Sound 폴더 안에 저장한다.
class CSoundManager;
- 사운드 소스코드는 Include/Resource/Sound/ 안에 저장한다.
- 기본적인 구조는 텍스처와 비슷하다.
-- CResourceManager에서 CSoundManager를 하나 생성하여 관리.
-- CSoundManager에서는 개별 CSound를 unordered_map을 통해 관리.
-- CSound는 CRef를 상속받아 참조 포인터를 사용
{ FMOD::System* m_System }
- 사운드를 로딩하는 과정은, FMOD에서 담당할 것이다 -> FMOD에서 정한 순서대로 사운드 리소스를 로딩해주어야 한다.
{ FMOD::ChannelGroup* m_MasterGroup }
- 윈도우의 '볼륨 믹서' 기능을 보면 알 수 있듯이, 소리 재생에는 여러 개의 채널이 존재한다.
- FMOD도 똑같이, 각각 채널을 지정할 수 있고, 채널별로 음량을 올리거나 줄일 수도 있으며, 마스터 볼륨을 통해 일괄적으로 조정할 수도 있다.
- 마스터 그룹으로 사용할 ChannelGroup 변수를 하나 생성해준다.
{ m_mapChannelGroup }
- 나머지 채널 그룹은, unordered_map으로 만들어 여러 그룹을 관리할 수 있도록 해준다.
- key = 문자열 이름, value = ChannelGroup 포인터
< ~SoundManager() >
- FMOD::ChannelGroup은 내부에 아예 자신의 메모리 할당을 해제하는 release()라는 메소드가 존재한다. 마스터그룹과 하위 그룹의 메모리 할당을 소멸자에서 반드시 제거해 주어야 한다.
- FMOD::System도 close() 를 통해 시스템을 닫아 주고, release()로 메모리 할당을 해제해 주어야 한다. 채널 그룹이 먼저 제거되어야 꼬이지 않음을 명심하자.
< Init() >
{ FMOD_RESULT result }
- 변수는 FMOD에 존재하는 메소드들의 성공/실패 여부, 실패 시 어떤 이유로 실패했는지등 에러 넘버를 반환한다.
- 성공 시 FMOD_OK라는 값이 반환되므로, 만약 이 값이 반환되지 않았다면 return false 해준다.
< FMOD::System_Create(&m_System) >
- 함수는 시스템을 생성하고, 성공/실패 여부를 FMOD_RESULT 타입의 변수에 담아 반환한다.
< result = m_System->init(256, FMOD_INIT_NORMAL, nullptr); >
- 시스템 생성 성공 시, m_System 내부의 메소드 init()을 실행시켜 초기화를 진행한다.
-1번 인자: 사운드 채널의 갯수
-2번 인자: FMOD 로딩 형태(여러가지 로딩 형태가 있음. F12 눌러서 확인해볼 것.)
-3번 인자: extra driver data -> 외부 플러그인의 메모리 주소를 말하는 듯. nullptr 입력.
< result = m_System->getMasterChannelGroup(&m_MasterGroup); >
- 마스터 채널 그룹을 생성해서 그 주소를 m_MasterGroup에 저장하고, 시행 결과를 result에 반환한다.
- 생성한 마스터 채널은 key값을 "Master"로 해서 m_mapChannelGroup 안에 삽입해준다.
- 초기화 과정 완료.
< FMOD::ChannelGroup* FindChannelGroup(); >
- 인자로 문자열 이름을 전달받아서 이름에 해당하는 ChannelGroup의 주소를 찾아준다.
< class Sound* FindSound() >
- 마찬가지로 사운드 데이터를 찾아줌
< bool CreateSoundChannel() >
- 인자로 사운드 채널의 이름을 받아 사운드 채널을 생성한다.
1. 일단 이름에 해당하는 채널그룹이 있는지 확인하고 없을 때 생성한다.
< CreateChannelGroup(const char* Name, &Group) >
2. ChannelGroup 포인터 변수 Group 하나 생성하고, 위 메소드에 주소를 전달해 채널을 생성한다.
- 해당 메소드의 결과로는 여타 메소드들과 같은 FMOD_RESULT가 반환된다. 잘 생성되었는지 확인하는 과정도 추가해준다.
< m_MasterGroup->addGroup(Group, false)
3. 마스터 그룹은 채널들을 일괄적으로 관리해야 하므로 새로 만든 채널그룹을 추가한다.
-2번 인자는 상위 채널을 기준으로 하위 채널들의 클록을 설정한다고 한다. false 사용.
위 과정까지 끝났으면 m_mapGroup에 추가해준다.
< Update() >
< m_System->update() >
- FMOD System 안에도 update() 메소드가 존재한다. 해당 메소드를 매 프레임 갱신시켜주어야 정상적으로 작동한다.
bool CSoundManager::LoadSound(
const std::string& GroupName,
const std::string& Name,
bool Loop,
const char* FileName,
const std::string& PathName
);
- 이제 실제 사운드를 로딩해주어야 한다.
- 인자로 생성된 사운드가 속할 그룹명, 사운드의 이름, 루프 여부, 파일명, 파일 경로를 받는다.
-- FMOD의 경로 시스템은, 멀티바이트로 처리된다.
1. 우선 해당 이름의 사운드 파일이 있는지 찾아본다. 있으면 그대로 true 리턴(이미 등록되어있으므로)
2. 해당 이름의 그룹 채널이 있는지 찾아본다. 없으면 실패를 반환하고 return
3. 사운드는 존재하지 않고, 채널은 존재하면 CSound를 동적 할당하고 이름을 넣어 준다.
4. CSound의 LoadSound() 메소드에 받은 인자를 넣어 호출한다.
5. 위 LoadSound() 과정이 성공하면 채널 그룹에 해당 사운드를 삽입해준다.
class CSound
{ FMOD::System m_System }
{ FMOD::Sound* m_Sound }
{ FMOD::ChannelGroup* m_Group }
{ FMOD::Channel* m_Channel }
{ bool m_Play } < bool GetPlay() >
- 현재 플레이 중인지 여부를 저장하는 변수
{ bool m_Loop }< bool GetLoop() >
< ~CSound() >
- 만약 m_Sound가 등록되어 있을 경우 release() 메소드를 호출해서 제거해준다.
bool CSound::LoadSound(
FMOD::System* System,
FMOD::ChannelGroup* Group,
bool Loop,
const char* FileName,
const std::string& PathName
);
1. 경로를 제외한 인자를 우선 자신의 변수에 대입한다.
2. CPath를 포함시키고, 경로를 받아온다.
{ FMOD_MODE Mode = FMOD_DEFAULT }
- FMOD_DEFAULT: 기본 1회 재생
- FMOD_LOOP_NORMAL: 루프 재생
3. 루프인지 아닌지를 확인하여 재생모드 변수를 만들어 저장해놓는다.
< m_System->createSound(Fullpath, Mode, nullptr, &m_Sound) != FMOD_OK >
4. 준비된 변수들을 createSound() 메소드에 전달하여 사운드를 생성한다. 여기서도 FMOD_OK가 반환되지 않으면 실패로 간주하고 false를 반환한다.
- 이 과정을 마치면 true를 반환한다.
< void Play() >
- 사운드 재생은 < m_System->playSound(m_Sound, m_Group, false, &m_Channel) >
- 인자: 음원 / 그룹 / 일시정지된 상태로 시작할것인지 / 재생되는 채널 주소가 저장될 변수 주소
- 재생시키고 m_Play도 true로 바꿔주자.
< void Stop() >
- m_Channel에 주소가 있다면 진입한다.
- { bool Playing } 지역변수를 false로 초기화하고, < m_Channel->isPlaying() 메소드에 주소로 넣어주면, 현재 재생 중인지에 대한 정보가 Playing에 들어오게 된다.
- 만약 Playing이 참이면, m_Channel->stop() 메소드를 호출해주면 정지가 된다.
- 이후 m_Channel을 nullptr로 바꿔 준다.
< void Pause() >
- Playing 변수를 만들어 확인하는 과정까지는 동일하다.
- 만약 Playing이 true이면, m_Channel->SetPaused() 메소드에 true를 넣고 호출한다.
- m_Playing 변수도 false로 바꿔 준다.
< void Resume() >
- Pause()의 반대로 해주면 됨
< bool SetMasterVolume(int Volume) >
- 채널 그룹의 주소로 접근하여 setVolume(float Volume) 메소드를 호출하면 됨.
- 볼륨의 크기는 0~1 사이이다.
< bool SetVolume(const std::string& Name, int Volume) >
< bool SoundPlay(const std::string&Name) >
< bool SoundStop(const std::string&Name) >
< bool SoundPause(const std::string&Name) >
< bool SoundResume(const std::string&Name) >
- 위 네 메소드는 만들어두었던 메소드를 활용하면 된다.
< void ReleaseSound(const std::string&Name) >
- ReleaseTexture 메소드와 동일한 방식
** 위의 메소드들에 CResourceManager과, CSceneResourceManager에서도 접근할 수 있게 같은 메소드를 만들어 준다.
class CPathManager;
- AddPath() 메소드를 사용하여 SOUND_PATH에 대한 경로를 "Sound/"로 설정한다.
class CSoundManager;
< Init() >
- 기본 채널 그룹 BGM, SFX, UI 세 가지 정도 만들어 두자.
< ~CSoundManager() >
- CSound는 동적할당 되어있으므로 제거해주자.
-- m_mapSound가 참조 카운팅을 사용하고 있으므로 clear 해주면 알아서 제거될 것이다.
- 전반적인 구조 설계는 끝났으므로 CMainScene에서 사운드 로드를 한 후 배경음악을 재생시켜보면 재생이 잘 되는 것을 확인할 수 있다.
'WIN32API FrameWork > 한단계씩 직접 구현' 카테고리의 다른 글
57. 위젯의 마우스 충돌 (0) | 2022.06.07 |
---|---|
56. 위젯 (0) | 2022.06.06 |
54. 마우스 충돌 - 픽셀 충돌 (0) | 2022.06.03 |
53. 마우스 (0) | 2022.06.03 |
52. 박스-원 충돌 (0) | 2022.06.02 |