나누기와 fmod

다음의 예제코드를 한번 보자. 간단히 코드 설명을 하자면...
270도에 해당되는 gap을 22.5도에 해당되는 border로 나눈 다음 나머지는 fmod 로 구한다
라는 내용의 코드에 해당된다.

/////////////////////////////////////////////////////////////////////
#define D3DX_PI    ((FLOAT)  3.141592654f) // d3dx9math.h

float gap = D3DX_PI * 1.5; // 4.7123890
float border = D3DX_PI / 8; // 0.39269909

int quot = (int) (gap / border);
float mod = ::fmod(gap, border);
/////////////////////////////////////////////////////////////////////


일반적인 컴파일 환경에서 이 빌드는 다음과 같은 리턴값을 내게 된다.

quot : 11
mod : 0.39269897

사실은 quot 가 12가 나오고 mod는 0이 나오는 것을 예상했지만 float 연산에서의 말로는 표현할 수 없는 정확도와 관련된 작은 오차로 인해서 위와 같은 결과값이 나오는 것이라고 예상 할 수 있겠다.

그럼 컴파일 옵션을 다음과 같이 바꿔 보자

구성속성 -> C/C++ -> 코드 생성 에 들어가서

부동 소수점 모델을 Fast (/fp:fast)  로 변경
고급 명령어 집합 사용을 스트리밍 SIMD Extensions(/arch:SSE) 로 변경

그 이후에 다시 저 값을 돌려보면 다른 연산 결과가 나온다.

quot : 12
mod : 0.39269897

원래 도출하려고 했던 답으로는 아주 곤란하다. quot는 12가 나왔지만 mod는 원래대로의 컴파일 옵션과 다를것 없는 결과가 나와버렸다.
해당 컴파일된 내용을 디어셈블러로 보게 되면 약간 재미있는것을 보게 되는데 소스에서 int quot = (int)(gap / border) 하는 부분인데,

// /fast 옵션과 SIMD, SIMD2의 옵션이 모두 켜졌을때
int quot = (int) (gap / border);
004113F8 movss xmm0,dword ptr [gap]
004113FD divss xmm0,dword ptr [border]
00411402 cvttss2si eax,xmm0
00411406 mov dword ptr [quot],eax

// SMID 또는 /fast 옵션 두개중 한개만 켜있거나 둘다 꺼져있는 경우
int quot = (int) (gap / border);
00411420 fld dword ptr [gap]
00411423 fdiv dword ptr [border]
00411426 call @ILT+230(__ftol2_sse) (4110EBh)
0041142B mov dword ptr [quot],eax

다른건 둘째치고 굵게 처리된 부분에서 약간의 차이가 존재한다.
위의 경우에는 CPU에서 지원하는 cvttss2si 라는 명령어 셋을 호출한다. 저 명령어 셋은 간단히 실수형 체계를 정수형 체계로 전환하는 명령어 셋이라고 볼 수 있는데 지원되는 CPU가 한정된 명령어 셋이라고 볼수 있는 반면, 밑의 경우는 따로 어떠한 함수를 호출하게 된다.

이 결과를 어떻게 받아들일지는 결론은 개개인에 맡기고 싶다.
원래 도출하고 싶은 결론은 SMID와 /fast 옵션을 둘다 킬때에는 저런 실수 나누기 연산에 유의해야 한다는 점이였지만 다른 재미있는 현상도 발견하게 되어 같이 적어봤다.

by 1ststory | 2009/12/30 11:36 | Programmable | 트랙백 | 덧글(0)

Game Audio Programming (3)

Chapter7
DirectSound 구현

DirectSound 기초
하드웨어 기반의 디지털 오디오 혼합 장치와 관련된 소프트웨어 인터페이스
실시간으로 개개의 사운드 버퍼를 혼합

VxD , WDM 드라이버
VxD - 오디오 하드웨어를 독점 사용(윈도우 95, 윈도우 98 (first edition) )
WDM - KMixer 에서 커널 레벨의 혼합


IDirectSound8 인터페이스
IDirectSound8 장치의 열거
HRESULT WINAPI DirectSoundEnumerate
BOOL CALLBACK DSEnumCallback

DirectSound8 오브젝트 생성
DirectSoundCreate8() - COM 오브젝트 생성
HRESULT DirectSoundCreate8(
  LPCGUID lpcGuidDevice,
  LPDIRECTSOUND8 * ppDS8,
  LPUNKNOWN pUnkOuter
);

lpcGuidDevice - 사용하고자 하는 사운드 카드의 GUID. NULL 이면 메인 사운드 카드 사용
ppDS8 - IDirectSound8 인터페이스 포인터
pUnkOuter - 예약된 파라메터. NULL 사용

CoCreateInstance() - DirectSound 직접 초기화

Cooperation 레벨 설정
SetCooperativeLevel()

장치 설정(CAP) 검색
GetCaps()
dwMaxHwMixingAllBuffers - 사용 가능한 버퍼 숫자(0~256)
dwTotalHwMemBytes - PCI/ISA 카드 구분가능 (0 - PCI, 아니면 ISA)

1차 버퍼 생성
CreateSoundBuffer()

오브젝트 해제
Release()

Chapter8
기본 디지털 오디오 샘플 재생


Wave 파일 로딩
Wave 파일 포멧

RIFF (Resource Interchange Format File) 타입

WAVEFORMATEX 구조
WAVEFORMATEX - mmsystem.h

wFormatTag - 포멧 타입 (PCM - WAVE_FORMAT_PCM)
nChannels -  wave 파일의 채널 갯수
nSamplePerSec - 샘플 비율 (hertz, ex - 11025, 22050, 44100)
nAveBytePerSec - 대역폭 초당 비율 ( nSamplesPerSec * nBlockAlign )
nBlockAlign - 단일 샘플 그룹의 크기 (16bit 스테레오 - 4byte, 8bit 모노 - 1byte, nChannels * (wBitPerSample / 8) )
wBitPerSample - 샘플의 bit 수 (8, 16)
cbSize - WAVEPROMATEX 의 크기

파일 로드 부분 구현부 생략

IDirectSoundBuffer8 인터페이스
DirectSound 버퍼

버퍼 레벨에서의 디지털 오디오 제어

Wave 파일의 로딩
버퍼 생성
버퍼를 채움 - Lock()
버퍼의 재생과 조작 - Play(), Stop(), GetStatus()
Volume, Pan, Frequency
SetVolume() - 볼륨조절(-10000 ~ 0, 데시벨단위로 입력)
SetPan() - 좌우 음향 조절
SetFrequency() - 재생 비율 조절

by 1ststory | 2009/03/29 23:20 | 책읽기 | 트랙백 | 덧글(0)

Game Audio Programming (2)

Chapter 4
튼튼한 오디오 API 디자인


오디오 시스템 디자인 목적
저레벨 기능
2D 사운드 기본 동작(재생, 정지, 멈춤, 볼륨 등등)
기본 동작과 특성 조작
3D listener object 기본 기능 추출
개별의 사운드 오브젝트 하드웨어 요소 추출

중레벨 기능
PCM 웨이브 파일 로드
거대한 오디오 파일 로드
사운드 동적 로드, 언로드에 대한 하드웨어 리소스 자동 관리
다수의 압축 오디오 포멧 관리(Ogg, MP3, WMA, ACM)

고레벨 기능
스크립트 로드 시스템
고레벨 음경 시스템 생성

일반적인 API 디자인 원칙
튼튼하고, 사용하기 쉽고, 파워풀하며 유연성 있는 API 라이브러리 및 시스템
얼마나 추상적이며 얼마나 은폐적인가

내부 vs 외부 API들

추상 인터페이스
-생략-

오디오 인터페이스 계층
Application
High-Level Music system, High-Level Sound System
Mid-level Wrapper Layer
API Layer (DirectX Audio or other API)
몇몇의 기본 원칙
오브젝트 기반 디자인
오브젝트 디자인과 네이밍 조화

Chapeter 5
오디오 API 구현

대략적인 구현 API에 대한 인터페이스 소개. 대략적인 내용은 생략

인터페이스 클래스
IAudioBase - API 인터페이스 공통 정의
IPlayable - 기본 오디오 통제
ISound - 2D 사운드
ISound3D, IListener - 3D 오디오 영역
ISegment, IDLS
IAudioScript - DirectMusic 스크립팅 인터페이스
IAudioManager - 오디오 시스템의 핵심


Chapter 6
DirectX 오디오 개요
DirectX Audio

DirectSound
DirectX Audio 저레벨 오디오 컴포넌트
- 샘플 오디오 데이터 청크의 관리(?)
- 모든 오디오 데이터 혼합(?)

DirectMusic
마지막으로 추가된 DirectX Audio 시스템
MIDI + DLS 시스템
음악 녹음 재생 시스템 과 사운드 이펙트 녹음재생 시스템 둘다 이용

DirectX 와 COM(Component Object Model)
COM
바이너리 레벨의 표준 오브젝트 모델
다른 언어와의 호환성
CoInitialize() 호출로 사용. CoUninitialize() 호출로 사용 종료
결과값은 HRESULT (32비트 정수값) 리턴값으로 구분

COM 오브젝트 생성
CoCreateInstance()

IUnknown
모든 COM 오브젝트들은 참조 카운트가 존재. 참조 카운트가 0가되야 삭제
AddRef() - 참조 카운트 증가
Release() - 오브젝트 종료

DirectX9 SDK 인스톨 및 사용
생략

DirectX Audio 프로젝트 생성
생략

by 1ststory | 2009/03/15 22:54 | 책읽기 | 트랙백 | 덧글(0)

◀ 이전 페이지다음 페이지 ▶