]> git.tdb.fi Git - libs/al.git/blobdiff - source/sounddecoder.cpp
Seek back to beginning after reading signature
[libs/al.git] / source / sounddecoder.cpp
index c9da9b808e75b87b540179e4932907fbd92b6858..e0a56d3a4fc1513d21e6b99eada7f26c262903db 100644 (file)
-#include <cstring>
-#include <stdexcept>
+#include <msp/core/refptr.h>
 #include <msp/io/file.h>
-#include <msp/io/memory.h>
+#include <msp/strings/format.h>
+#include "mp3decoder.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 {
 
+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()
 {
-       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();
+       delete source;
 }
 
-void SoundDecoder::open_io(Msp::IO::Seekable &io)
+SoundDecoder *SoundDecoder::open_file(const string &fn)
 {
-       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();
+       RefPtr<IO::BufferedFile> file = new IO::BufferedFile(fn);
+       SoundDecoder *decoder = open_io(*file);
+       decoder->source = file.release();
+       return decoder;
 }
 
-void SoundDecoder::open_common()
+SoundDecoder *SoundDecoder::open_io(IO::Seekable &io)
 {
-       vorbis_info *info = ov_info(&ovfile, -1);
-       freq = info->rate;
-
-       size = ov_pcm_total(&ovfile, 0)*info->channels*2;
-
-       switch(info->channels)
+       char sig_buf[8];
+       io.read(sig_buf, sizeof(sig_buf));
+       io.seek(0, IO::S_BEG);
+       string signature(sig_buf, sizeof(sig_buf));
+       if(OggDecoder::detect(signature))
+               return new OggDecoder(io);
+       else if(Mp3Decoder::detect(signature))
+               return new Mp3Decoder(io);
+       else
        {
-       case 1: format = MONO16; break;
-       case 2: format = STEREO16; break;
-       default: throw runtime_error("Unsupported number of channels");
+               string sig_hex;
+               for(unsigned i=0; i<sizeof(sig_buf); ++i)
+               {
+                       if(i)
+                               sig_hex += ' ';
+                       sig_hex += Msp::format("%02X", static_cast<unsigned char>(sig_buf[i]));
+               }
+               throw unsupported_sound(sig_hex);
        }
 }
 
-void SoundDecoder::close()
-{
-       if(ovfile.datasource)
-               ov_clear(&ovfile);
-       delete source;
-       source = 0;
-}
-
-void SoundDecoder::rewind()
-{
-       ov_pcm_seek(&ovfile, 0);
-}
-
-unsigned SoundDecoder::read(char *buf, unsigned len)
-{
-       int section = 0;
-       int res = ov_read(&ovfile, buf, len, 0, 2, 1, &section);
-       if(res<0)
-               throw runtime_error("Error reading ogg vorbis file");
-       else if(res==0)
-               eof_flag = true;
-       return res;
-}
-
 } // namespace AL
 } // namespace Msp