Main Page   Namespace List   Class Hierarchy   Compound List   File List   Compound Members   File Members  

vorbis_soundprovider_generic.cpp

Go to the documentation of this file.
00001 /*
00002         $Id: vorbis_soundprovider_generic.cpp,v 1.13 2001/02/24 06:00:40 cybernerd Exp $
00003 
00004         ------------------------------------------------------------------------
00005         ClanLib, the platform independent game SDK.
00006 
00007         This library is distributed under the GNU LIBRARY GENERAL PUBLIC LICENSE
00008         version 2. See COPYING for details.
00009 
00010         For a total list of contributers see CREDITS.
00011 
00012         ------------------------------------------------------------------------
00013 */
00014 
00016 
00017 #include "vorbis_soundprovider_generic.h"
00018 
00019 
00020 CL_VorbisSoundProvider::CL_VorbisSoundProvider(
00021         const std::string &name,
00022         CL_InputSourceProvider *provider,
00023         bool delete_provider)
00024 {
00025         impl = new CL_VorbisSoundProvider_Generic;
00026         impl->name = name;
00027         impl->provider = provider;
00028         impl->delete_provider = delete_provider;
00029         
00030         if (provider == NULL)
00031         {
00032                 impl->provider = CL_InputSourceProvider::create_file_provider("");
00033                 impl->delete_provider = true;
00034         }
00035 }
00036 
00037 CL_VorbisSoundProvider::CL_VorbisSoundProvider(
00038         const std::string &name,
00039         CL_ResourceManager *resources)
00040 {
00041         impl = new CL_VorbisSoundProvider_Generic;
00042         impl->name = name;
00043         impl->provider = resources->get_resource_provider();
00044 }
00045 
00046 CL_VorbisSoundProvider::~CL_VorbisSoundProvider()
00047 {
00048         if (impl->delete_provider) delete impl->provider;
00049         delete impl;
00050 }
00051 
00052 CL_StreamSoundProvider_Session *CL_VorbisSoundProvider::begin_session()
00053 {
00054         return new CL_VorbisStream(impl->provider->open_source(impl->name.c_str()));
00055 }
00056 
00057 void CL_VorbisSoundProvider::end_session(CL_StreamSoundProvider_Session *session)
00058 {
00059         delete session;
00060 }
00061 
00062 // -----------------------------------------------------------------------------
00063 
00064 CL_VorbisStream::CL_VorbisStream(CL_InputSource *_input)
00065 : inited(false), input(_input), stream_eof(false)
00066 {
00067         init();
00068 }
00069 
00070 CL_VorbisStream::~CL_VorbisStream()
00071 {
00072         deinit();
00073 }
00074 
00075 void CL_VorbisStream::init()
00076 {
00077         if (inited) return;
00078 
00079         input->seek(0, CL_InputSource::seek_set);
00080 
00081         ogg_sync_init(&oy); /* Now we can read pages */
00082 
00083         char *buffer;
00084         int bytes;
00085         
00086         buffer = ogg_sync_buffer(&oy,4096);
00087         bytes = input->read(buffer, 4096);
00088         ogg_sync_wrote(&oy,bytes);
00089 
00090         /* Get the first page. */
00091         if (ogg_sync_pageout(&oy,&og) !=1)
00092         {
00093                 /* error case.  Must not be Vorbis data */
00094                 throw CL_Error("Input does not appear to be an Ogg bitstream.");
00095         }
00096         
00097         /* Get the serial number and set up the rest of decode. */
00098         /* serialno first; use it to set up a logical stream */
00099         ogg_stream_init(&os,ogg_page_serialno(&og));
00100 
00101         vorbis_info_init(&vi);
00102         vorbis_comment_init(&vc);
00103         if (ogg_stream_pagein(&os,&og)<0)
00104         { 
00105                 /* error; stream version mismatch perhaps */
00106                 throw CL_Error("Error reading first page of Ogg bitstream data.");
00107         }
00108         
00109         if (ogg_stream_packetout(&os,&op)!=1)
00110         { 
00111                 /* no page? must not be vorbis */
00112                 throw CL_Error("Error reading initial header packet.");
00113         }
00114     
00115         if (vorbis_synthesis_headerin(&vi,&vc,&op)<0)
00116         { 
00117                 /* error case; not a vorbis header */
00118                 throw CL_Error("This Ogg bitstream does not contain Vorbis "
00119                       "audio data.");
00120         }
00121     
00122         /* At this point, we're sure we're Vorbis.  We've set up the logical
00123            (Ogg) bitstream decoder.  Get the comment and codebook headers and
00124            set up the Vorbis decoder */
00125     
00126         /* The next two packets in order are the comment and codebook headers.
00127            They're likely large and may span multiple pages.  Thus we reead
00128            and submit data until we get our two pacakets, watching that no
00129            pages are missing.  If a page is missing, error out; losing a
00130            header page is the only place where missing data is fatal. */
00131     
00132         int i=0;
00133         while (i<2)
00134         {
00135                 while (i<2)
00136                 {
00137                         int result=ogg_sync_pageout(&oy,&og);
00138                         if(result==0) break; /* Need more data */
00139                         /* Don't complain about missing or corrupt data yet.  We'll
00140                            catch it at the packet output phase */
00141                         if(result==1)
00142                         {
00143                                 ogg_stream_pagein(&os,&og);
00144                                 /* we can ignore any errors here
00145                                    as they'll also become apparent
00146                                    at packetout */
00147 
00148                                 while(i<2)
00149                                 {
00150                                         result=ogg_stream_packetout(&os,&op);
00151                                         if(result==0)break;
00152                                         if(result==-1)
00153                                         {
00154                                                 /* Uh oh; data at some point was corrupted or missing!
00155                                                 We can't tolerate that in a header.  Die. */
00156                                                 throw CL_Error("Corrupt secondary header.");
00157                                         }
00158                                         vorbis_synthesis_headerin(&vi,&vc,&op);
00159                                         i++;
00160                                 }
00161                         }
00162                 }
00163                 /* no harm in not checking before adding more */
00164                 buffer=ogg_sync_buffer(&oy,4096);
00165                 bytes=input->read(buffer,4096);
00166                 if(bytes==0 && i<2)
00167                 {
00168                         throw CL_Error("End of file before finding all Vorbis headers!");
00169                 }
00170                 ogg_sync_wrote(&oy,bytes);
00171         }
00172     
00173         /* Throw the comments plus a few lines about the bitstream we're
00174         decoding */
00175 /*      {
00176                 char **ptr=vc.user_comments;
00177                 while(*ptr)
00178                 {
00179                         fprintf(stderr,"%s\n",*ptr);
00180                         ++ptr;
00181                 }
00182                 fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi.channels,vi.rate);
00183                 fprintf(stderr,"Encoded by: %s\n\n",vc.vendor);
00184         }
00185     
00186         convsize=4096/vi.channels;
00187 */
00188 //      std::cout << "vc.vendor: " << vc.vendor << std::endl;
00189         
00190         /* OK, got and parsed all three headers. Initialize the Vorbis
00191         packet->PCM decoder. */
00192         vorbis_synthesis_init(&vd,&vi); /* central decode state */
00193         vorbis_block_init(&vd,&vb);     /* local state for most of the decode
00194                                        so multiple block decodes can
00195                                        proceed in parallel.  We could init
00196                                        multiple vorbis_block structures
00197                                        for vd here */
00198 }
00199 
00200 void CL_VorbisStream::deinit()
00201 {
00202         if (!inited) return;
00203 
00204         /* clean up this logical bitstream; before exit we see if we're
00205         followed by another [chained] */
00206         
00207         ogg_stream_clear(&os);
00208         
00209         /* ogg_page and ogg_packet structs always point to storage in
00210         libvorbis.  They're never freed or manipulated directly */
00211         
00212         vorbis_block_clear(&vb);
00213         vorbis_dsp_clear(&vd);
00214         vorbis_info_clear(&vi);  /* must be called last */
00215 
00216         /* OK, clean up the framer */
00217         ogg_sync_clear(&oy);
00218 
00219         delete input;
00220 }
00221 
00222 bool CL_VorbisStream::eof() const
00223 {
00224         return stream_eof;
00225 }
00226 
00227 void CL_VorbisStream::stop()
00228 {
00229 }
00230 
00231 bool CL_VorbisStream::play()
00232 {
00233         if (stream_eof)
00234         {
00235                 deinit();
00236                 stream_eof = false;
00237                 init();
00238         }
00239         return true;
00240 }
00241 
00242 bool CL_VorbisStream::set_position(int pos)
00243 {
00244         return false;
00245 }
00246 
00247 int CL_VorbisStream::get_data(void *_data_ptr, int data_requested)
00248 {
00249         data_requested /= sizeof(short) * vi.channels;
00250         
00251         short *data_ptr = (short *) _data_ptr;
00252         int data_left = data_requested;
00253 
00254         while (!eof() && data_left > 0)
00255         {
00256                 float **pcm;
00257 
00258                 int samples = vorbis_synthesis_pcmout(&vd, &pcm);
00259                 if (samples <= 0)
00260                 {
00261                         stream_data();
00262                         continue;
00263                 }
00264                 
00265                 if (samples > data_left) samples = data_left;
00266 
00267                 for (int i=0; i<samples; i++)
00268                 {
00269                         for (int j=0; j<vi.channels; j++)
00270                         {
00271                                 int s = (int) (pcm[j][i] * 32767);
00272                                 if (s < -32767) s = -32767;
00273                                 else if (s > 32767) s = 32767;
00274                                 *(data_ptr++) = (short) s;
00275                         }
00276                 }
00277                 
00278                 vorbis_synthesis_read(&vd, samples);
00279                 data_left -= samples;
00280         }
00281         
00282         return (data_requested - data_left) * sizeof(short) * vi.channels;
00283 }
00284 
00285 void CL_VorbisStream::stream_data()
00286 {
00287         while (!eof())
00288         {
00289                 int result=ogg_stream_packetout(&os,&op);
00290                 if (result > 0)
00291                 {
00292                         if(vorbis_synthesis(&vb,&op)==0) /* test for success! */
00293                                 vorbis_synthesis_blockin(&vd,&vb);
00294                         break;
00295                 }
00296                 
00297                 while (!eof())
00298                 {
00299                         int result = ogg_sync_pageout(&oy,&og);
00300                         if (result == -1) continue; // corrupt data at this page position. Read next.
00301                         if (result == 0) // need more data
00302                         {
00303                                 char *buffer=ogg_sync_buffer(&oy,4096);
00304                                 int bytes=input->read(buffer,4096);
00305                                 ogg_sync_wrote(&oy,bytes);
00306                                 if (bytes==0)
00307                                 {
00308                                         stream_eof = true;
00309                                         return;
00310                                 }
00311                         }
00312                         else
00313                         {
00314                                 ogg_stream_pagein(&os,&og);
00315                                 break;
00316                         }
00317                 }
00318         }
00319 }
00320         
00321 int CL_VorbisStream::get_frequency() const
00322 {
00323         return vi.rate;
00324 }
00325 
00326 SoundFormat CL_VorbisStream::get_format() const
00327 {
00328         return (vi.channels == 2) ? sf_16bit_signed_stereo : sf_16bit_signed;
00329 }

Generated at Wed Apr 4 19:54:04 2001 for ClanLib by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001