225 lines
6.3 KiB
C++
225 lines
6.3 KiB
C++
|
/**
|
||
|
* \file audio_decoder_vorbis.cpp
|
||
|
* \brief CAudioDecoderVorbis
|
||
|
* \date 2012-04-11 09:35GMT
|
||
|
* \author Jan Boon (Kaetemi)
|
||
|
* CAudioDecoderVorbis
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Copyright (C) 2008-2012 by authors
|
||
|
*
|
||
|
* This file is part of RYZOM CORE.
|
||
|
* RYZOM CORE is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU Affero General Public License as
|
||
|
* published by the Free Software Foundation, either version 3 of the
|
||
|
* License, or (at your option) any later version.
|
||
|
*
|
||
|
* RYZOM CORE 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
|
||
|
* Affero General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Affero General Public
|
||
|
* License along with RYZOM CORE. If not, see
|
||
|
* <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#include "stdsound.h"
|
||
|
#include <nel/sound/audio_decoder_vorbis.h>
|
||
|
|
||
|
// STL includes
|
||
|
|
||
|
// NeL includes
|
||
|
#include <nel/misc/debug.h>
|
||
|
|
||
|
// Project includes
|
||
|
|
||
|
using namespace std;
|
||
|
using namespace NLMISC;
|
||
|
|
||
|
namespace NLSOUND {
|
||
|
|
||
|
size_t vorbisReadFunc(void *ptr, size_t size, size_t nmemb, void *datasource)
|
||
|
{
|
||
|
CAudioDecoderVorbis *audio_decoder_vorbis = (CAudioDecoderVorbis *)datasource;
|
||
|
NLMISC::IStream *stream = audio_decoder_vorbis->getStream();
|
||
|
nlassert(stream->isReading());
|
||
|
sint32 length = (sint32)(size * nmemb);
|
||
|
if (length > audio_decoder_vorbis->getStreamSize() - stream->getPos())
|
||
|
length = audio_decoder_vorbis->getStreamSize() - stream->getPos();
|
||
|
stream->serialBuffer((uint8 *)ptr, length);
|
||
|
return length;
|
||
|
}
|
||
|
|
||
|
int vorbisSeekFunc(void *datasource, ogg_int64_t offset, int whence)
|
||
|
{
|
||
|
if (whence == SEEK_CUR && offset == 0)
|
||
|
{
|
||
|
// nlwarning(NLSOUND_XAUDIO2_PREFIX "This seek call doesn't do a damn thing, wtf.");
|
||
|
return 0; // ooookkaaaaaayyy
|
||
|
}
|
||
|
|
||
|
CAudioDecoderVorbis *audio_decoder_vorbis = (CAudioDecoderVorbis *)datasource;
|
||
|
|
||
|
NLMISC::IStream::TSeekOrigin origin;
|
||
|
switch (whence)
|
||
|
{
|
||
|
case SEEK_SET:
|
||
|
origin = NLMISC::IStream::begin;
|
||
|
break;
|
||
|
case SEEK_CUR:
|
||
|
origin = NLMISC::IStream::current;
|
||
|
break;
|
||
|
case SEEK_END:
|
||
|
origin = NLMISC::IStream::end;
|
||
|
break;
|
||
|
default:
|
||
|
// nlwarning(NLSOUND_XAUDIO2_PREFIX "Seeking to fake origin.");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (audio_decoder_vorbis->getStream()->seek(SEEK_SET ? audio_decoder_vorbis->getStreamOffset() + (sint32)offset : (sint32)offset, origin)) return 0;
|
||
|
else return -1;
|
||
|
}
|
||
|
|
||
|
//int vorbisCloseFunc(void *datasource)
|
||
|
//{
|
||
|
// //CAudioDecoderVorbis *audio_decoder_vorbis = (CAudioDecoderVorbis *)datasource;
|
||
|
//}
|
||
|
|
||
|
long vorbisTellFunc(void *datasource)
|
||
|
{
|
||
|
CAudioDecoderVorbis *audio_decoder_vorbis = (CAudioDecoderVorbis *)datasource;
|
||
|
return (long)(audio_decoder_vorbis->getStream()->getPos() - audio_decoder_vorbis->getStreamOffset());
|
||
|
}
|
||
|
|
||
|
static ov_callbacks OV_CALLBACKS_NLMISC_STREAM = {
|
||
|
(size_t (*)(void *, size_t, size_t, void *)) vorbisReadFunc,
|
||
|
(int (*)(void *, ogg_int64_t, int)) vorbisSeekFunc,
|
||
|
(int (*)(void *)) NULL, //vorbisCloseFunc,
|
||
|
(long (*)(void *)) vorbisTellFunc
|
||
|
};
|
||
|
|
||
|
CAudioDecoderVorbis::CAudioDecoderVorbis(NLMISC::IStream *stream, bool loop)
|
||
|
: _Stream(stream), _Loop(loop), _StreamSize(0), _IsMusicEnded(false)
|
||
|
{
|
||
|
_StreamOffset = stream->getPos();
|
||
|
stream->seek(0, NLMISC::IStream::end);
|
||
|
_StreamSize = stream->getPos();
|
||
|
stream->seek(_StreamOffset, NLMISC::IStream::begin);
|
||
|
ov_open_callbacks(this, &_OggVorbisFile, NULL, 0, OV_CALLBACKS_NLMISC_STREAM);
|
||
|
}
|
||
|
|
||
|
CAudioDecoderVorbis::~CAudioDecoderVorbis()
|
||
|
{
|
||
|
ov_clear(&_OggVorbisFile);
|
||
|
}
|
||
|
|
||
|
/// Get information on a music file (only artist and title at the moment).
|
||
|
bool CAudioDecoderVorbis::getInfo(NLMISC::IStream *stream, std::string &artist, std::string &title)
|
||
|
{
|
||
|
CAudioDecoderVorbis mbv(stream, false); // just opens and closes the oggvorbisfile thing :)
|
||
|
vorbis_comment *vc = ov_comment(&mbv._OggVorbisFile, -1);
|
||
|
char *title_c = vorbis_comment_query(vc, "title", 0);
|
||
|
if (title_c) title = title_c; else title.clear();
|
||
|
char *artist_c = vorbis_comment_query(vc, "artist", 0);
|
||
|
if (artist_c) artist = artist_c; else artist.clear();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
uint32 CAudioDecoderVorbis::getRequiredBytes()
|
||
|
{
|
||
|
return 0; // no minimum requirement of bytes to buffer out
|
||
|
}
|
||
|
|
||
|
uint32 CAudioDecoderVorbis::getNextBytes(uint8 *buffer, uint32 minimum, uint32 maximum)
|
||
|
{
|
||
|
sint current_section = 0; // ???
|
||
|
if (_IsMusicEnded) return 0;
|
||
|
nlassert(minimum <= maximum); // can't have this..
|
||
|
uint32 bytes_read = 0;
|
||
|
#ifdef NL_BIG_ENDIAN
|
||
|
sint endianness = 1;
|
||
|
#else
|
||
|
sint endianness = 0;
|
||
|
#endif
|
||
|
do
|
||
|
{
|
||
|
// signed 16-bit or unsigned 8-bit little-endian samples
|
||
|
sint br = ov_read(&_OggVorbisFile, (char *)&buffer[bytes_read], maximum - bytes_read,
|
||
|
endianness, // Specifies big or little endian byte packing. 0 for little endian, 1 for b ig endian. Typical value is 0.
|
||
|
getBitsPerSample() == 8 ? 1 : 2,
|
||
|
getBitsPerSample() == 8 ? 0 : 1, // Signed or unsigned data. 0 for unsigned, 1 for signed. Typically 1.
|
||
|
¤t_section);
|
||
|
// nlinfo(NLSOUND_XAUDIO2_PREFIX "current_section: %i", current_section);
|
||
|
if (br > 0)
|
||
|
{
|
||
|
bytes_read += (uint32)br;
|
||
|
}
|
||
|
else if (br == 0) // EOF
|
||
|
{
|
||
|
if (_Loop)
|
||
|
{
|
||
|
ov_pcm_seek(&_OggVorbisFile, 0);
|
||
|
//_Stream->seek(0, NLMISC::IStream::begin);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_IsMusicEnded = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// error
|
||
|
switch(br)
|
||
|
{
|
||
|
case OV_HOLE:
|
||
|
nlwarning("ov_read returned OV_HOLE");
|
||
|
break;
|
||
|
case OV_EINVAL:
|
||
|
nlwarning("ov_read returned OV_EINVAL");
|
||
|
break;
|
||
|
case OV_EBADLINK:
|
||
|
nlwarning("ov_read returned OV_EBADLINK");
|
||
|
break;
|
||
|
default:
|
||
|
nlwarning("ov_read returned %d", br);
|
||
|
}
|
||
|
}
|
||
|
} while (bytes_read < minimum);
|
||
|
return bytes_read;
|
||
|
}
|
||
|
|
||
|
uint8 CAudioDecoderVorbis::getChannels()
|
||
|
{
|
||
|
vorbis_info *vi = ov_info(&_OggVorbisFile, -1);
|
||
|
return (uint8)vi->channels;
|
||
|
}
|
||
|
|
||
|
uint CAudioDecoderVorbis::getSamplesPerSec()
|
||
|
{
|
||
|
vorbis_info *vi = ov_info(&_OggVorbisFile, -1);
|
||
|
return (uint)vi->rate;
|
||
|
}
|
||
|
|
||
|
uint8 CAudioDecoderVorbis::getBitsPerSample()
|
||
|
{
|
||
|
return 16;
|
||
|
}
|
||
|
|
||
|
bool CAudioDecoderVorbis::isMusicEnded()
|
||
|
{
|
||
|
return _IsMusicEnded;
|
||
|
}
|
||
|
|
||
|
float CAudioDecoderVorbis::getLength()
|
||
|
{
|
||
|
return (float)ov_time_total(&_OggVorbisFile, -1);
|
||
|
}
|
||
|
|
||
|
} /* namespace NLSOUND */
|
||
|
|
||
|
/* end of file */
|