Removed: #795 CMusicBuffer from sound lowlevel

This commit is contained in:
kaetemi 2012-04-11 11:40:42 +02:00
parent 1aade54d7d
commit 4eeb06857c
4 changed files with 0 additions and 549 deletions

View file

@ -1,119 +0,0 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program 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.
//
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef NLSOUND_MUSIC_BUFFER_H
#define NLSOUND_MUSIC_BUFFER_H
namespace NLMISC
{
class IStream;
class CIFile;
}
namespace NLSOUND
{
/*
* TODO: Streaming
* Some kind of decent streaming functionality, to get rid of the current music implementation. Audio decoding should be done on nlsound level. IBuffer needs a writable implementation, it allocates and owns the data memory, which can be written to by nlsound. When buffer is written, a function needs to be called to 'finalize' the buffer (so it can be submitted to OpenAL for example).
* Required interface functions, IBuffer:
* /// Allocate a new writable buffer. If this buffer was already allocated, the previous data is released.
* /// May return NULL if the format or frequency is not supported by the driver.
* uint8 *IBuffer::openWritable(uint size, TBufferFormat bufferFormat, uint8 channels, uint8 bitsPerSample, uint32 frequency);
* /// Tell that you are done writing to this buffer, so it can be copied over to hardware if needed.
* /// If keepLocal is true, a local copy of the buffer will be kept (so allocation can be re-used later).
* /// keepLocal overrides the OptionLocalBufferCopy flag. The buffer can use this function internally.
* void IBuffer::lockWritable(bool keepLocal);
* Required interface functions, ISource:
* /// Enable or disable the streaming facilities.
* void ISource::setStreaming(bool streaming);
* /// Submits a new buffer to the stream. A buffer of 100ms length is optimal for streaming.
* /// Should be called by a thread which checks countStreamingBuffers every 100ms
* void ISource::submitStreamingBuffer(IBuffer *buffer);
* /// Returns the number of buffers that are queued (includes playing buffer). 3 buffers is optimal.
* uint ISource::countStreamingBuffers();
* Other required interface functions, ISource:
* /// Enable or disable 3d calculations (to send directly to speakers).
* void ISource::set3DMode(bool enable);
* For compatibility with music trough fmod, ISoundDriver:
* /// Returns true if the sound driver has a native implementation of IMusicChannel (bad!).
* /// If this returns false, use the nlsound music channel, which goes trough Ctrack/ISource,
* /// The nlsound music channel requires support for IBuffer/ISource streaming.
* bool ISoundDriver::hasMusicChannel();
*/
/**
* \brief IMusicBuffer
* \date 2008-08-30 11:38GMT
* \author Jan Boon (Kaetemi)
* IMusicBuffer is only used by the driver implementation to stream
* music files into a readable format (it's a simple decoder interface).
* You should not call these functions (getSongTitle) on nlsound or user level,
* as a driver might have additional music types implemented.
* TODO: Change IMusicBuffer to IAudioDecoder, and change the interface to make more sense.
* TODO: Allow user application to register more decoders.
* TODO: Look into libavcodec for decoding audio.
*/
class IMusicBuffer
{
private:
// pointers
/// Stream from file created by IMusicBuffer
NLMISC::IStream *_InternalStream;
public:
IMusicBuffer();
virtual ~IMusicBuffer();
/// Create a new music buffer, may return NULL if unknown type, destroy with delete. Filepath lookup done here. If async is true, it will stream from hd, else it will load in memory first.
static IMusicBuffer *createMusicBuffer(const std::string &filepath, bool async, bool loop);
/// Create a new music buffer from a stream, type is file extension like "ogg" etc.
static IMusicBuffer *createMusicBuffer(const std::string &type, NLMISC::IStream *stream, bool loop);
/// Get information on a music file (only artist and title at the moment).
static bool getInfo(const std::string &filepath, std::string &artist, std::string &title);
/// Get how many bytes the music buffer requires for output minimum.
virtual uint32 getRequiredBytes() =0;
/// Get an amount of bytes between minimum and maximum (can be lower than minimum if at end).
virtual uint32 getNextBytes(uint8 *buffer, uint32 minimum, uint32 maximum) =0;
/// Get the amount of channels (2 is stereo) in output.
virtual uint8 getChannels() =0;
/// Get the samples per second (often 44100) in output.
virtual uint32 getSamplesPerSec() =0;
/// Get the bits per sample (often 16) in output.
virtual uint8 getBitsPerSample() =0;
/// Get if the music has ended playing (never true if loop).
virtual bool isMusicEnded() =0;
/// Get the total time in seconds.
virtual float getLength() =0;
/// Get the size of uncompressed data in bytes.
virtual uint getUncompressedSize() =0;
}; /* class IMusicBuffer */
} /* namespace NLSOUND */
#endif /* #ifndef NLSOUND_MUSIC_BUFFER_H */
/* end of file */

View file

@ -1,100 +0,0 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program 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.
//
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef NLSOUND_MUSIC_BUFFER_VORBIS_H
#define NLSOUND_MUSIC_BUFFER_VORBIS_H
// STL includes
// 3rd Party includes
#ifdef NL_OS_WINDOWS
# pragma warning( push )
# pragma warning( disable : 4244 )
#endif
#include <vorbis/vorbisfile.h>
#ifdef NL_OS_WINDOWS
# pragma warning( pop )
#endif
// NeL includes
// Project includes
#include "music_buffer.h"
namespace NLSOUND
{
/**
* \brief CMusicBufferVorbis
* \date 2008-08-30 11:38GMT
* \author Jan Boon (Kaetemi)
* CMusicBufferVorbis
* Create trough IMusicBuffer, type "ogg"
*/
class CMusicBufferVorbis : public IMusicBuffer
{
protected:
// outside pointers
NLMISC::IStream *_Stream;
// pointers
// instances
OggVorbis_File _OggVorbisFile;
bool _Loop;
bool _IsMusicEnded;
sint32 _StreamOffset;
sint32 _StreamSize;
public:
CMusicBufferVorbis(NLMISC::IStream *stream, bool loop);
virtual ~CMusicBufferVorbis();
inline NLMISC::IStream *getStream() { return _Stream; }
inline sint32 getStreamSize() { return _StreamSize; }
inline sint32 getStreamOffset() { return _StreamOffset; }
/// Get information on a music file (only artist and title at the moment).
static bool getInfo(NLMISC::IStream *stream, std::string &artist, std::string &title);
/// Get how many bytes the music buffer requires for output minimum.
virtual uint32 getRequiredBytes();
/// Get an amount of bytes between minimum and maximum (can be lower than minimum if at end).
virtual uint32 getNextBytes(uint8 *buffer, uint32 minimum, uint32 maximum);
/// Get the amount of channels (2 is stereo) in output.
virtual uint8 getChannels();
/// Get the samples per second (often 44100) in output.
virtual uint32 getSamplesPerSec();
/// Get the bits per sample (often 16) in output.
virtual uint8 getBitsPerSample();
/// Get if the music has ended playing (never true if loop).
virtual bool isMusicEnded();
/// Get the total time in seconds.
virtual float getLength();
/// Get the size of uncompressed data in bytes.
virtual uint getUncompressedSize();
}; /* class CMusicBufferVorbis */
} /* namespace NLSOUND */
#endif /* #ifndef NLSOUND_MUSIC_BUFFER_VORBIS_H */
/* end of file */

View file

@ -1,109 +0,0 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program 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.
//
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdsound_lowlevel.h"
#include "nel/sound/driver/music_buffer_vorbis.h"
#include "nel/sound/driver/music_buffer.h"
using namespace std;
using namespace NLMISC;
namespace NLSOUND
{
IMusicBuffer::IMusicBuffer() : _InternalStream(NULL)
{
}
IMusicBuffer::~IMusicBuffer()
{
if (_InternalStream) { delete _InternalStream; _InternalStream = NULL; }
}
IMusicBuffer *IMusicBuffer::createMusicBuffer(const std::string &filepath, bool async, bool loop)
{
string lookup = CPath::lookup(filepath, false);
if (lookup.empty())
{
nlwarning("Music file %s does not exist!", filepath.c_str());
return NULL;
}
string type = CFile::getExtension(filepath);
CIFile *ifile = new CIFile();
ifile->setCacheFileOnOpen(!async);
ifile->allowBNPCacheFileOnOpen(!async);
ifile->open(lookup);
IMusicBuffer *mb = createMusicBuffer(type, ifile, loop);
if (mb) mb->_InternalStream = ifile;
else delete ifile;
return mb;
}
IMusicBuffer *IMusicBuffer::createMusicBuffer(const std::string &type, NLMISC::IStream *stream, bool loop)
{
if (!stream)
{
nlwarning("Stream is NULL");
return NULL;
}
string type_lower = toLower(type);
if (type_lower == "ogg")
{
return new CMusicBufferVorbis(stream, loop);
}
else
{
nlwarning("Music file type unknown: '%s'", type_lower.c_str());
return NULL;
}
}
bool IMusicBuffer::getInfo(const std::string &filepath, std::string &artist, std::string &title)
{
string lookup = CPath::lookup(filepath, false);
if (lookup.empty())
{
nlwarning("Music file %s does not exist!", filepath.c_str());
return false;
}
string type = CFile::getExtension(filepath);
string type_lower = toLower(type);
if (type_lower == "ogg")
{
CIFile ifile;
ifile.setCacheFileOnOpen(false);
ifile.allowBNPCacheFileOnOpen(false);
ifile.open(lookup);
return CMusicBufferVorbis::getInfo(&ifile, artist, title);
}
else
{
nlwarning("Music file type unknown: '%s'", type_lower.c_str());
artist.clear(); title.clear();
return false;
}
}
} /* namespace NLSOUND */
/* end of file */

View file

@ -1,221 +0,0 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program 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.
//
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdsound_lowlevel.h"
// Project includes
#include "nel/sound/driver/music_buffer_vorbis.h"
using namespace std;
using namespace NLMISC;
namespace NLSOUND
{
size_t vorbisReadFunc(void *ptr, size_t size, size_t nmemb, void *datasource)
{
CMusicBufferVorbis *music_buffer_vorbis = (CMusicBufferVorbis *)datasource;
NLMISC::IStream *stream = music_buffer_vorbis->getStream();
nlassert(stream->isReading());
sint32 length = (sint32)(size * nmemb);
if (length > music_buffer_vorbis->getStreamSize() - stream->getPos())
length = music_buffer_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
}
CMusicBufferVorbis *music_buffer_vorbis = (CMusicBufferVorbis *)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 (music_buffer_vorbis->getStream()->seek(SEEK_SET ? music_buffer_vorbis->getStreamOffset() + (sint32)offset : (sint32)offset, origin)) return 0;
else return -1;
}
//int vorbisCloseFunc(void *datasource)
//{
// //CMusicBufferVorbis *music_buffer_vorbis = (CMusicBufferVorbis *)datasource;
//}
long vorbisTellFunc(void *datasource)
{
CMusicBufferVorbis *music_buffer_vorbis = (CMusicBufferVorbis *)datasource;
return (long)(music_buffer_vorbis->getStream()->getPos() - music_buffer_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
};
CMusicBufferVorbis::CMusicBufferVorbis(NLMISC::IStream *stream, bool loop)
: _Stream(stream), _Loop(loop), _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);
}
CMusicBufferVorbis::~CMusicBufferVorbis()
{
ov_clear(&_OggVorbisFile);
}
/// Get information on a music file (only artist and title at the moment).
bool CMusicBufferVorbis::getInfo(NLMISC::IStream *stream, std::string &artist, std::string &title)
{
CMusicBufferVorbis 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 CMusicBufferVorbis::getRequiredBytes()
{
return 0; // no minimum requirement of bytes to buffer out
}
uint32 CMusicBufferVorbis::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 big 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.
&current_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);
}
return 0;
}
} while (bytes_read < minimum);
return bytes_read;
}
uint8 CMusicBufferVorbis::getChannels()
{
vorbis_info *vi = ov_info(&_OggVorbisFile, -1);
return (uint8)vi->channels;
}
uint32 CMusicBufferVorbis::getSamplesPerSec()
{
vorbis_info *vi = ov_info(&_OggVorbisFile, -1);
return vi->rate;
}
uint8 CMusicBufferVorbis::getBitsPerSample()
{
return 16;
}
bool CMusicBufferVorbis::isMusicEnded()
{
return _IsMusicEnded;
}
float CMusicBufferVorbis::getLength()
{
return (float)ov_time_total(&_OggVorbisFile, -1);
}
uint CMusicBufferVorbis::getUncompressedSize()
{
return (uint)ov_pcm_total(&_OggVorbisFile, -1) * (getBitsPerSample() / 2) * getChannels();
}
} /* namespace NLSOUND */
/* end of file */