mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2024-11-16 06:29:31 +00:00
303 lines
6.1 KiB
C++
303 lines
6.1 KiB
C++
|
/*
|
||
|
Copyright (C) 2007, 2010 - Bit-Blot
|
||
|
|
||
|
This file is part of Aquaria.
|
||
|
|
||
|
Aquaria is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU General Public License
|
||
|
as published by the Free Software Foundation; either version 2
|
||
|
of the License, or (at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
|
||
|
See the GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program; if not, write to the Free Software
|
||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||
|
*/
|
||
|
#include "OggStream.h"
|
||
|
#include "SoundManager.h"
|
||
|
#include "Base.h"
|
||
|
|
||
|
#define BUFFER_SIZE (4096 * 4)
|
||
|
|
||
|
OggStream::OggStream()
|
||
|
{
|
||
|
loop=false;
|
||
|
source = 0;
|
||
|
buffers[0] = 0;
|
||
|
buffers[1] = 0;
|
||
|
}
|
||
|
|
||
|
void OggStream::open(std::string path)
|
||
|
{
|
||
|
int result;
|
||
|
|
||
|
oggFile = fopen(core->adjustFilenameCase(path.c_str()), "rb");
|
||
|
|
||
|
if (!oggFile)
|
||
|
{
|
||
|
sound->error("Could not open Ogg file.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
result = ov_open(oggFile, &oggStream, NULL, 0);
|
||
|
|
||
|
if (result < 0)
|
||
|
{
|
||
|
fclose(oggFile);
|
||
|
|
||
|
sound->error(std::string("Could not open Ogg stream. ") + errorString(result));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
vorbisInfo = ov_info(&oggStream, -1);
|
||
|
vorbisComment = ov_comment(&oggStream, -1);
|
||
|
|
||
|
if(vorbisInfo->channels == 1)
|
||
|
format = AL_FORMAT_MONO16;
|
||
|
else
|
||
|
format = AL_FORMAT_STEREO16;
|
||
|
|
||
|
|
||
|
alGenBuffers(2, buffers);
|
||
|
check();
|
||
|
alGenSources(1, &source);
|
||
|
check();
|
||
|
|
||
|
alSource3f(source, AL_POSITION, 0.0, 0.0, 0.0);
|
||
|
alSource3f(source, AL_VELOCITY, 0.0, 0.0, 0.0);
|
||
|
alSource3f(source, AL_DIRECTION, 0.0, 0.0, 0.0);
|
||
|
alSourcef (source, AL_ROLLOFF_FACTOR, 0.0 );
|
||
|
alSourcei (source, AL_SOURCE_RELATIVE, AL_TRUE );
|
||
|
}
|
||
|
|
||
|
void OggStream::release()
|
||
|
{
|
||
|
BBGE_PROF(OggStream::release);
|
||
|
if (source)
|
||
|
{
|
||
|
alSourceStop(source);
|
||
|
empty();
|
||
|
alDeleteSources(1, &source);
|
||
|
check();
|
||
|
}
|
||
|
if (buffers && (buffers[0] || buffers[1]))
|
||
|
{
|
||
|
alDeleteBuffers(1, buffers);
|
||
|
check();
|
||
|
}
|
||
|
|
||
|
ov_clear(&oggStream);
|
||
|
|
||
|
source = 0;
|
||
|
buffers[0] = 0;
|
||
|
buffers[1] = 0;
|
||
|
}
|
||
|
|
||
|
void OggStream::display()
|
||
|
{
|
||
|
std::cout
|
||
|
<< "version " << vorbisInfo->version << "\n"
|
||
|
<< "channels " << vorbisInfo->channels << "\n"
|
||
|
<< "rate (hz) " << vorbisInfo->rate << "\n"
|
||
|
<< "bitrate upper " << vorbisInfo->bitrate_upper << "\n"
|
||
|
<< "bitrate nominal " << vorbisInfo->bitrate_nominal << "\n"
|
||
|
<< "bitrate lower " << vorbisInfo->bitrate_lower << "\n"
|
||
|
<< "bitrate window " << vorbisInfo->bitrate_window << "\n"
|
||
|
<< "\n"
|
||
|
<< "vendor " << vorbisComment->vendor << "\n";
|
||
|
|
||
|
for(int i = 0; i < vorbisComment->comments; i++)
|
||
|
std::cout << " " << vorbisComment->user_comments[i] << "\n";
|
||
|
|
||
|
std::cout << std::endl;
|
||
|
}
|
||
|
|
||
|
bool OggStream::play(bool l)
|
||
|
{
|
||
|
BBGE_PROF(OggStream::play);
|
||
|
if(isPlaying())
|
||
|
return true;
|
||
|
|
||
|
if(!stream(buffers[0]))
|
||
|
return false;
|
||
|
|
||
|
if(!stream(buffers[1]))
|
||
|
return false;
|
||
|
|
||
|
loop=l;
|
||
|
|
||
|
alSourceQueueBuffers(source, 2, buffers);
|
||
|
alSourcePlay(source);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool OggStream::isPlaying()
|
||
|
{
|
||
|
ALenum state;
|
||
|
|
||
|
if (source)
|
||
|
{
|
||
|
alGetSourcei(source, AL_SOURCE_STATE, &state);
|
||
|
|
||
|
return (state == AL_PLAYING);
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void OggStream::setGain(float gain)
|
||
|
{
|
||
|
if (!source) return;
|
||
|
|
||
|
alSourcef(source, AL_GAIN, gain);
|
||
|
ALenum error=alGetError();
|
||
|
|
||
|
if(error!=AL_FALSE)
|
||
|
{
|
||
|
switch(error)
|
||
|
{
|
||
|
case(AL_INVALID_VALUE):
|
||
|
sound->error("Invalid value for gain");
|
||
|
break;
|
||
|
default:
|
||
|
sound->error("Error trying to set gain!");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool OggStream::update()
|
||
|
{
|
||
|
if (!source) return false;
|
||
|
|
||
|
int processed;
|
||
|
bool active = true;
|
||
|
|
||
|
if (!isPlaying())
|
||
|
{
|
||
|
alSourcePlay(source);
|
||
|
}
|
||
|
|
||
|
alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed);
|
||
|
|
||
|
while(processed--)
|
||
|
{
|
||
|
ALuint buffer;
|
||
|
|
||
|
alSourceUnqueueBuffers(source, 1, &buffer);
|
||
|
check();
|
||
|
|
||
|
active = stream(buffer);
|
||
|
|
||
|
alSourceQueueBuffers(source, 1, &buffer);
|
||
|
check();
|
||
|
}
|
||
|
|
||
|
if (!active)
|
||
|
{
|
||
|
release();
|
||
|
}
|
||
|
|
||
|
return active;
|
||
|
}
|
||
|
|
||
|
bool OggStream::stream(ALuint buffer)
|
||
|
{
|
||
|
char pcm[BUFFER_SIZE];
|
||
|
int size = 0;
|
||
|
int section;
|
||
|
int result;
|
||
|
|
||
|
while(size < BUFFER_SIZE)
|
||
|
{
|
||
|
result = ov_read(&oggStream, pcm + size, BUFFER_SIZE - size, 0, 2, 1, §ion);
|
||
|
|
||
|
if(result > 0)
|
||
|
size += result;
|
||
|
else
|
||
|
{ if(result < 0) {} else break; }
|
||
|
}
|
||
|
|
||
|
if(size == 0)
|
||
|
{
|
||
|
if (loop)
|
||
|
{
|
||
|
std::cout << "looping\n";
|
||
|
int r = ov_pcm_seek(&oggStream, 0);
|
||
|
if (r != 0)
|
||
|
{
|
||
|
std::cout << "error\n";
|
||
|
}
|
||
|
|
||
|
while(size < BUFFER_SIZE)
|
||
|
{
|
||
|
result = ov_read(&oggStream, pcm + size, BUFFER_SIZE - size, 0, 2, 1, §ion);
|
||
|
|
||
|
if(result > 0)
|
||
|
size += result;
|
||
|
else
|
||
|
{ if(result < 0) {} else break; }
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
alBufferData(buffer, format, pcm, size, vorbisInfo->rate);
|
||
|
//check();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void OggStream::empty()
|
||
|
{
|
||
|
if (!source) return;
|
||
|
int queued;
|
||
|
|
||
|
alGetSourcei(source, AL_BUFFERS_QUEUED, &queued);
|
||
|
|
||
|
while(queued--)
|
||
|
{
|
||
|
ALuint buffer;
|
||
|
|
||
|
alSourceUnqueueBuffers(source, 1, &buffer);
|
||
|
check();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void OggStream::check()
|
||
|
{
|
||
|
int error = alGetError();
|
||
|
|
||
|
if(error != AL_NO_ERROR)
|
||
|
sound->error(std::string("OpenAL error was raised."));
|
||
|
}
|
||
|
|
||
|
std::string OggStream::errorString(int code)
|
||
|
{
|
||
|
switch(code)
|
||
|
{
|
||
|
case OV_EREAD:
|
||
|
return std::string("Read from media.");
|
||
|
case OV_ENOTVORBIS:
|
||
|
return std::string("Not Vorbis data.");
|
||
|
case OV_EVERSION:
|
||
|
return std::string("Vorbis version mismatch.");
|
||
|
case OV_EBADHEADER:
|
||
|
return std::string("Invalid Vorbis header.");
|
||
|
case OV_EFAULT:
|
||
|
return std::string("Internal logic fault (bug or heap/stack corruption.");
|
||
|
default:
|
||
|
return std::string("Unknown Ogg error.");
|
||
|
}
|
||
|
}
|
||
|
|