Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

wvspeex.cc

Go to the documentation of this file.
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  *
00005  * Provides a WvEncoder abstraction for the Speex audio packet format.
00006  * suitable for encoding voice at low bitrates.
00007  *
00008  * Only monaural audio is supported for now.
00009  */
00010 #include "wvspeex.h"
00011 #include <speex.h>
00012 #include <speex_header.h>
00013 
00014 /**
00015  * Returns the SpeexMode to use for a given sampling rate.
00016  * "modeid" is the suggested mode
00017  * "samplingrate" is the sampling rate
00018  */
00019 static SpeexMode *get_speex_mode(WvSpeex::CodecMode modeid,
00020     int samplingrate)
00021 {
00022     // use the suggested mode if it is valid
00023     if (modeid >= 0 && modeid < SPEEX_NB_MODES)
00024         return speex_mode_list[modeid];
00025 
00026     // otherwise determine a suitable default
00027     SpeexMode *mode;
00028     assert(samplingrate <= 48000 || ! "sampling rate too high");
00029     assert(samplingrate >= 6000 || ! "sampling rate too low");
00030     if (samplingrate > 25000)
00031         mode = & speex_uwb_mode;
00032     else if (samplingrate > 12500)
00033         mode = & speex_wb_mode;
00034     else
00035         mode = & speex_nb_mode;
00036     return mode;
00037 }
00038 
00039 
00040 
00041 /***** WvSpeexEncoder *****/
00042 
00043 WvSpeexEncoder::WvSpeexEncoder(
00044     const WvSpeex::BitrateSpec &bitratespec,
00045     int samplingrate, unsigned int channels, WvSpeex::CodecMode modeid,
00046     int complexity) :
00047     spxstate(NULL), spxbits(NULL), spxmode(NULL),
00048     _channels(channels), _samplesperframe(0)
00049 {
00050     // init encoder
00051     spxmode = get_speex_mode(modeid, samplingrate);
00052     spxstate = speex_encoder_init(spxmode);
00053     if (! spxstate)
00054     {
00055         seterror("error during speex_encoder_init");
00056         return;
00057     }
00058     spxbits = new SpeexBits;
00059     speex_bits_init(spxbits);
00060     
00061     // set sampling rate
00062     speex_encoder_ctl(spxstate, SPEEX_SET_SAMPLING_RATE, &samplingrate);
00063 
00064     // set the complexity
00065     if (complexity != WvSpeex::DEFAULT_COMPLEXITY)
00066         speex_encoder_ctl(spxstate, SPEEX_SET_COMPLEXITY, &complexity);
00067     
00068     // init bitrate management
00069     switch (bitratespec.mode)
00070     {
00071         case WvSpeex::BitrateSpec::VBR_QUALITY:
00072         {
00073             int enable = 1;
00074             speex_encoder_ctl(spxstate, SPEEX_SET_VBR, &enable);
00075             float quality = bitratespec.quality_index * 10;
00076             speex_encoder_ctl(spxstate, SPEEX_SET_VBR_QUALITY,
00077                 &quality);
00078             break;
00079         }
00080 
00081         case WvSpeex::BitrateSpec::CBR_QUALITY:
00082         {
00083             int quality = int(bitratespec.quality_index * 10);
00084             speex_encoder_ctl(spxstate, SPEEX_SET_QUALITY,
00085                 &quality);
00086             break;
00087         }
00088 
00089         case WvSpeex::BitrateSpec::CBR_BITRATE:
00090         {
00091             int bitrate = bitratespec.nominal_bitrate;
00092             speex_encoder_ctl(spxstate, SPEEX_SET_BITRATE,
00093                 &bitrate);
00094             break;
00095         }
00096     }
00097 
00098     // cache frame size since we use it often
00099     speex_encoder_ctl(spxstate, SPEEX_GET_FRAME_SIZE,
00100         &_samplesperframe);
00101 }
00102 
00103 
00104 WvSpeexEncoder::~WvSpeexEncoder()
00105 {
00106     speex_encoder_destroy(spxstate);
00107     speex_bits_destroy(spxbits);
00108     delete spxbits;
00109 }
00110 
00111 
00112 bool WvSpeexEncoder::_typedencode(IBuffer &inbuf, OBuffer &outbuf,
00113     bool flush)
00114 {
00115     if (! flushspxbits(outbuf))
00116         return false;
00117     for (;;)
00118     {
00119         size_t avail = inbuf.used();
00120         if (avail == 0)
00121             return true;
00122         if (avail < size_t(_samplesperframe))
00123             return ! flush; // not enough data
00124         speex_encode(spxstate, const_cast<float*>(
00125             inbuf.get(_samplesperframe)), spxbits);
00126         if (! flushspxbits(outbuf))
00127             return false;
00128         if (! flush)
00129             return true;
00130     }
00131 }
00132 
00133 
00134 bool WvSpeexEncoder::_typedfinish(OBuffer &outbuf)
00135 {
00136     return flushspxbits(outbuf);
00137 }
00138 
00139 
00140 bool WvSpeexEncoder::flushspxbits(OBuffer &outbuf)
00141 {
00142     size_t needed = speex_bits_nbytes(spxbits);
00143     if (needed == 0)
00144         return true;
00145 
00146     while (needed != 0)
00147     {
00148         size_t avail = outbuf.optallocable();
00149         if (avail == 0)
00150             return false;
00151         if (avail > needed)
00152             avail = needed;
00153         speex_bits_write(spxbits, reinterpret_cast<char*>(
00154             outbuf.alloc(avail)), avail);
00155         needed -= avail;
00156     }
00157     // must reset before the next frame can be created
00158     speex_bits_reset(spxbits);
00159     return true;
00160 }
00161 
00162 
00163 int WvSpeexEncoder::samplingrate() const
00164 {
00165     int rate;
00166     speex_encoder_ctl(const_cast<void*>(spxstate),
00167         SPEEX_GET_SAMPLING_RATE, &rate);
00168     return rate;
00169 }
00170 
00171 
00172 WvSpeex::CodecMode WvSpeexEncoder::mode() const
00173 {
00174     return WvSpeex::CodecMode(spxmode->modeID);
00175 }
00176 
00177 
00178 bool WvSpeexEncoder::vbr() const
00179 {
00180     int enabled;
00181     speex_encoder_ctl(const_cast<void*>(spxstate),
00182         SPEEX_GET_VBR, &enabled);
00183     return enabled;
00184 }
00185 
00186 
00187 int WvSpeexEncoder::nominalbitrate() const
00188 {
00189     int bitrate;
00190     speex_encoder_ctl(const_cast<void*>(spxstate),
00191         SPEEX_GET_BITRATE, &bitrate);
00192     return bitrate;
00193 }
00194 
00195 
00196 
00197 /***** WvSpeexDecoder *****/
00198 
00199 WvSpeexDecoder::WvSpeexDecoder(int samplingrate, unsigned int channels,
00200     WvSpeex::CodecMode modeid) :
00201     _samplingrate(samplingrate), _channels(channels),
00202     spxstate(NULL), spxbits(NULL), spxmode(NULL),
00203     _samplesperframe(0)
00204 {
00205     // init decoder
00206     spxmode = get_speex_mode(modeid, samplingrate);
00207     spxstate = speex_decoder_init(spxmode);
00208     if (! spxstate)
00209     {
00210         seterror("error during speex_decoder_init");
00211         return;
00212     }
00213     spxbits = new SpeexBits;
00214     speex_bits_init(spxbits);
00215     
00216     // set sampling rate
00217     speex_decoder_ctl(spxstate, SPEEX_SET_SAMPLING_RATE,
00218         & samplingrate);
00219 
00220     // cache frame size since we use it often
00221     speex_decoder_ctl(spxstate, SPEEX_GET_FRAME_SIZE,
00222         &_samplesperframe);
00223 }
00224 
00225 
00226 WvSpeexDecoder::~WvSpeexDecoder()
00227 {
00228     speex_decoder_destroy(spxstate);
00229     speex_bits_destroy(spxbits);
00230     delete spxbits;
00231 }
00232 
00233 
00234 WvSpeex::CodecMode WvSpeexDecoder::mode() const
00235 {
00236     return WvSpeex::CodecMode(spxmode->modeID);
00237 }
00238 
00239 
00240 bool WvSpeexDecoder::postfilter() const
00241 {
00242     int enabled;
00243     speex_decoder_ctl(spxstate, SPEEX_GET_ENH, &enabled);
00244     return enabled;
00245 }
00246 
00247 
00248 void WvSpeexDecoder::setpostfilter(bool enable)
00249 {
00250     int enabled = enable ? 1 : 0;
00251     speex_decoder_ctl(spxstate, SPEEX_SET_ENH, &enabled);
00252 }
00253 
00254 
00255 bool WvSpeexDecoder::_typedencode(IBuffer &inbuf, OBuffer &outbuf,
00256     bool flush)
00257 {
00258     for (;;)
00259     {
00260         size_t avail = inbuf.used();
00261         if (avail == 0)
00262             return true;
00263         if (outbuf.free() < size_t(_samplesperframe))
00264             return false; // not enough room
00265 
00266         size_t skip = 0;
00267         if (avail > MAX_BYTES_PER_FRAME)
00268         {
00269             // packet is too large but try to decode some audio anyhow
00270             skip = avail - MAX_BYTES_PER_FRAME;
00271             avail -= skip;
00272         }
00273         speex_bits_read_from(spxbits, const_cast<char*>(
00274             reinterpret_cast<const char*>(inbuf.get(avail))), avail);
00275         float *outsamples = outbuf.alloc(_samplesperframe);
00276         int retval = speex_decode(spxstate, spxbits, outsamples);
00277         inbuf.skip(skip); // skip over bad data
00278         if (retval != 0)
00279             return false; // signal bad data but don't stop on error
00280         if (! flush)
00281             return true;
00282     }
00283 }
00284 
00285 
00286 bool WvSpeexDecoder::_typedfinish(OBuffer &outbuf)
00287 {
00288     return true;
00289 }
00290 
00291 
00292 bool WvSpeexDecoder::missing(OBuffer &outbuf)
00293 {
00294     if (! isok() || isfinished())
00295         return false;
00296     if (outbuf.free() < size_t(_samplesperframe))
00297         return false; // not enough room
00298     speex_decode(spxstate, NULL, outbuf.alloc(_samplesperframe));
00299     return true;
00300 }

Generated on Sat Feb 21 21:05:32 2004 for WvStreams by doxygen 1.3.5