-#include <cstring>
-#include <stdexcept>
+#include <msp/core/refptr.h>
+#include <msp/io/file.h>
+#include "oggdecoder.h"
#include "sounddecoder.h"
using namespace std;
-namespace {
-
-struct MemorySource
-{
- const void *data;
- unsigned length;
- unsigned pos;
-
- MemorySource(const void *d, unsigned l): data(d), length(l), pos(0) { }
-};
-
-size_t memory_read(void *ptr, size_t size, size_t nmemb, void *src)
-{
- MemorySource &memsrc = *reinterpret_cast<MemorySource *>(src);
- unsigned len = min<unsigned>(size*nmemb, memsrc.length-memsrc.pos);
- memcpy(ptr, reinterpret_cast<const char *>(memsrc.data)+memsrc.pos, len);
- memsrc.pos += len;
-
- return len/size;
-}
-
-int memory_seek(void *src, ogg_int64_t offset, int whence)
-{
- MemorySource &memsrc = *reinterpret_cast<MemorySource *>(src);
- if(whence==SEEK_SET)
- memsrc.pos = offset;
- else if(whence==SEEK_CUR)
- memsrc.pos += offset;
- else if(whence==SEEK_END)
- memsrc.pos = memsrc.length-offset;
- memsrc.pos = min(memsrc.pos, memsrc.length);
-
- return memsrc.pos;
-}
-
-int memory_close(void *src)
-{
- delete reinterpret_cast<MemorySource *>(src);
- return 0;
-}
-
-long memory_tell(void *src)
-{
- MemorySource &memsrc = *reinterpret_cast<MemorySource *>(src);
- return memsrc.pos;
-}
-
-ov_callbacks memory_callbacks=
-{
- &memory_read,
- &memory_seek,
- &memory_close,
- &memory_tell
-};
-
-} // namespace
-
namespace Msp {
namespace AL {
+unsupported_sound::unsupported_sound(const string &w):
+ runtime_error(w)
+{ }
+
+
SoundDecoder::SoundDecoder():
+ source(0),
+ freq(0),
+ size(0),
+ format(MONO8),
eof_flag(false)
-{
- ovfile.datasource = 0;
-}
+{ }
SoundDecoder::~SoundDecoder()
{
- if(ovfile.datasource)
- ov_clear(&ovfile);
-}
-
-void SoundDecoder::open_file(const string &fn)
-{
- if(ovfile.datasource)
- throw logic_error("Sound has already been opened");
- if(ov_fopen(const_cast<char *>(fn.c_str()), &ovfile)<0)
- throw runtime_error("Could not open ogg vorbis file "+fn);
-
- open_common();
-}
-
-void SoundDecoder::open_memory(const void *d, unsigned len)
-{
- if(ovfile.datasource)
- throw logic_error("Sound has already been opened");
-
- MemorySource *src = new MemorySource(d, len);
- if(ov_open_callbacks(src, &ovfile, 0, 0, memory_callbacks)<0)
- {
- delete src;
- throw runtime_error("Could not open ogg vorbis memory block");
- }
-
- open_common();
-}
-
-void SoundDecoder::open_common()
-{
- vorbis_info *info = ov_info(&ovfile, -1);
- freq = info->rate;
-
- size = ov_pcm_total(&ovfile, 0)*info->channels*2;
-
- switch(info->channels)
- {
- case 1: format = MONO16; break;
- case 2: format = STEREO16; break;
- default: throw runtime_error("Unsupported number of channels");
- }
-}
-
-void SoundDecoder::close()
-{
- if(ovfile.datasource)
- ov_clear(&ovfile);
+ delete source;
}
-void SoundDecoder::rewind()
+SoundDecoder *SoundDecoder::open_file(const string &fn)
{
- ov_pcm_seek(&ovfile, 0);
+ RefPtr<IO::BufferedFile> file = new IO::BufferedFile(fn);
+ SoundDecoder *decoder = new OggDecoder(*file);
+ decoder->source = file.release();
+ return decoder;
}
-unsigned SoundDecoder::read(char *buf, unsigned len)
+SoundDecoder *SoundDecoder::open_io(IO::Seekable &io)
{
- int section = 0;
- int res = ov_read(&ovfile, buf, len, 0, 2, 1, §ion);
- if(res<0)
- throw runtime_error("Error reading ogg vorbis file");
- else if(res==0)
- eof_flag = true;
- return res;
+ return new OggDecoder(io);
}
} // namespace AL