메시지나 이벤트를 보내는 시점과 처리하는 시점을 디커플링한다.
#include <iostream>
#include <cassert>
using namespace std;
enum SoundId {
SOUND_A
};
struct PlayMessage {
SoundId id;
int volume;
};
class Audio {
public:
static void init() {
head_ = 0;
tail_ = 0;
}
static void PlaySound(SoundId id, int volume);
static void Update();
//그 외 메서드
private:
static int head_;
static int tail_;
static const int MAX_PENDING = 16;
static PlayMessage pending_[MAX_PENDING];
static int numPending_;
};
void Audio::PlaySound(SoundId id, int volume) {
//보류 중인 요청을 쭉 살펴본다.
for (int i = head_; i != tail_; i = (i + 1) % MAX_PENDING)
{
if (pending_[i].id == id) {
//둘 중에 소리가 큰 값으로 덮어쓴다.
pending_[i].volume = max(volume, pending_[i].volume);
//이 요청은 큐에 넣지 않는다.
return;
}
}
assert((tail_ + 1) % MAX_PENDING != head_);
//배열 맨 뒤에 추가한다.
pending_[tail_].id = id;
pending_[tail_].volume = volume;
tail_ = (tail_ + 1) % MAX_PENDING;
}
void Audio::Update() {
//보류된 요청이 없다면 아무것도 하지 않는다.
if (head_ == tail_) return;
ResourcedId resource = loadSound(pending_[head_].id);
int channel = findOpenChannel();
if (channel == -1) return;
startSound(resource, channel, pending_[head_].volume);
head_ = (head_ + 1) % MAX_PENDING;
}
int main() {
Audio::PlaySound(SOUND_A, 100);
Audio::Update();
}