X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fsound.cpp;h=8b6af20fcde8fe2c0ea22951a8d138c3dece0289;hb=97dae493948466867b9f661f45e451711dd6b41b;hp=896d1d5c392798eb63595b0bb1b1f402a990a1fa;hpb=8e69eba7dc53233c169152bdf654f032fcd0629f;p=libs%2Fal.git diff --git a/source/sound.cpp b/source/sound.cpp index 896d1d5..8b6af20 100644 --- a/source/sound.cpp +++ b/source/sound.cpp @@ -5,39 +5,108 @@ Copyright © 2008 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL */ +#include #include #include "sound.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(src); + unsigned len=min(size*nmemb, memsrc.length-memsrc.pos); + memcpy(ptr, reinterpret_cast(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(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; +} + +void memory_close(void *src) +{ + delete reinterpret_cast(src); +} + +long memory_tell(void *src) +{ + MemorySource &memsrc=*reinterpret_cast(src); + return memsrc.pos; +} + +ov_callbacks memory_callbacks= +{ + &memory_read, + &memory_seek, + 0, + &memory_tell +}; + +} // namespace + namespace Msp { namespace AL { Sound::Sound(): - data(0) + data(0), + eof_flag(false) { ovfile.datasource=0; } Sound::~Sound() { + delete[] data; if(ovfile.datasource) ov_clear(&ovfile); } -void Sound::open(const string &fn) +void Sound::open_file(const string &fn) { + if(ovfile.datasource) + throw InvalidState("Sound has already been opened"); if(ov_fopen(const_cast(fn.c_str()), &ovfile)<0) throw Exception("Could not open ogg vorbis file "+fn); - vorbis_info *info=ov_info(&ovfile, -1); - freq=info->rate; - switch(info->channels) + open_common(); +} + +void Sound::open_memory(const void *d, unsigned len) +{ + if(ovfile.datasource) + throw InvalidState("Sound has already been opened"); + + MemorySource *src=new MemorySource(d, len); + if(ov_open_callbacks(src, &ovfile, 0, 0, memory_callbacks)<0) { - case 1: format=MONO16; break; - case 2: format=STEREO16; break; - default: throw Exception("Unsupported number of channels"); + delete src; + throw Exception("Could not open ogg vorbis memory block"); } + + open_common(); } void Sound::load_data() @@ -46,17 +115,64 @@ void Sound::load_data() throw InvalidState("Data has already been loaded"); size=ov_pcm_total(&ovfile, 0)*4; - data=new char[size]; + char *dptr=new char[size]; unsigned pos=0; - while(unsigned len=read(data+pos, size-pos)) + while(unsigned len=read(dptr+pos, size-pos)) pos+=len; + data=dptr; size=pos; + read_pos=0; +} + +void Sound::load_file(const std::string &fn) +{ + open_file(fn); + load_data(); + close(); } -void Sound::load(const string &fn) +void Sound::load_memory(const void *d, unsigned len) { - open(fn); + open_memory(d, len); load_data(); + close(); +} + +void Sound::close() +{ + if(ovfile.datasource) + ov_clear(&ovfile); +} + +void Sound::rewind() +{ + if(data) + read_pos=0; + else + ov_pcm_seek(&ovfile, 0); +} + +unsigned Sound::read(char *buf, unsigned len) +{ + if(data) + { + len=min(len, size-read_pos); + memcpy(buf, data+read_pos, len); + read_pos+=len; + return len; + } + else if(ovfile.datasource) + { + int section=0; + int res=ov_read(&ovfile, buf, len, 0, 2, 1, §ion); + if(res<0) + throw Exception("Error reading ogg vorbis file"); + else if(res==0) + eof_flag=true; + return res; + } + else + throw InvalidState("No data available"); } const char *Sound::get_data() const @@ -66,13 +182,19 @@ const char *Sound::get_data() const return data; } -unsigned Sound::read(char *buf, unsigned len) +void Sound::open_common() { - int section=0; - int res=ov_read(&ovfile, buf, len, 0, 2, 1, §ion); - if(res<0) - throw Exception("Error reading ogg vorbis file"); - return res; + delete data; + data=0; + + vorbis_info *info=ov_info(&ovfile, -1); + freq=info->rate; + switch(info->channels) + { + case 1: format=MONO16; break; + case 2: format=STEREO16; break; + default: throw Exception("Unsupported number of channels"); + } } } // namespace AL