pipe.cpp Source File

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 - 2003 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 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.1.1.1 2003/12/08 12:20:33 jaromil Exp $"
    00024
    00025 */
    00026
    00027 #include <iostream>
    00028 #include <stdlib.h>
    00029 #include <audioproc.h>
    00030 #include <pipe.h>
    00031 #include <jutils.h>
    00032 #include <config.h>
    00033
    00034
    00035 #define MIN(a,b) (a<=b) ? a : b;
    00036
    00037 #define _SIZE(val) \
    00038   int 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(__size); \
    00046   val = ((char*)bufferEnd-(char*)buffer)-__size;
    00047
    00048 /*
    00049   start is a pointer to the first character that goes out
    00050   end is a pointer to the last character to go out
    00051 */
    00052
    00053 Pipe::Pipe(int size) {
    00054   func("Pipe::Pipe(%i)",size);
    00055   pipesize = size;
    00056   buffer = malloc(pipesize);
    00057   if(!buffer)
    00058     error("FATAL: can't allocate %i bytes buffer for audio Pipe: %s",
    00059           pipesize, strerror(errno));
    00060   bufferEnd=(char*)buffer+size;
    00061   end=start=buffer;
    00062   blocking = true;
    00063   _thread_init();
    00064   unlock();
    00065 }
    00066
    00067 Pipe::~Pipe() {
    00068   func("Pipe::~Pipe : freeing %p",buffer);
    00069   lock();
    00070   free(buffer);
    00071   unlock();
    00072   //  _thread_destroy();
    00073 }
    00074
    00075
    00076 int Pipe::read_float_intl(int samples, float *buf, int channels) {
    00077   lock();
    00078   _SIZE(buffered);
    00079   int c, cc;
    00080   int length = samples<<2;
    00081   float *pp = buf;
    00082
    00083   if (buffered<length) {
    00084     //    func("Pipe::read_float(%i,%p) : only %i bytes in the pipe",
    00085     //          samples,buf,buffered);
    00086     unlock();
    00087     return -1;
    00088   }
    00089
    00090   int origLength=length;
    00091
    00092   while (buffered && length)    {
    00093
    00094     /* |buffer*****|end-----------|start********|bufferEnd
    00095        |buffer-----|start*********|end----------|bufferEnd */
    00096
    00097     int len = MIN(length,buffered);
    00098
    00099     int currentBlockSize = (char*)bufferEnd-(char*)start;
    00100     currentBlockSize=MIN(currentBlockSize,len);
    00101
    00102     /* fill */
    00103     cc = currentBlockSize; //>>2 QUAAA
    00104     switch(channels) {
    00105     case 1:
    00106       for(c=0; c<cc; c++)
    00107         pp[c] = (((IN_DATATYPE*)start)[c*2] +
    00108                  ((IN_DATATYPE*)start)[c*2+1]) / 65536.0f; // /2 /32768.0f
    00109       break;
    00110     case 2:
    00111       for(c=0; c<cc; c++) {
    00112         //      pp[c*2] = ((IN_DATATYPE*)start)[c*2] /32768.0f;
    00113         //      pp[c*2+1] = ((IN_DATATYPE*)start)[c*2+1] /32768.0f;
    00114         pp[c] = ((IN_DATATYPE*)start)[c] / 32768.0f;
    00115       }
    00116       break;
    00117     default: break;
    00118     }
    00119     /* --- */
    00120
    00121     (char*)start += currentBlockSize;
    00122     len -= currentBlockSize;
    00123     (char*)pp += currentBlockSize;
    00124     length -= currentBlockSize;
    00125     if ((end!=buffer) && (start==bufferEnd))
    00126       start = buffer;
    00127
    00128     if (len) { /* short circuit */
    00129
    00130       /* fill */
    00131       cc = len; // >>2 QUAAA
    00132     switch(channels) {
    00133     case 1:
    00134       for(c=0; c<cc; c++)
    00135         pp[c] = (((IN_DATATYPE*)start)[c*2] +
    00136                  ((IN_DATATYPE*)start)[c*2+1]) / 65536.0f; // /2 /32768.0f
    00137       break;
    00138     case 2:
    00139       for(c=0; c<cc; c++) {
    00140         //      pp[c*2] = ((IN_DATATYPE*)start)[c*2] /32768.0f;
    00141         //      pp[c*2+1] = ((IN_DATATYPE*)start)[c*2+1] /32768.0f;
    00142         pp[c] = ((IN_DATATYPE*)start)[c] / 32768.0f;
    00143       }
    00144       break;
    00145     default: break;
    00146     }
    00147     /* --- */
    00148
    00149     (char*)pp += len;
    00150     (char*)start += len;
    00151     length -= len;
    00152     if ((end!=buffer) && (start==bufferEnd))
    00153       start = buffer;
    00154     }
    00155   }
    00156
    00157   unlock();
    00158   return (origLength-length)>>2;
    00159 }
    00160
    00161
    00162
    00163 /* this takes SAMPLES, they can be stereo or mono
    00164    mono will be averaged between the two channels
    00165    it is supposed that the pipes always contains 16bit STEREO (length = samples<<2)
    00166
    00167    RETURNS: samples read
    00168  */
    00169 int Pipe::read_float_bidi(int samples, float **buf, int channels) {
    00170   lock();
    00171
    00172   _SIZE(buffered);
    00173
    00174   /* if nothing is in, returns -1 */
    00175   if(!buffered) {
    00176     unlock();
    00177     func("Pipe:read_float_bidi(%i,%p,%i) : nothing in the pipe",
    00178          samples, buf, channels);
    00179     return -1;
    00180   }
    00181
    00182   int c, cc;
    00183   int length = samples<<2;
    00184   float **pp = buf;
    00185
    00186   if (buffered<length)
    00187     if(blocking) {
    00188       unlock();
    00189       func("Pipe::read_float_bidi(%i,%p,%i) : only %i bytes in the pipe",
    00190            samples,buf,channels,buffered);
    00191       return -1;
    00192     } else
    00193       length = buffered;
    00194
    00195   int origLength=length;
    00196
    00197   while (buffered && length)    {
    00198
    00199     /* |buffer*****|end-----------|start********|bufferEnd
    00200        |buffer-----|start*********|end----------|bufferEnd */
    00201
    00202     int len = MIN(length,buffered);
    00203
    00204     int currentBlockSize = (char*)bufferEnd-(char*)start;
    00205     currentBlockSize=MIN(currentBlockSize,len);
    00206
    00207     /* fill */
    00208     cc = currentBlockSize>>2;
    00209     switch(channels) {
    00210     case 1:
    00211       for(c=0; c<cc; c++)
    00212         pp[0][c] = (((IN_DATATYPE*)start)[c*2] +
    00213                     ((IN_DATATYPE*)start)[c*2+1]) / 65536.0f; // /2 /32768.0f
    00214       break;
    00215     case 2:
    00216       for(c=0; c<cc; c++) {
    00217         pp[0][c] = ((IN_DATATYPE*)start)[c*2] /32768.0f;
    00218         pp[1][c] = ((IN_DATATYPE*)start)[c*2+1] /32768.0f;
    00219       }
    00220       break;
    00221     default:
    00222       error("Pipe:read_float_bidi doesn't supports %i channels",channels);
    00223       break;
    00224     }
    00225     /* --- */
    00226
    00227     (char*)start += currentBlockSize;
    00228     len -= currentBlockSize;
    00229     (char*)pp += currentBlockSize;
    00230     length -= currentBlockSize;
    00231     if ((end!=buffer) && (start==bufferEnd))
    00232       start = buffer;
    00233
    00234     if (len) { /* short circuit */
    00235
    00236       /* fill */
    00237       cc = len>>2;
    00238       switch(channels) {
    00239       case 1:
    00240         for(c=0; c<cc; c++)
    00241           pp[0][c] = (((IN_DATATYPE*)start)[c*2] +
    00242                       ((IN_DATATYPE*)start)[c*2+1]) / 65536.0f; // /2 /32768.0f
    00243         break;
    00244       case 2:
    00245         for(c=0; c<cc; c++) {
    00246           pp[0][c] = ((IN_DATATYPE*)start)[c*2] /32768.0f;
    00247           pp[1][c] = ((IN_DATATYPE*)start)[c*2+1] /32768.0f;
    00248         }
    00249         break;
    00250       default:
    00251         error("Pipe:read_float_bidi doesn't supports %i channels",channels);
    00252         break;
    00253       }
    00254       /* --- */
    00255
    00256       (char*)pp += len;
    00257       (char*)start += len;
    00258       length -= len;
    00259       if ((end!=buffer) && (start==bufferEnd))
    00260         start = buffer;
    00261     }
    00262   }
    00263
    00264   unlock();
    00265   return (origLength-length)>>2;
    00266 }
    00267
    00268
    00269 void Pipe::block(bool val) {
    00270   lock();
    00271   blocking = val;
    00272   unlock();
    00273 }
    00274
    00275
    00276 int Pipe::mix16stereo(int samples, int32_t *mix) {
    00277   lock();
    00278   /* int buffered = size(); */
    00279   _SIZE(buffered);
    00280   int c, cc;
    00281
    00282   int length = samples<<2;
    00283   int32_t *pp = mix;
    00284
    00285   //  if (!buffered) return -1;
    00286
    00287   if (buffered<length) {
    00288     //    func("Pipe::mix16stereo(%i,%p) : only %i bytes in the pipe",
    00289     //    samples,mix,buffered);
    00290     unlock();
    00291     return -1;
    00292   }
    00293
    00294   int origLength=length;
    00295
    00296   while (buffered && length)    {
    00297
    00298     /* |buffer*****|end-----------|start********|bufferEnd
    00299        |buffer-----|start*********|end----------|bufferEnd */
    00300
    00301     int len = MIN(length,buffered);
    00302
    00303     int currentBlockSize = (char*)bufferEnd-(char*)start;
    00304     currentBlockSize=MIN(currentBlockSize,len);
    00305
    00306     /* mix */
    00307     cc = currentBlockSize>>1;
    00308     for(c=0; c<cc ;c++)
    00309       pp[c] += (int32_t) ((IN_DATATYPE*)start)[c];
    00310     /* --- */
    00311
    00312     (char*)start += currentBlockSize;
    00313     len -= currentBlockSize;
    00314     (char*)pp += currentBlockSize;
    00315     length -= currentBlockSize;
    00316     if ((end!=buffer) && (start==bufferEnd))
    00317       start = buffer;
    00318
    00319     if (len) { /* short circuit */
    00320
    00321       /* mix */
    00322       cc = len>>1;
    00323       for(c=0; c<cc ;c++)
    00324         pp[c] += (int) ((IN_DATATYPE*)start)[c];
    00325       /* --- */
    00326
    00327       (char*)pp += len;
    00328       (char*)start += len;
    00329       length -= len;
    00330       if ((end!=buffer) && (start==bufferEnd))
    00331         start = buffer;
    00332     }
    00333   }
    00334
    00335   unlock();
    00336   return origLength-length;
    00337 }
    00338
    00339 int Pipe::read(int length, void *data) {
    00340   lock();
    00341
    00342   _SIZE(buffered);
    00343
    00344   /* if nothing is in, returns -1 */
    00345   if(!buffered) {
    00346     unlock();
    00347     return -1;
    00348   }
    00349
    00350   /* if less than desired is in, then
    00351      (blocking) returns -1
    00352      (non blocking) returns what's available */
    00353   if (buffered<length)
    00354     if(blocking) {
    00355       unlock();
    00356       return -1;
    00357     } else
    00358       length = buffered;
    00359
    00360
    00361   int origLength=length;
    00362
    00363   while (buffered && length)    {
    00364
    00365     /* |buffer*****|end-----------|start********|bufferEnd
    00366        |buffer-----|start*********|end----------|bufferEnd */
    00367
    00368     int len = MIN(length,buffered);
    00369
    00370     int currentBlockSize = (char*)bufferEnd-(char*)start;
    00371     currentBlockSize=MIN(currentBlockSize,len);
    00372     /* fill */
    00373     memcpy(data, start, currentBlockSize);
    00374
    00375     (char*)start += currentBlockSize;
    00376     len -= currentBlockSize;
    00377     (char*)data += currentBlockSize;
    00378     length -= currentBlockSize;
    00379     if ((end!=buffer) && (start==bufferEnd))
    00380       start = buffer;
    00381
    00382     if (len) { /* short circuit */
    00383       memcpy(data, start, len);
    00384       (char*)data += len;
    00385       (char*)start += len;
    00386       length -= len;
    00387       if ((end!=buffer) && (start==bufferEnd))
    00388         start = buffer;
    00389     }
    00390   }
    00391
    00392   unlock();
    00393   return origLength-length;
    00394 }
    00395
    00396 int Pipe::write(int length, void *data) {
    00397   int spc;
    00398   lock();
    00399
    00400   _SPACE(spc);
    00401   if (length>(spc-1)) {
    00402     //    warning("Pipe::write(%i,%p) : not enough space in the pipe (spc=%i)",length,data,spc);
    00403 //    fprintf(stderr,".");
    00404     unlock();
    00405     return -1;
    00406   }
    00407
    00408   int origLength=length;
    00409
    00410   while (length) {
    00411
    00412     /* |buffer-----|end***********|start--------|bufferEnd
    00413        |buffer*****|start---------|end**********|bufferEnd */
    00414     //    _SPACE(spc);
    00415     int len=MIN(length, spc-1);
    00416
    00417     int currentBlockSize = (char*)bufferEnd-(char*)end;
    00418     currentBlockSize=MIN(currentBlockSize, len);
    00419     ::memcpy(end, data, currentBlockSize);
    00420
    00421     (char*)end += currentBlockSize;
    00422
    00423     len -= currentBlockSize;
    00424
    00425     (char*)data += currentBlockSize;
    00426     length -= currentBlockSize;
    00427     if ((start!=buffer) && (end==bufferEnd))
    00428       end = buffer;
    00429
    00430     if (len) { // short circuit
    00431       ::memcpy(end, data, len);
    00432       (char*)data += len;
    00433       (char*)end += len;
    00434       length -= len;
    00435
    00436       if ((start!=buffer) && (end==bufferEnd))
    00437         end = buffer;
    00438     }
    00439   }
    00440   unlock();
    00441   return origLength-length;
    00442 }
    00443
    00444 // |buffer******|end--------------|start**************|bufferEnd
    00445 // |buffer-----|start**************|end---------------|bufferEnd
    00446 int Pipe::size() {
    00447   /* size macro allocates the result variable by itself */
    00448   lock();
    00449   _SIZE(res);
    00450   unlock();
    00451   return res;
    00452 }
    00453
    00454 // |buffer------|end**************|start--------------|bufferEnd
    00455 // |buffer*****|start--------------|end***************|bufferEnd
    00456 int Pipe::space() {
    00457   int res;
    00458   lock();
    00459   _SPACE(res);
    00460   unlock();
    00461   return res;
    00462 }
    00463
    00464 void Pipe::flush() {
    00465   lock();
    00466   bufferEnd=(char*)buffer+pipesize;
    00467   end=start=buffer;
    00468   unlock();
    00469 }
    00470
    00471 void Pipe::flush(int bytes) {
    00472   lock();
    00473   void *temp = malloc(bytes);
    00474   read(bytes, temp);
    00475   free(temp);
    00476   unlock();
    00477 }