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

pipe.cpp

00001 /*
00002   Copyright (c) 2001 Charles Samuels <charles@kde.org>
00003   Copyright (c) 2002 - 2004 Denis Rojo <jaromil@dyne.org>
00004   
00005 this pipe class was first written by Charles Samuels
00006 and then heavily mutilated and optimized by Denis "jaromil" Rojo
00007 
00008 This library is free software; you can redistribute it and/or
00009 modify it under the terms of the GNU Library General Public
00010 License as published by the Free Software Foundation; either
00011 version 2 of the License, or (at your option) any later version.
00012   
00013 This library is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 Library General Public License for more details.
00017    
00018 You should have received a copy of the GNU Library General Public License
00019 along with this library; see the file COPYING.LIB.  If not, write to
00020 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00021 Boston, MA 02111-1307, USA.
00022 
00023 "$Id: pipe.cpp,v 1.4 2004/12/13 00:26:37 jaromil Exp $"
00024 
00025 */
00026 
00027 #include <iostream>
00028 #include <stdlib.h>
00029 #include <errno.h>
00030 #include <audioproc.h>
00031 #include <pipe.h>
00032 #include <jutils.h>
00033 #include <config.h>
00034 
00035 
00036 #define MIN(a,b) (a<=b) ? a : b; 
00037 
00038 #define _SIZE(val) \
00039   if ((char*)end > (char*)start) \
00040     val = (char*)end-(char*)start; \
00041   else  \
00042     val = ((char*)bufferEnd-(char*)start)+((char*)end-(char*)buffer);
00043 
00044 #define _SPACE(val) \
00045   _SIZE(val); \
00046   val = ((char*)bufferEnd-(char*)buffer)-val;
00047 
00048 // COPY AND MIX CALLBACKS
00049 // they provide function that are moving data
00050 // handling it in different ways. it is an optimization when we do
00051 // conversions while copying the buffer around, or mixing it directly
00052 // from the pipe to a buffer.
00053 
00054 // samples are double if stereo (1 sample is only left or right)
00055 // multiplying them by the samplesize we can obtain sizes in bytes
00056 
00057 static inline void copy_byte(void *dst, void *src, int samples) {
00058   memcpy(dst,src,samples);
00059   }
00060 
00061 static inline void copy_int16_to_float(void *dst, void *src, int samples) {
00062   register int c;
00063   for( c = samples; c>0 ; c-- ) {
00064     ((float*)dst)[c] = ((int16_t*)src)[c] / 32768.0f;
00065   }
00066 }
00067 
00068 static inline void copy_float_to_int16(void *dst, void *src, int samples) {
00069   register int c;
00070   for( c = samples; c>0 ; c-- ) {
00071     ((int16_t*)dst)[c] = (int16_t) lrintf( ((float*)src)[c] );
00072   }
00073 }
00074 
00075 static inline void mix_int16_to_int32(void *dst, void *src, int samples) {
00076   register int c;
00077   for( c = samples ; c>0 ; c-- ) {
00078     ((int32_t*)dst)[c]
00079       +=
00080       ((int16_t*)src)[c];
00081   }
00082 }
00083 
00085 // // this is also a list for the available types
00086 
00087 static struct pipe_copy_list callbacks[] = {
00088   { "copy_byte", copy_byte, 1, 1 },
00089   { "copy_int16_to_float", copy_int16_to_float, sizeof(int16_t), sizeof(float) },
00090   { "copy_float_to_int16", copy_float_to_int16, sizeof(float), sizeof(int16_t) },
00091   { "mix_int16_to_int32", mix_int16_to_int32, sizeof(int16_t), sizeof(int32_t) },
00092   { 0, 0 }
00093 };
00094 
00095 /*
00096   start is a pointer to the first character that goes out
00097   end is a pointer to the last character to go out
00098 */
00099 
00100 bool Pipe::set_input_type(char *name) {
00101   int c;
00102   for(c=0 ; callbacks[c].callback ; c++) {
00103     if(strcasecmp(name,callbacks[c].name)==0) {
00104       write_copy_cb = &callbacks[c];
00105       return true;
00106     }
00107   }
00108   error("can't set input type \"%s\" on pipe",name);
00109   return false;
00110 }
00111 
00112 bool Pipe::set_output_type(char *name) {
00113   int c;
00114   for(c=0 ; callbacks[c].callback ; c++) {
00115     if(strcasecmp(name,callbacks[c].name)==0) {
00116       read_copy_cb = &callbacks[c];
00117       return true;
00118     }
00119   }
00120   error("can't set output type \"%s\" on pipe",name);
00121   return false;
00122 }
00123 
00124 
00125 Pipe::Pipe(int size) {
00126   func("Pipe::Pipe(%i)",size);
00127   pipesize = size;
00128   buffer = calloc(pipesize, 1);
00129   if(!buffer)
00130     error("FATAL: can't allocate %i bytes buffer for audio Pipe: %s",
00131           pipesize, strerror(errno));
00132   bufferEnd=(char*)buffer+size;
00133   end=start=buffer;
00134 
00135   // set default types to simple bytes
00136   set_input_type("copy_byte");
00137   set_output_type("copy_byte");
00138   // set blocking timeout (ttl) defaults
00139   read_blocking = false;
00140   read_blocking_time = 2000;
00141   write_blocking = false;
00142   write_blocking_time = 2000;
00143 
00144   _thread_init();
00145   //unlock();
00146   
00147 }
00148 
00149 Pipe::~Pipe() {
00150   func("Pipe::~Pipe : freeing %p",buffer);
00151   lock();
00152   free(buffer);
00153   unlock();
00154   //  _thread_destroy();
00155 }
00156 
00157 void Pipe::set_block(bool input, bool output) {
00158   lock();
00159   write_blocking = input;
00160   read_blocking = output;
00161   unlock();
00162 }
00163 
00164 void Pipe::set_block_timeout(int input, int output) {
00165   lock();
00166   write_blocking_time = input;
00167   read_blocking_time = output;
00168   unlock();
00169 }
00170     
00171 int Pipe::read(int length, void *data) {
00172   int worklen, origlen, truelen;
00173   int blk, len, buffered, buffered_bytes;
00174   int ttl = 0;
00175   
00176   if(read_blocking) ttl = read_blocking_time;
00177 
00178   lock();
00179 
00180   _SIZE(buffered_bytes);
00181   buffered = buffered_bytes 
00182     / read_copy_cb->src_samplesize;
00183   truelen = length;
00184 
00185 
00186   while(buffered<length) {
00187     
00188   /* if less than desired is in, then 
00189      (blocking) waits
00190      (non blocking) returns what's available */
00191     if(read_blocking) {
00192       unlock();
00193       if(!ttl) return -1;
00194       jsleep(0,10); ttl -= 10;
00195       lock();
00196       _SIZE(buffered_bytes);
00197       buffered = buffered_bytes 
00198         / read_copy_cb->src_samplesize;
00199     } else {
00200     // nothing in the pipe
00201       if(!buffered) {
00202         unlock();
00203         return 0;
00204       } else
00205         truelen = buffered;
00206       break;
00207     }
00208   }
00209 
00210   origlen = worklen = truelen * read_copy_cb->src_samplesize;
00211 
00212   while (worklen) {
00213                                 
00214     /* |buffer*****|end-----------|start********|bufferEnd
00215        |buffer-----|start*********|end----------|bufferEnd */
00216     
00217     len = MIN(worklen,buffered_bytes);
00218     
00219     blk = ((char*)bufferEnd - (char*)start);
00220 
00221     blk=MIN(blk,len);
00222     
00223     /* fill */
00224     (*read_copy_cb->callback)
00225       (data, start,
00226        blk / read_copy_cb->src_samplesize);
00227     
00228     (char*)start += blk;
00229     len -= blk;
00230     (char*)data += blk;
00231     worklen -= blk;
00232     if ((end!=buffer) && (start==bufferEnd))
00233       start = buffer;
00234     
00235     if (len) { /* short circuit */
00236 
00237       (*read_copy_cb->callback)
00238         (data, start,
00239          len / read_copy_cb->src_samplesize);
00240       
00241       (char*)data += len;
00242       (char*)start += len;
00243       worklen -= len;
00244       if ((end!=buffer) && (start==bufferEnd))
00245         start = buffer;
00246     }
00247   }
00248   
00249   unlock();
00250   return ( (origlen-worklen)/read_copy_cb->src_samplesize );
00251 }
00252 
00253 int Pipe::write(int length, void *data) {
00254   int worklen, origlen, space_samples;
00255   int space_bytes, len, truelen, blk;
00256   int ttl = 0;
00257 
00258   if(write_blocking) ttl = write_blocking_time;
00259 
00260   lock();
00261 
00262   _SPACE(space_bytes);
00263   space_samples = (space_bytes / write_copy_cb->dst_samplesize);
00264   truelen = length;
00265 
00266   while(length > space_samples) {
00267 
00268     // timeout block mechanism
00269     if(write_blocking) {
00270       unlock();
00271       if(!ttl) return -1; // block timeout
00272       jsleep(0,10); ttl -= 10; // wait 10 milliseconds
00273       lock();
00274       // recalculate actual sizes
00275       _SPACE(space_bytes);
00276       space_samples = space_bytes
00277         / write_copy_cb->dst_samplesize;
00278 
00279     } else { // non-block
00280 
00281       if(!space_bytes) {
00282         unlock();
00283         return 0; // nothing in the pipe
00284       } else
00285         // write what's available
00286         truelen = space_samples;
00287       break;
00288     }
00289   }
00290   
00291   origlen = worklen = truelen * write_copy_cb->dst_samplesize;
00292 
00293   while (worklen) {
00294     
00295     /* |buffer-----|end***********|start--------|bufferEnd
00296        |buffer*****|start---------|end**********|bufferEnd */
00297     len=MIN(worklen, space_bytes);
00298     
00299     blk = (char*)bufferEnd-(char*)end;
00300     blk = MIN(blk, len);
00301     
00302     /* fill */
00303     (*write_copy_cb->callback)
00304       (end, data,
00305        blk / write_copy_cb->dst_samplesize);
00306 
00307       (char*)end += blk;
00308       len -= blk;
00309       (char*)data += blk;
00310       worklen -= blk;
00311       if ((start!=buffer)
00312           && (end==bufferEnd))
00313         end = buffer;
00314                 
00315     if (len) { // short circuit         
00316 
00317       (*write_copy_cb->callback)
00318         (end, data,
00319          len / write_copy_cb->dst_samplesize);
00320 
00321       (char*)data += len;
00322       (char*)end += len;
00323       worklen -= len;
00324       
00325       if ((start!=buffer)
00326           && (end==bufferEnd))
00327         end = buffer;
00328     }
00329   }
00330   _SPACE(space_bytes);
00331   unlock();
00332   return ((origlen-worklen) / write_copy_cb->dst_samplesize);
00333 }
00334 
00335 // |buffer******|end--------------|start**************|bufferEnd
00336 // |buffer-----|start**************|end---------------|bufferEnd
00337 int Pipe::size() {
00338   int res;
00339   /* size macro allocates the result variable by itself */
00340   lock();
00341   _SIZE(res);
00342   unlock();
00343 
00344   return res;
00345 }
00346 
00347 // |buffer------|end**************|start--------------|bufferEnd
00348 // |buffer*****|start--------------|end***************|bufferEnd
00349 int Pipe::space() {
00350   int res;
00351   lock();
00352   _SPACE(res);
00353   unlock();
00354 
00355   return res;
00356 }
00357 
00358 void Pipe::flush() {
00359   lock();
00360   bufferEnd=(char*)buffer+pipesize;
00361   end=start=buffer;
00362   unlock();
00363 }
00364 
00365 void Pipe::flush(int bytes) {
00366   lock();
00367   void *temp = malloc(bytes);
00368   read(bytes, temp);
00369   free(temp);
00370   unlock();
00371 }

Generated on Thu Dec 16 12:28:21 2004 for MuSE by doxygen1.3