- -( dyne // software :: culture :: events :: tazebao :: discussion :: museum \\ freaknet )- -
 
Main Page | Modules | Class Hierarchy | Class List | File List | Class Members | File Members

pipe.cpp

Go to the documentation of this file.
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.9 2005/04/21 02:58:09 xant Exp $"
00024 
00025 */
00026 
00027 #include <iostream>
00028 #include <stdlib.h>
00029 #include <math.h>
00030 #include <errno.h>
00031 
00032 #include <audioproc.h>
00033 #include <pipe.h>
00034 #include <jutils.h>
00035 #include <config.h>
00036 
00037 
00038 #define MIN(a,b) (a<=b) ? a : b; 
00039 
00040 #define _SIZE(val) \
00041   if ((char*)end > (char*)start) \
00042     val = (char*)end-(char*)start; \
00043   else  \
00044     val = ((char*)bufferEnd-(char*)start)+((char*)end-(char*)buffer);
00045 
00046 #define _SPACE(val) \
00047   _SIZE(val); \
00048   val = ((char*)bufferEnd-(char*)buffer)-val;
00049 
00050 // COPY AND MIX CALLBACKS
00051 // they provide function that are moving data
00052 // handling it in different ways. it is an optimization when we do
00053 // conversions while copying the buffer around, or mixing it directly
00054 // from the pipe to a buffer.
00055 
00056 // samples are double if stereo (1 sample is only left or right)
00057 // multiplying them by the samplesize we can obtain sizes in bytes
00058 
00059 static inline void copy_byte(void *dst, void *src, int samples) {
00060   memcpy(dst,src,samples);
00061   }
00062 
00063 static inline void copy_int16_to_float(void *dst, void *src, int samples) {
00064   register int c;
00065   for( c = samples; c>0 ; c-- ) {
00066     ((float*)dst)[c] = ((int16_t*)src)[c] / 32768.0f;
00067   }
00068 }
00069 
00070 static inline void copy_float_to_int16(void *dst, void *src, int samples) {
00071   register int c;
00072   for( c = samples; c>0 ; c-- ) {
00073     ((int16_t*)dst)[c] = (int16_t) lrintf( ((float*)src)[c] );
00074   }
00075 }
00076 
00077 static inline void mix_int16_to_int32(void *dst, void *src, int samples) {
00078   register int c;
00079   for( c = samples ; c>0 ; c-- ) {
00080     ((int32_t*)dst)[c]
00081       +=
00082       ((int16_t*)src)[c];
00083   }
00084 }
00085 
00087 // // this is also a list for the available types
00088 
00089 static struct pipe_copy_list callbacks[] = {
00090   { "copy_byte", copy_byte, 1, 1 },
00091   { "copy_int16_to_float", copy_int16_to_float, sizeof(int16_t), sizeof(float) },
00092   { "copy_float_to_int16", copy_float_to_int16, sizeof(float), sizeof(int16_t) },
00093   { "mix_int16_to_int32", mix_int16_to_int32, sizeof(int16_t), sizeof(int32_t) },
00094   { 0, 0 }
00095 };
00096 
00097 /*
00098   start is a pointer to the first character that goes out
00099   end is a pointer to the last character to go out
00100 */
00101 
00102 bool Pipe::set_input_type(char *name) {
00103   int c;
00104   for(c=0 ; callbacks[c].callback ; c++) {
00105     if(strcasecmp(name,callbacks[c].name)==0) {
00106       write_copy_cb = &callbacks[c];
00107       return true;
00108     }
00109   }
00110   error("can't set input type \"%s\" on pipe",name);
00111   return false;
00112 }
00113 
00114 bool Pipe::set_output_type(char *name) {
00115   int c;
00116   for(c=0 ; callbacks[c].callback ; c++) {
00117     if(strcasecmp(name,callbacks[c].name)==0) {
00118       read_copy_cb = &callbacks[c];
00119       return true;
00120     }
00121   }
00122   error("can't set output type \"%s\" on pipe",name);
00123   return false;
00124 }
00125 
00126 
00127 Pipe::Pipe(int size) {
00128   func("Pipe::Pipe(%i)",size);
00129   pipesize = size;
00130   buffer = calloc(pipesize, 1);
00131   if(!buffer)
00132     error("FATAL: can't allocate %i bytes buffer for audio Pipe: %s",
00133           pipesize, strerror(errno));
00134   bufferEnd=(char*)buffer+size;
00135   end=start=buffer;
00136 
00137   // set default types to simple bytes
00138   set_input_type("copy_byte");
00139   set_output_type("copy_byte");
00140   // set blocking timeout (ttl) defaults
00141   read_blocking = false;
00142   read_blocking_time = 20000;
00143   write_blocking = false;
00144   write_blocking_time = 20000;
00145 
00146   _thread_init();
00147   //unlock();
00148   
00149 }
00150 
00151 Pipe::~Pipe() {
00152   func("Pipe::~Pipe : freeing %p",buffer);
00153   lock();
00154   free(buffer);
00155   unlock();
00156   //  _thread_destroy();
00157 }
00158 
00159 void Pipe::set_block(bool input, bool output) {
00160   lock();
00161   write_blocking = input;
00162   read_blocking = output;
00163   unlock();
00164 }
00165 
00166 void Pipe::set_block_timeout(int input, int output) {
00167   lock();
00168   write_blocking_time = input;
00169   read_blocking_time = output;
00170   unlock();
00171 }
00172     
00173 int Pipe::read(int length, void *data) {
00174   int worklen, origlen, truelen;
00175   int blk, len, buffered, buffered_bytes;
00176   int ttl = 0;
00177   
00178   if(read_blocking) ttl = read_blocking_time;
00179 
00180   lock();
00181 
00182   _SIZE(buffered_bytes);
00183   buffered = buffered_bytes 
00184     / read_copy_cb->src_samplesize;
00185   truelen = length;
00186 
00187 
00188   while(buffered<length) {
00189     
00190   /* if less than desired is in, then 
00191      (blocking) waits
00192      (non blocking) returns what's available */
00193     if(read_blocking) {
00194       unlock();
00195       if(!ttl) return -1;
00196       jsleep(0,100); ttl -= 10;
00197       lock();
00198       _SIZE(buffered_bytes);
00199       buffered = buffered_bytes 
00200         / read_copy_cb->src_samplesize;
00201     } else {
00202     // nothing in the pipe
00203       if(!buffered) {
00204         unlock();
00205         return 0;
00206       } else
00207         truelen = buffered;
00208       break;
00209     }
00210   }
00211 
00212   origlen = worklen = truelen * read_copy_cb->src_samplesize;
00213 
00214   while (worklen) {
00215                                 
00216     /* |buffer*****|end-----------|start********|bufferEnd
00217        |buffer-----|start*********|end----------|bufferEnd */
00218     
00219     len = MIN(worklen,buffered_bytes);
00220     
00221     blk = ((char*)bufferEnd - (char*)start);
00222 
00223     blk=MIN(blk,len);
00224     
00225     /* fill */
00226     (*read_copy_cb->callback)
00227       (data, start,
00228        blk / read_copy_cb->src_samplesize);
00229         /* blank just copied bytes */
00230         memset(start,0,blk / read_copy_cb->src_samplesize);
00231     
00232     (char*)start += blk;
00233     len -= blk;
00234     (char*)data += blk;
00235     worklen -= blk;
00236     if ((end!=buffer) && (start==bufferEnd))
00237       start = buffer;
00238     
00239     if (len) { /* short circuit */
00240 
00241       (*read_copy_cb->callback)
00242         (data, start,
00243          len / read_copy_cb->src_samplesize);
00244       
00245           /* blank just copied bytes */
00246           memset(start,0,len / read_copy_cb->src_samplesize);
00247       (char*)data += len;
00248       (char*)start += len;
00249       worklen -= len;
00250       if ((end!=buffer) && (start==bufferEnd))
00251         start = buffer;
00252     }
00253   }
00254   
00255   unlock();
00256   return ( (origlen-worklen)/read_copy_cb->src_samplesize );
00257 }
00258 
00259 int Pipe::write(int length, void *data) {
00260   int worklen, origlen, space_samples;
00261   int space_bytes, len, truelen, blk;
00262   int ttl = 0;
00263 
00264   if(write_blocking) ttl = write_blocking_time;
00265 
00266   lock();
00267 
00268   _SPACE(space_bytes);
00269   space_samples = (space_bytes / write_copy_cb->dst_samplesize);
00270   truelen = length;
00271 
00272   while(length > space_samples) {
00273 
00274     // timeout block mechanism
00275     if(write_blocking) {
00276       unlock();
00277       if(!ttl) return -1; // block timeout
00278       jsleep(0,100); ttl -= 10;
00279       lock();
00280       // recalculate actual sizes
00281       _SPACE(space_bytes);
00282       space_samples = space_bytes
00283         / write_copy_cb->dst_samplesize;
00284 
00285     } else { // non-block
00286 
00287       if(!space_bytes) {
00288         unlock();
00289         return 0; // nothing in the pipe
00290       } else
00291         // write what's available
00292         truelen = space_samples;
00293       break;
00294     }
00295   }
00296   
00297   origlen = worklen = truelen * write_copy_cb->dst_samplesize;
00298 
00299   while (worklen) {
00300     
00301     /* |buffer-----|end***********|start--------|bufferEnd
00302        |buffer*****|start---------|end**********|bufferEnd */
00303     len=MIN(worklen, space_bytes);
00304     
00305     blk = (char*)bufferEnd-(char*)end;
00306     blk = MIN(blk, len);
00307     
00308     /* fill */
00309     (*write_copy_cb->callback)
00310       (end, data,
00311        blk / write_copy_cb->dst_samplesize);
00312 
00313       (char*)end += blk;
00314       len -= blk;
00315       (char*)data += blk;
00316       worklen -= blk;
00317       if ((start!=buffer)
00318           && (end==bufferEnd))
00319         end = buffer;
00320                 
00321     if (len) { // short circuit         
00322 
00323       (*write_copy_cb->callback)
00324         (end, data,
00325          len / write_copy_cb->dst_samplesize);
00326 
00327       (char*)data += len;
00328       (char*)end += len;
00329       worklen -= len;
00330       
00331       if ((start!=buffer)
00332           && (end==bufferEnd))
00333         end = buffer;
00334     }
00335   }
00336   _SPACE(space_bytes);
00337   unlock();
00338   return ((origlen-worklen) / write_copy_cb->dst_samplesize);
00339 }
00340 
00341 // |buffer******|end--------------|start**************|bufferEnd
00342 // |buffer-----|start**************|end---------------|bufferEnd
00343 int Pipe::size() {
00344   int res;
00345   /* size macro allocates the result variable by itself */
00346   lock();
00347   _SIZE(res);
00348   unlock();
00349 
00350   return res;
00351 }
00352 
00353 // |buffer------|end**************|start--------------|bufferEnd
00354 // |buffer*****|start--------------|end***************|bufferEnd
00355 int Pipe::space() {
00356   int res;
00357   lock();
00358   _SPACE(res);
00359   unlock();
00360 
00361   return res;
00362 }
00363 
00364 void Pipe::flush() {
00365   lock();
00366   bufferEnd=(char*)buffer+pipesize;
00367   end=start=buffer;
00368   unlock();
00369 }
00370 
00371 void Pipe::flush(int bytes) {
00372   lock();
00373   void *temp = malloc(bytes);
00374   read(bytes, temp);
00375   free(temp);
00376   unlock();
00377 }