376 lines
7.1 KiB
C++
Executable File
376 lines
7.1 KiB
C++
Executable File
#include "precompiled.h"
|
|
|
|
#include "CMusicPlayer.h"
|
|
|
|
#ifdef _MSC_VER
|
|
# ifndef NDEBUG
|
|
# pragma comment(lib, "ogg.lib")
|
|
# pragma comment(lib, "vorbis.lib")
|
|
# pragma comment(lib, "vorbisfile.lib")
|
|
# else
|
|
# pragma comment(lib, "ogg_d.lib")
|
|
# pragma comment(lib, "vorbis_d.lib")
|
|
# pragma comment(lib, "vorbisfile_d.lib")
|
|
# endif
|
|
#endif
|
|
|
|
|
|
#include "res/res.h"
|
|
|
|
size_t VorbisRead(void *ptr, size_t byteSize, size_t sizeToRead, void *datasource)
|
|
{
|
|
size_t spaceToEOF;
|
|
size_t actualSizeToRead;
|
|
SOggFile* vorbisData;
|
|
|
|
vorbisData = (SOggFile*)datasource;
|
|
|
|
spaceToEOF = vorbisData->dataSize - vorbisData->dataRead;
|
|
if ((sizeToRead*byteSize) < spaceToEOF)
|
|
actualSizeToRead = (sizeToRead*byteSize);
|
|
else
|
|
actualSizeToRead = spaceToEOF;
|
|
|
|
if (actualSizeToRead)
|
|
{
|
|
memcpy(ptr, (char*)vorbisData->dataPtr + vorbisData->dataRead, actualSizeToRead);
|
|
vorbisData->dataRead += (actualSizeToRead);
|
|
}
|
|
|
|
return actualSizeToRead;
|
|
}
|
|
|
|
int VorbisSeek(void *datasource, ogg_int64_t offset, int fromWhere)
|
|
{
|
|
size_t spaceToEOF;
|
|
ogg_int64_t actualOffset;
|
|
SOggFile* vorbisData;
|
|
|
|
vorbisData = (SOggFile*)datasource;
|
|
|
|
switch (fromWhere)
|
|
{
|
|
case SEEK_SET:
|
|
|
|
if (vorbisData->dataSize >= offset)
|
|
actualOffset = offset;
|
|
else
|
|
actualOffset = vorbisData->dataSize;
|
|
|
|
vorbisData->dataRead = (int)actualOffset;
|
|
break;
|
|
case SEEK_CUR: // Seek from where we are
|
|
spaceToEOF = vorbisData->dataSize - vorbisData->dataRead;
|
|
if (offset < spaceToEOF)
|
|
actualOffset = (offset);
|
|
else
|
|
actualOffset = spaceToEOF;
|
|
vorbisData->dataRead += (size_t)actualOffset;
|
|
break;
|
|
case SEEK_END:
|
|
vorbisData->dataRead = vorbisData->dataSize+1;
|
|
break;
|
|
default:
|
|
printf("*** ERROR *** Unknown seek command in VorbisSeek\n");
|
|
break;
|
|
};
|
|
|
|
return 0;
|
|
}
|
|
|
|
int VorbisClose(void *datasource)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
long VorbisTell(void *datasource)
|
|
{
|
|
SOggFile* vorbisData;
|
|
vorbisData = (SOggFile*)datasource;
|
|
|
|
return (long)vorbisData->dataRead;
|
|
}
|
|
|
|
|
|
|
|
//Class implementation
|
|
CMusicPlayer::CMusicPlayer(void)
|
|
{
|
|
info = NULL;
|
|
source = NULL;
|
|
format = NULL;
|
|
|
|
buffers[0] = buffers[1] = ~0;
|
|
}
|
|
|
|
CMusicPlayer::~CMusicPlayer(void)
|
|
{
|
|
release();
|
|
}
|
|
|
|
void CMusicPlayer::open(char *filename)
|
|
{
|
|
int ret = 0;
|
|
format = NULL;
|
|
info = NULL;
|
|
|
|
/*
|
|
FILE* tempOggFile;
|
|
int sizeOfFile;
|
|
char tempChar;
|
|
int tempArray;
|
|
|
|
if(!(tempOggFile = fopen(filename, "rb")))
|
|
{
|
|
printf("Unable to open Ogg file\n");
|
|
exit(1);
|
|
}
|
|
sizeOfFile = 0;
|
|
while (!feof(tempOggFile))
|
|
{
|
|
tempChar = getc(tempOggFile);
|
|
sizeOfFile++;
|
|
}
|
|
|
|
memFile.dataPtr = new char[sizeOfFile];
|
|
rewind(tempOggFile);
|
|
tempArray = 0;
|
|
while (!feof(tempOggFile))
|
|
{
|
|
memFile.dataPtr[tempArray] = getc(tempOggFile);
|
|
tempArray++;
|
|
}
|
|
|
|
fclose(tempOggFile);
|
|
*/
|
|
void* p;
|
|
size_t sizeOfFile;
|
|
if(vfs_load(filename, p, sizeOfFile) <= 0)
|
|
return;
|
|
|
|
memFile.dataPtr = (char*)p;
|
|
memFile.dataRead = 0;
|
|
memFile.dataSize = sizeOfFile;
|
|
|
|
|
|
//set up callbacks
|
|
vorbisCallbacks.read_func = VorbisRead;
|
|
vorbisCallbacks.close_func = VorbisClose;
|
|
vorbisCallbacks.seek_func = VorbisSeek;
|
|
vorbisCallbacks.tell_func = VorbisTell;
|
|
|
|
//start file to from memory
|
|
if (ov_open_callbacks(&memFile, &oggStream, NULL, 0, vorbisCallbacks) != 0)
|
|
{
|
|
printf("Could not decode ogg into memory\n");
|
|
exit(1);
|
|
}
|
|
|
|
info = ov_info(&oggStream, -1);
|
|
|
|
if(info->channels == 1)
|
|
{
|
|
//hopefully not mono
|
|
format = AL_FORMAT_MONO16;
|
|
}
|
|
else
|
|
{
|
|
format = AL_FORMAT_STEREO16;
|
|
}
|
|
|
|
alGenBuffers(2,buffers);
|
|
//printf("Gen buffers calling check()\n");
|
|
check();
|
|
//printf("Gen sources calling check()\n");
|
|
alGenSources(1,&source);
|
|
check();
|
|
//printf("check returned from sources\n");
|
|
|
|
alSource3f(source,AL_POSITION,0.0,0.0,0.0);
|
|
check();
|
|
//printf("returned from POSITION\n");
|
|
alSource3f(source,AL_VELOCITY,0.0,0.0,0.0);
|
|
check();
|
|
//printf("returned from VELOCITY\n");
|
|
alSource3f(source,AL_DIRECTION,0.0,0.0,0.0);
|
|
check();
|
|
//printf("returned from DIRECTION\n");
|
|
alSourcef(source,AL_ROLLOFF_FACTOR,0.0);
|
|
check();
|
|
//printf("returned from ROLLOFF\n");
|
|
alSourcei(source,AL_SOURCE_RELATIVE,AL_TRUE);
|
|
check();
|
|
//printf("returned from S RELATIVE\n");
|
|
}
|
|
|
|
void CMusicPlayer::release()
|
|
{
|
|
alSourceStop(source);
|
|
empty();
|
|
alDeleteSources(1,&source);
|
|
check();
|
|
alDeleteBuffers(1,buffers);
|
|
check();
|
|
ov_clear(&oggStream);
|
|
mem_free(memFile.dataPtr);
|
|
}
|
|
|
|
|
|
bool CMusicPlayer::play()
|
|
{
|
|
check();
|
|
//printf("returned from check at start of isPlaying()\n");
|
|
//check if already playing
|
|
if(isPlaying())
|
|
return true;
|
|
|
|
//printf("calling stream on first buffer\n");
|
|
//load data into 1st buffer
|
|
if(!stream(buffers[0]))
|
|
return false;
|
|
|
|
//printf("calling stream on second buffer\n");
|
|
//load data into 2nd buffer
|
|
if(!stream(buffers[1]))
|
|
return false;
|
|
|
|
//bind the 2 buffers to the source
|
|
alSourceQueueBuffers(source,2,buffers);
|
|
check();
|
|
//printf("check returned from Queuebuffers\n");
|
|
alSourcePlay(source);
|
|
check();
|
|
//printf("check returned from SourcePlay\n");
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CMusicPlayer::isPlaying()
|
|
{
|
|
ALenum state = NULL;
|
|
|
|
alGetSourcei(source,AL_SOURCE_STATE,&state);
|
|
check();
|
|
//printf("returning from isPlaying.\n");
|
|
return (state == AL_PLAYING);
|
|
}
|
|
|
|
|
|
bool CMusicPlayer::update()
|
|
{
|
|
int processed;
|
|
bool active = true;
|
|
|
|
//check which buffers have already been played
|
|
alGetSourcei(source,AL_BUFFERS_PROCESSED, &processed);
|
|
//printf("checking() buffers processed\n");
|
|
check();
|
|
//printf("check returned\n");
|
|
|
|
while(processed-- && processed >= 0)
|
|
{
|
|
ALuint buffer;
|
|
|
|
//remove buffer from queue
|
|
alSourceUnqueueBuffers(source,1,&buffer);
|
|
check();
|
|
|
|
//fill buffer with new data if false is returned the there is no more data
|
|
active = stream(buffer);
|
|
|
|
//attach buffer to end of queue
|
|
alSourceQueueBuffers(source,1,&buffer);
|
|
check();
|
|
}
|
|
|
|
return active;
|
|
}
|
|
|
|
void CMusicPlayer::check()
|
|
{
|
|
int error = alGetError();
|
|
/*
|
|
if(error != AL_NO_ERROR)
|
|
{
|
|
std::cout << "OpenAL error " << error << errorString(error) << std::endl;
|
|
exit(1);
|
|
}
|
|
*/
|
|
}
|
|
|
|
void CMusicPlayer::empty()
|
|
{
|
|
int queued;
|
|
alGetSourcei(source,AL_BUFFERS_QUEUED,&queued);
|
|
|
|
while(queued--)
|
|
{
|
|
ALuint buffer;
|
|
|
|
alSourceUnqueueBuffers(source,1,&buffer);
|
|
check();
|
|
}
|
|
}
|
|
|
|
bool CMusicPlayer::stream(ALuint buffer)
|
|
{
|
|
char data[AUDIO_BUFFER_SIZE];
|
|
int size = 0;
|
|
int section, ret;
|
|
|
|
|
|
|
|
while(size < AUDIO_BUFFER_SIZE)
|
|
{
|
|
ret = ov_read(&oggStream, data + size, AUDIO_BUFFER_SIZE - size,0,2,1,§ion);
|
|
|
|
if(ret > 0)
|
|
{
|
|
size += ret;
|
|
}
|
|
else
|
|
{
|
|
if(ret < 0)
|
|
{
|
|
printf("Error reading from ogg file\n");
|
|
exit(1);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(size == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
alBufferData(buffer,format,data,size,info->rate);
|
|
//printf("calling check in stream()\n");
|
|
check();
|
|
//printf("check returned\n");
|
|
|
|
return true;
|
|
}
|
|
|
|
std::string CMusicPlayer::errorString(int errorcode)
|
|
{
|
|
switch(errorcode)
|
|
{
|
|
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.");
|
|
}
|
|
} |