Context context;
context.init(22050, 2, 1024);
//main code
context.deinit();
latency (in seconds) = period_size / channels / byte per sample (2 for 16 bit sound) / sample_rate
Then application should load some samples to the library. Clunk itself does not provide code to decode audio formats, or load raw wave files. Check ogg/vorbis library for a free production-quality audio codec. Samples allocates within context internally with clunk::Context::create_sample() method.
clunk::Buffer data; //placeholder for a memory chunk //decode ogg sample into data clunk::Sample *sample = Context->create_sample(); sample->init(data, ogg_rate, AUDIO_S16LSB, ogg_channels);
So all audio data were loaded and initialized. Next step is to allocate objects. Clunk was designed to be easily integrated into programs. The most useful object is clunk::Object. It could hold several playing sources . You could use two different approaches here:
clunk::Object *clunk_object; GameObject::~GameObject() { if (clunk_object != NULL) { clunk_object->autodelete(); //destroy me! clunk_object = NULL; //leave destruction to the clunk::Context } }
So the next step is source management. It's the most easiest part. Each source connects to its audio sample. Source holds data about actual playing sound: position in wave data, pitch, gain and distance. It processes audio data and simulate 3d sound positioning with hrtf function.
Creating source and adding it to the object : (the most easiest part)
clunk_object->play("voice", new Source(yeti_sound_sample)); // no loop, no pitch, no gain adjustments.
clunk_object->cancel("voice");
Or cancel all sounds from this object at once:
clunk_object->cancel_all(true);
clunk_object->update(clunk::v3<float>(x, y, z), clunk::v3<float>(velocity_x, velocity_y, velocity_z), clunk::v3<float>(direction_x, direction_y, direction_z));
context.get_listener()->update(clunk::v3<float>(x, y, z), clunk::v3<float>(velocity_x, velocity_y, velocity_z), clunk::v3<float>(direction_x, direction_y, direction_z));
class FooStream : public clunk::Stream { public: void FooStream(const std::string &file) { //open music file. //store music parameters into members : sample_rate = music_rate; channels = music_channels; format = AUDIO_S16LSB; //this values here are only for educational purpose. Don't forget to fill it with actual values from the music file! } void rewind() { //rewind your stream here } bool read(clunk::Buffer &data, unsigned hint) { //read as many data as you want, but it'd better to read around 'hint' bytes to avoid memory queue overhead. } virtual ~FooStream() { //don't forget to close your stream here. Leaks are unwanted guests here. } };
So, the most complicated part passed by. Let the party begin !
context.play(0, new FooStream("data/background_music.ogg"), false); //do not loop music, look below for details. context.play(1, new FooStream("data/ambience_city.ogg"), true); //loops ambient
There's no magic numbers here. I've chosen 0 and 1 just for fun. You could use any integer id. 42 for example. Why don't I use loop == true for music ? We need it to change various tunes. Let's periodically test if music ends and restart with new tune:
if (!context.playing(0)) { context.play(0, new FooStream(next_song)); }
1.5.5