예제 #1
0
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();
}
예제 #2
0
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));
		}
	}
}
예제 #3
0
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;
}
예제 #4
0
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, &current_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;
	}
}
예제 #5
0
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;
}
예제 #6
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;
}
예제 #7
0
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));
		}
	}
}