if(tracks.empty() || decoder)
return;
- decoder = new AL::SoundDecoder;
- decoder->open_file(*current_track);
+ decoder = SoundDecoder::open_file(*current_track);
streamer.play(*decoder);
}
--- /dev/null
+#include <stdexcept>
+#include <vorbis/vorbisfile.h>
+#include "oggdecoder.h"
+
+using namespace std;
+
+namespace {
+
+size_t read(void *ptr, size_t size, size_t nmemb, void *src)
+{
+ Msp::IO::Base *in = reinterpret_cast<Msp::IO::Base *>(src);
+ unsigned len = in->read(reinterpret_cast<char *>(ptr), size*nmemb);
+ return len/size;
+}
+
+int seek(void *src, ogg_int64_t offset, int whence)
+{
+ Msp::IO::SeekType type;
+ if(whence==SEEK_SET)
+ type = Msp::IO::S_BEG;
+ else if(whence==SEEK_CUR)
+ type = Msp::IO::S_CUR;
+ else if(whence==SEEK_END)
+ type = Msp::IO::S_END;
+ else
+ return -1;
+
+ Msp::IO::Seekable *in = reinterpret_cast<Msp::IO::Seekable *>(src);
+ return in->seek(offset, type);
+}
+
+long tell(void *src)
+{
+ return reinterpret_cast<Msp::IO::Seekable *>(src)->tell();
+}
+
+ov_callbacks io_callbacks =
+{
+ &read,
+ &seek,
+ 0,
+ &tell
+};
+
+} // namespace
+
+
+namespace Msp {
+namespace AL {
+
+struct OggDecoder::Private
+{
+ OggVorbis_File ovfile;
+};
+
+OggDecoder::OggDecoder(IO::Seekable &io):
+ priv(new Private)
+{
+ if(ov_open_callbacks(&io, &priv->ovfile, 0, 0, io_callbacks)<0)
+ throw runtime_error("Could not open ogg vorbis resource");
+
+ vorbis_info *info = ov_info(&priv->ovfile, -1);
+ freq = info->rate;
+
+ size = ov_pcm_total(&priv->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");
+ }
+}
+
+OggDecoder::~OggDecoder()
+{
+ if(priv->ovfile.datasource)
+ ov_clear(&priv->ovfile);
+ delete priv;
+}
+
+void OggDecoder::rewind()
+{
+ ov_pcm_seek(&priv->ovfile, 0);
+}
+
+unsigned OggDecoder::read(char *buf, unsigned len)
+{
+ int section = 0;
+ int res = ov_read(&priv->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;
+}
+
+} // namespace AL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_AL_OGGDECODER_H_
+#define MSP_AL_OGGDECODER_H_
+
+#include "sounddecoder.h"
+
+namespace Msp {
+namespace AL {
+
+class OggDecoder: public SoundDecoder
+{
+private:
+ struct Private;
+
+ Private *priv;
+
+public:
+ OggDecoder(IO::Seekable &);
+ ~OggDecoder();
+
+ virtual void rewind();
+ virtual unsigned read(char *, unsigned);
+};
+
+} // namespace AL
+} // namespace Msp
+
+#endif
-#include <cstring>
-#include <stdexcept>
+#include <msp/core/refptr.h>
#include <msp/io/file.h>
-#include <msp/io/memory.h>
+#include "oggdecoder.h"
#include "sounddecoder.h"
using namespace std;
-namespace {
-
-size_t read(void *ptr, size_t size, size_t nmemb, void *src)
-{
- Msp::IO::Base *in = reinterpret_cast<Msp::IO::Base *>(src);
- unsigned len = in->read(reinterpret_cast<char *>(ptr), size*nmemb);
- return len/size;
-}
-
-int seek(void *src, ogg_int64_t offset, int whence)
-{
- Msp::IO::SeekType type;
- if(whence==SEEK_SET)
- type = Msp::IO::S_BEG;
- else if(whence==SEEK_CUR)
- type = Msp::IO::S_CUR;
- else if(whence==SEEK_END)
- type = Msp::IO::S_END;
- else
- return -1;
-
- Msp::IO::Seekable *in = reinterpret_cast<Msp::IO::Seekable *>(src);
- return in->seek(offset, type);
-}
-
-long tell(void *src)
-{
- return reinterpret_cast<Msp::IO::Seekable *>(src)->tell();
-}
-
-ov_callbacks io_callbacks =
-{
- &read,
- &seek,
- 0,
- &tell
-};
-
-} // namespace
-
namespace Msp {
namespace AL {
SoundDecoder::SoundDecoder():
source(0),
+ freq(0),
+ size(0),
+ format(MONO8),
eof_flag(false)
-{
- ovfile.datasource = 0;
-}
+{ }
SoundDecoder::~SoundDecoder()
{
- close();
-}
-
-void SoundDecoder::open_file(const string &fn)
-{
- if(ovfile.datasource)
- throw logic_error("Sound has already been opened");
-
- IO::BufferedFile *file = new IO::BufferedFile(fn);
- if(ov_open_callbacks(file, &ovfile, 0, 0, io_callbacks)<0)
- {
- delete file;
- throw runtime_error("Could not open ogg vorbis file "+fn);
- }
- source = file;
-
- open_common();
-}
-
-void SoundDecoder::open_io(Msp::IO::Seekable &io)
-{
- if(ovfile.datasource)
- throw logic_error("Sound has already been opened");
-
- if(ov_open_callbacks(&io, &ovfile, 0, 0, io_callbacks)<0)
- throw runtime_error("Could not open ogg vorbis resource");
-
- 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;
- source = 0;
}
-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
-#ifndef MSP_AL_SOUND_H_
-#define MSP_AL_SOUND_H_
+#ifndef MSP_AL_SOUNDDECODER_H_
+#define MSP_AL_SOUNDDECODER_H_
#include <string>
-#include <vorbis/vorbisfile.h>
#include <msp/io/seekable.h>
#include "format.h"
class SoundDecoder
{
private:
- OggVorbis_File ovfile;
IO::Seekable *source;
+protected:
unsigned freq;
unsigned size;
Format format;
bool eof_flag;
-public:
SoundDecoder();
- ~SoundDecoder();
-
- void open_file(const std::string &);
- void open_io(IO::Seekable &);
-private:
- void open_common();
public:
- void close();
- void rewind();
- unsigned read(char *, unsigned);
+ virtual ~SoundDecoder();
+
+ static SoundDecoder *open_file(const std::string &);
+ static SoundDecoder *open_io(IO::Seekable &);
+
+ virtual void rewind() = 0;
+ virtual unsigned read(char *, unsigned) = 0;
bool eof() const { return eof_flag; }
Format get_format() const { return format; }
+#include <msp/core/refptr.h>
#include "sounddecoder.h"
#include "waveform.h"
void Waveform::load_file(const string &fn)
{
- SoundDecoder decoder;
- decoder.open_file(fn);
- load(decoder);
+ RefPtr<SoundDecoder> decoder = SoundDecoder::open_file(fn);
+ load(*decoder);
}
void Waveform::load_io(IO::Seekable &io)
{
- SoundDecoder decoder;
- decoder.open_io(io);
- load(decoder);
+ RefPtr<SoundDecoder> decoder = SoundDecoder::open_io(io);
+ load(*decoder);
}
void Waveform::load(SoundDecoder &decoder)