void C4MusicFileOgg::Stop(int fadeout_ms) { if (playing) { // remember position for eventual later resume ALfloat playback_pos_in_buffer = 0; alErrorCheck(alGetSourcef(channel, AL_SEC_OFFSET, &playback_pos_in_buffer)); last_playback_pos_sec += playback_pos_in_buffer; last_interruption_time = C4TimeMilliseconds::Now(); // stop! alSourceStop(channel); // clear queue ALint num_queued=0; alErrorCheck(alGetSourcei(channel, AL_BUFFERS_QUEUED, &num_queued)); ALuint buffer; for (size_t i = 0; i < (size_t)num_queued; ++i) alErrorCheck(alSourceUnqueueBuffers(channel, 1, &buffer)); } // clear buffers if (channel) { alSourcei(channel, AL_BUFFER, 0); alDeleteBuffers(num_buffers, buffers); alDeleteSources(1, &channel); } playing = false; channel = 0; // close file UnprepareSourceFileReading(); }
void C4MusicFileOgg::Execute() { if (playing) { // get processed buffer count ALint num_processed = 0; alErrorCheck(alGetSourcei(channel, AL_BUFFERS_PROCESSED, &num_processed)); bool done = false; while (num_processed--) { // refill processed buffers ALuint buffer; alErrorCheck(alSourceUnqueueBuffers(channel, 1, &buffer)); size_t buffer_idx; for (buffer_idx=0; buffer_idx<num_buffers; ++buffer_idx) if (buffers[buffer_idx] == buffer) break; if (!done) done = !FillBuffer(buffer_idx); } if (done) streaming_done = true; // check if done ALint state = 0; alErrorCheck(alGetSourcei(channel, AL_SOURCE_STATE, &state)); if (state != AL_PLAYING && streaming_done) { Stop(); } else if (state == AL_STOPPED) { alErrorCheck(alSourcePlay(channel)); } } }
bool C4MusicFileOgg::Play(bool loop) { // Valid file? if (!loaded) return false; // stop previous Stop(); // Get channel to use alGenSources(1, (ALuint*)&channel); if (!channel) return false; playing = true; streaming_done = false; this->loop = loop; byte_pos_total = 0; // initial volume setting SetVolume(float(::Config.Sound.MusicVolume) / 100.0f); // prepare read ogg_info.sound_data.resize(num_buffers * buffer_size); alGenBuffers(num_buffers, buffers); ov_pcm_seek(&ogg_file, 0); // Fill initial buffers for (size_t i=0; i<num_buffers; ++i) if (!FillBuffer(i)) break; // if this fails, the piece is shorter than the initial buffers // play! alErrorCheck(alSourcePlay(channel)); return true; }
bool C4MusicFileOgg::FillBuffer(size_t idx) { // uncompress from ogg data int endian = 0; long bytes_read_total = 0, bytes_read; char uncompressed_data[buffer_size]; do { bytes_read = ov_read(&ogg_file, uncompressed_data+bytes_read_total, (buffer_size-bytes_read_total)*sizeof(BYTE), endian, 2, 1, ¤t_section); bytes_read_total += bytes_read; } while (bytes_read > 0 && bytes_read_total < buffer_size); // buffer data if (bytes_read_total) { byte_pos_total += bytes_read_total; ALuint buffer = buffers[idx]; alErrorCheck(alBufferData(buffer, ogg_info.format, uncompressed_data, bytes_read_total, ogg_info.sample_rate)); // queue buffer alErrorCheck(alSourceQueueBuffers(channel, 1, &buffer)); } // streaming done? if (bytes_read_total < buffer_size) { // streaming done. loop or done. if (loop) { // reset pos in ogg file ov_raw_seek(&ogg_file, 0); // if looping and nothing has been committed to this buffer yet, try again // except if byte_pos_total==0, i.e. if the piece is completely empty size_t prev_bytes_total = byte_pos_total; byte_pos_total = 0; if (!bytes_read_total && prev_bytes_total) return FillBuffer(idx); return true; } else { // non-looping: we're done. return false; } } else { // might have more data to stream return true; } }
void C4MusicFileOgg::Stop(int fadeout_ms) { if (playing) { alSourceStop(channel); // clear queue ALint num_queued=0; alErrorCheck(alGetSourcei(channel, AL_BUFFERS_QUEUED, &num_queued)); ALuint buffer; for (size_t i = 0; i < (size_t)num_queued; ++i) alErrorCheck(alSourceUnqueueBuffers(channel, 1, &buffer)); } // clear buffers if (channel) { alSourcei(channel, AL_BUFFER, 0); alDeleteBuffers(num_buffers, buffers); alDeleteSources(1, &channel); } playing = false; channel = 0; }
bool C4MusicFileOgg::Play(bool loop, double max_resume_time) { // Valid file? if (!loaded) return false; // stop previous if (playing) { if (max_resume_time > 0.0) return true; // no-op Stop(); } // Ensure data reading is ready PrepareSourceFileReading(); // Get channel to use alGenSources(1, (ALuint*)&channel); if (!channel) return false; playing = true; streaming_done = false; this->loop = loop; byte_pos_total = 0; // Resume setting if (max_resume_time > 0) { // Only resume if significant amount of data is left to be played double time_remaining_sec = GetRemainingTime(); if (time_remaining_sec < max_resume_time) last_playback_pos_sec = 0.0; } else { last_playback_pos_sec = 0; } // initial volume setting SetVolume(float(::Config.Sound.MusicVolume) / 100.0f); // prepare read ogg_info.sound_data.resize(num_buffers * buffer_size); alGenBuffers(num_buffers, buffers); ov_time_seek(&ogg_file, last_playback_pos_sec); // Fill initial buffers for (size_t i=0; i<num_buffers; ++i) if (!FillBuffer(i)) break; // if this fails, the piece is shorter than the initial buffers // play! alErrorCheck(alSourcePlay(channel)); return true; }
void C4MusicFileOgg::Execute() { if (playing) { // get processed buffer count ALint num_processed = 0; alErrorCheck(alGetSourcei(channel, AL_BUFFERS_PROCESSED, &num_processed)); bool done = false; while (num_processed--) { // release processed buffer ALuint buffer; alErrorCheck(alSourceUnqueueBuffers(channel, 1, &buffer)); // add playback time of processed buffer to total playback time ALint buf_bits = 16, buf_chans = 2, buf_freq = 44100; alErrorCheck(alGetBufferi(buffer, AL_BITS, &buf_bits)); alErrorCheck(alGetBufferi(buffer, AL_CHANNELS, &buf_chans)); alErrorCheck(alGetBufferi(buffer, AL_FREQUENCY, &buf_freq)); double buffer_secs = double(buffer_size) / buf_bits / buf_chans / buf_freq * 8; last_playback_pos_sec += buffer_secs; // refill processed buffer size_t buffer_idx; for (buffer_idx=0; buffer_idx<num_buffers; ++buffer_idx) if (buffers[buffer_idx] == buffer) break; if (!done) done = !FillBuffer(buffer_idx); } if (done) streaming_done = true; // check if done ALint state = 0; alErrorCheck(alGetSourcei(channel, AL_SOURCE_STATE, &state)); if (state != AL_PLAYING && streaming_done) { Stop(); // reset playback to beginning for next time this piece is playing last_playback_pos_sec = 0.0; } else if (state == AL_STOPPED) { alErrorCheck(alSourcePlay(channel)); } } }