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

inchannels.cpp

00001 /* MuSE - Multiple Streaming Engine
00002  * Copyright (C) 2000-2002 Denis Roio aka jaromil <jaromil@dyne.org>
00003  *
00004  * This source code is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Public License as published 
00006  * by the Free Software Foundation; either version 2 of the License,
00007  * or (at your option) any later version.
00008  *
00009  * This source code is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00012  * Please refer to the GNU Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Public License along with
00015  * this source code; if not, write to:
00016  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  
00018 "$Id: inchannels.cpp,v 1.5 2004/04/04 23:07:24 pallotron Exp $"
00019  
00020  different classes for different IN channels
00021  they are instantiated and used by the Stream_mixer class (jmixer.cpp)
00022 
00023 */
00024 
00025 #include <iostream>
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <unistd.h>
00029 #include <string.h>
00030 #include <sys/types.h>
00031 #include <sys/wait.h>
00032 #include <signal.h>
00033 
00034 /* mixing and audioprocessing algorithms*/
00035 #include <audioproc.h>
00036 
00037 #include <jutils.h>
00038 #include <inchannels.h>
00039 #include <config.h>
00040 #include <generic.h>
00041 
00042 #ifdef HAVE_VORBIS
00043 #include <dec_ogg.h>
00044 #endif
00045 #ifdef HAVE_SNDFILE
00046 #include <dec_snd.h>
00047 #endif
00048 #include <dec_mp3.h>
00049 
00050 //#ifdef DEBUG
00051 #define PARADEC if(!dec) error("%s:%s %i :: decoder is NULL",__FILE__,__FUNCTION__,__LINE__);
00052 //#endif
00053 
00054 /* ----- Parent Class Channel ----- */
00055 
00056 typedef void* (kickoff)(void*);
00057 
00058 Channel::Channel() {
00059   func("Channel::Channel()");
00060   volume = 1.0;
00061   speed = 100;
00062   time.h = time.m = time.s = 0;
00063   position = time.f = 0.0;
00064   state = 0.0;
00065   playmode = PLAYMODE_PLAY;
00066   opened = false;
00067   on = false;
00068   update = false;
00069   running = false;
00070   quit = true;
00071 
00072   _thread_init();
00073   erbapipa = new Pipe(IN_PIPESIZE);
00074   playlist = new Playlist();
00075   dec = NULL;
00076   fill_prev_smp = true;
00077   lcd[0] = '\0';
00078 }
00079 
00080 Channel::~Channel() {
00081   func("Channel::~Channel()");
00082 
00083   /* paranoia */
00084   //stop();
00085   //  clean();
00086   quit = true;
00087   
00088   while(running) jsleep(0,20);
00089 
00090   /* clean up specific channel implementation */
00091 
00092   delete erbapipa;
00093   delete playlist;
00094   if(dec) delete dec;
00095 
00096   _thread_destroy();
00097 }
00098 
00099 void Channel::run() {
00100 
00101   IN_DATATYPE *buff; // pointer to buffers to pass them around
00102   lock();
00103   func("InChanThread! here i am");
00104   running = true;
00105   unlock();
00106   signal(); // signal to the parent thread we are born!
00107 
00108   quit = false;
00109 
00110   while(!quit) {
00111     
00112     if(on) {
00113       PARADEC
00114       dec->lock();
00115       /* now call get_audio() which
00116          returns the *IN_DATATYPE pointer to filled buffer
00117          setting up the following parameters:
00118          dec->state = 0.0-1.0 is the position of the stream
00119                       2.0 means end of the stream
00120                       3.0 means error decoding stream
00121          dec->frames  is updated with number of decoded 16bit frames (double if stereo)
00122          dec->samplerate and dec->channels tell about the audio format */
00123       buff = dec->get_audio();
00124       dec->unlock();
00125     /* then call resample() which sets up:
00126        samples = number of 44khz stereo samples
00127        and returns *IN_DATATYPE pointing to the resampled buffer */
00128       if(buff) {
00129         buff = resample(buff);
00130         /* at last pushes it up into the pipe
00131            bytes are samples<<2 being the audio 16bit stereo */
00132         while( erbapipa->write
00133                (samples<<2,buff) <0
00134                && !quit) jsleep(0,20);
00135         /* then calculates the position and time */
00136         if(dec->seekable) state = upd_time();
00137 
00138       } else /* if get_audio returns NULL then is eos or error */
00139         if(dec->eos) upd_eos();
00140         else if(dec->err) upd_err();
00141         else { /* should never be here */
00142           error("unknown state on %s channel",dec->name);
00143           report(); state = 0.0;
00144         } // if(buf) else      
00145 
00146     } else { // if(on)
00147 
00148       // just hang on
00149       jsleep(0,20);
00150       
00151     }
00152     
00153   } // while(!quit)
00154   running = false;
00155 }
00156 
00157 IN_DATATYPE *Channel::resample(IN_DATATYPE *audio) {
00158 
00159   /* there is no previous samples saved 
00160      fill in with the first */
00161   if(fill_prev_smp) {
00162     prev_smp[0] = audio[0];
00163     prev_smp[1] = audio[1];
00164     prev_smp[2] = audio[2];
00165     prev_smp[3] = audio[3];
00166     fill_prev_smp = false;
00167     //    erbapipa->flush();
00168   }
00169 
00170   frames = dec->frames;
00171   frames = (*munch)(buffo,audio,prev_smp,frames,volume);
00172   samples = frames/2; 
00173 
00174   /* save last part of the chunk
00175      for the next resampling */
00176   prev_smp[0] = audio[dec->frames-4];
00177   prev_smp[1] = audio[dec->frames-3];
00178   prev_smp[2] = audio[dec->frames-2];
00179   prev_smp[3] = audio[dec->frames-1];
00180 
00181   return(buffo);
00182 }
00183 
00184 bool Channel::play() {
00185   if(on) return(true);
00186 
00187   if(!running) {
00188     error("%i:%s %s channel thread not launched",
00189           __LINE__,__FILE__,__FUNCTION__);
00190     return(false);
00191   }
00192 
00193   if(!opened) {
00194     Url *url;
00195     warning("Channel::play() : no song loaded");
00196     url = (Url*) playlist->selected();
00197     if(!url) {
00198       warning("Channel::play() : no song selected in playlist");
00199       url = (Url*)playlist->begin();
00200       if(!url) {
00201         error("Channel::play() : playlist is void");
00202         return(false);
00203       }
00204     }
00205 
00206     if( !load( url->path ) ) {
00207       error("Channel::play() : can't load %s",url->path);
00208       return(false);
00209     } else url->sel(true);
00210   }
00211 
00212   if(time.f!=position) {
00213     pos(position);
00214   } else fill_prev_smp = true;
00215 
00216   on = true;
00217   return(on);
00218 }
00219 
00220 bool Channel::stop() {
00221   //  lock();
00222   on = false;
00223   if(opened) {
00224     //  unlock();
00225     pos(0.0);
00226     state = 0.0;
00227     erbapipa->flush();
00228     fill_prev_smp = true;
00229   }
00230   return(!on);
00231 }
00232 
00233 int Channel::load(char *file) {
00234   MuseDec *ndec = NULL;
00235   int res;
00236   /* returns:
00237      0 = error
00238      1 = stream is seakable
00239      2 = stream is not seekable  */  
00240 
00241   /* parse supported file types */
00242 
00243   if(strncasecmp(file+strlen(file)-4,".ogg",4)==0) {
00244 #ifdef HAVE_VORBIS
00245     func("creating Ogg decoder");
00246     ndec = new MuseDecOgg();
00247 #else
00248     error("can't open OggVorbis (support not compiled)");
00249 #endif
00250   }
00251   if(strncasecmp(file+strlen(file)-4,".mp3",4)==0) {
00252     func("creating Mp3 decoder");
00253     ndec = new MuseDecMp3();
00254   }
00255   // pallotron: aggiungo lo string compare per i formati
00256   // sndfile, per ora metto solo voc e wav.
00257   // TODO: vedere come si chiamano le altre estensioni
00258   // ed aggiungerle.
00259   if(strncasecmp(file+strlen(file)-4,".wav",4)==0) {
00260     func("creating LibSndFile decoder");
00261     ndec = new MuseDecSndFile();
00262   }
00263   
00264   if(!ndec) {
00265     error("can't open %s (unrecognized extension)",file);
00266     return(0);
00267   }
00268 
00269   lock();
00270 
00271   ndec->lock();
00272   res = ndec->load(file); // try to load the file/stream into the decoder
00273   ndec->unlock();
00274 
00275   if(!res) { // there is an error: we keep everything as it is
00276     error("decoder load returns error",file);
00277     unlock();
00278     delete ndec;
00279     return(0);
00280   }
00281   
00282   res = set_resampler(ndec);
00283 
00284   if(!res) {
00285     error("invalid input samplerate %u",ndec->samplerate);
00286     unlock();
00287     delete ndec;
00288     return(0);
00289   }
00290 
00291   // decoder succesfully opened the file
00292   // here if res == 2 then we have a stream
00293   // TODO: oggvorbis stream playing using libcurl
00294   if(dec) delete dec; // delete the old decoder if present
00295   dec = ndec;
00296   opened = true;
00297 
00298   res = (dec->seekable)?1:2;
00299   seekable = (res==1) ? true : false;
00300   state = 0.0;
00301   
00302   unlock();
00303 
00304   notice("loaded %s",file);
00305   notice("%s %iHz %s %s %iKb/s",
00306          dec->name, dec->samplerate,
00307          (dec->channels==1) ? "mono" : "stereo",
00308          (dec->seekable) ? "file" : "stream",
00309          dec->bitrate);
00310   return res;
00311 }
00312      
00313 bool Channel::pos(float pos) {
00314   PARADEC
00315   if(!dec->seekable) return false;
00316   pos = (pos<0.0) ? 0.0 : (pos>1.0) ? 1.1 : pos;
00317   dec->lock();
00318   if(!dec->seek(pos))
00319     error("Channel::seek : error calling decoder seek to %f",position);
00320   else
00321     position = time.f = pos;
00322   dec->unlock();
00323   return true;
00324 }
00325 
00326 void Channel::clean() {
00327   on = false;
00328   //  dec->lock();
00329   //  dec->clean();
00330   //  dec->unlock();
00331   opened = false;
00332   if(dec) delete dec;
00333   dec = NULL;
00334 }
00335 
00336 bool Channel::set_resampler(MuseDec *ndec) {
00337   switch(ndec->samplerate) {
00338   case 44100:
00339     if(ndec->channels==2) munch = resample_stereo_44;
00340     else munch = resample_mono_44;
00341     break;
00342   case 32000:
00343     if(ndec->channels==2) munch = resample_stereo_32;
00344     else munch = resample_mono_32;
00345     break;
00346   case 22050:
00347     if(ndec->channels==2) munch = resample_stereo_22;
00348     else munch = resample_mono_22;
00349     break;
00350   case 16000:
00351     if(ndec->channels==2) munch = resample_stereo_16;
00352     else munch = resample_mono_16;
00353     break;
00354   default:
00355     warning("Channel::set_mixer : i can't mix sound at %uhz",
00356             ndec->samplerate);
00357     return(false);
00358   }
00359   return(true);
00360 }
00361 
00362 
00363 float Channel::upd_time() {
00364   PARADEC
00365   float res;
00366 
00367   /* calculate the float 0.0-1.0 position on stream */
00368   res = (float)dec->framepos/(float)dec->frametot;
00369 
00370   /* calculate the time */
00371   if( ((res-time.f)>0.003) || (time.f-res)>0.003) {
00372     time.f = res;
00373     secs = dec->framepos / dec->fps;
00374     //    func("secs %i",secs);
00375     if(secs>3600) {
00376       time.h = (int) secs / 3600;
00377       secs -= time.h*3600;
00378     }
00379     if(secs>60) {
00380       time.m = (int) secs / 60;
00381       secs -= time.m*60;
00382     }
00383     time.s = (int) secs;
00384     update = true;
00385   }
00386 
00387   return(res);
00388 }
00389 
00390 void Channel::skip() {
00391   switch(playmode) {
00392   case PLAYMODE_PLAY:
00393     stop();
00394     break;
00395   case PLAYMODE_LOOP:
00396     pos(0.0);
00397     break;
00398   case PLAYMODE_CONT:
00399     Url *n;
00400     stop();
00401     n = (Url*)playlist->selected();
00402     if(n) do {
00403       n->sel(false); n = (Url*)n->next;
00404       if(!n) n = (Url*)playlist->begin();
00405       if(!n) break;
00406       n->sel(true);
00407     } while( ! load(n->path) );
00408     if(n) {
00409       play();
00410       update = true;
00411     }
00412     break;
00413   default: break;
00414   }
00415 }
00416 
00417 /* called on end of stream, manages playmode */
00418 void Channel::upd_eos() {
00419   PARADEC
00420     if(!dec->eos) return;
00421   func("end of %s on %s playing for %i:%i:%i",
00422        (seekable)?"stream":"file",dec->name,
00423        time.h,time.m,time.s);
00424   skip();
00425   dec->eos = false;
00426 }
00427 
00428 void Channel::upd_err() {
00429   PARADEC
00430     if(!dec->err) return;
00431     error("error on %s, skipping %s",
00432         dec->name,(seekable)?"stream":"file");
00433   report();
00434   skip();
00435   dec->err = false;
00436 }
00437 
00438 /* ----- LiveIN DSP Channel ----- */
00439 
00440 LiveIn::LiveIn() { 
00441   on = false;
00442   gotin = NULL;
00443 }
00444 
00445 void LiveIn::init(int smpr, int chans, int *thedsp) {
00446   dsp = thedsp;
00447   sample_rate = smpr;
00448   channels = chans;
00449 
00450   /*
00451   num_samples=(int)((sample_rate*BUF_SIZE)/(sample_rate<<1));
00452   opt = (num_samples*channels);
00453   */
00454 
00455   gotin = (IN_DATATYPE*)malloc((MIX_CHUNK<<2) +128);
00456 }
00457 
00458 LiveIn::~LiveIn() {
00459   if(gotin) free(gotin);
00460 }
00461 
00462 int LiveIn::mix(int *mixpcm) {
00463   int res;
00464 
00465   res = get_audio();
00466   mixxx_stereo_44_novol(mixpcm,gotin,res);
00467 
00468   return(res);
00469 }
00470 
00471 
00472 int LiveIn::get_audio() {
00473   int res;
00474 
00475   res = read(*dsp,gotin,MIX_CHUNK<<2);
00476   return(res>>2);
00477 }
00478 
00479 
00480 /* thread stuff */
00481 
00482 void Channel::_thread_init() {
00483 
00484   func("Channel::thread_init()");
00485   if(pthread_mutex_init (&_mutex,NULL) == -1)
00486     error("error initializing POSIX thread mutex");
00487   if(pthread_cond_init (&_cond, NULL) == -1)
00488     error("error initializing POSIX thread condition"); 
00489   if(pthread_attr_init (&_attr) == -1)
00490     error("error initializing POSIX thread attribute");
00491   
00492   /* set the thread as detached
00493      see: man pthread_attr_init(3) */
00494   pthread_attr_setdetachstate(&_attr,PTHREAD_CREATE_DETACHED);
00495 
00496 }
00497 
00498 void Channel::_thread_destroy() {
00499   opened = false;  
00500 
00501   /* we signal and then we check the thread
00502      exited by locking the conditional */
00503   while(running) {
00504     signal();
00505     lock(); unlock();
00506   }
00507 
00508   if(pthread_mutex_destroy(&_mutex) == -1)
00509     error("error destroying POSIX thread mutex");
00510   if(pthread_cond_destroy(&_cond) == -1)
00511     error("error destroying POSIX thread condition");
00512   if(pthread_attr_destroy(&_attr) == -1)
00513     error("error destroying POSIX thread attribute");
00514 }
00515 
00516 
00517 /* here for debugging purposes */
00518 void Channel::report() {
00519 
00520   warning("Channel | %s | %s | %s | %s |",
00521          (opened)?"opened":" ",
00522          (running)?"running":" ",
00523          (on)?"on":"off",
00524          (seekable)?"seekable":" ");
00525 
00526   act("vol %.2f pos %.2f lcd[%s]",volume,position,lcd);
00527   act("state %.2f playmode %s",state,
00528       (playmode==PLAYMODE_PLAY) ? "PLAY" :
00529       (playmode==PLAYMODE_LOOP) ? "LOOP" :
00530       (playmode==PLAYMODE_CONT) ? "CONT" :
00531       "ERROR");
00532   act("time: %i:%i:%i framepos %i frametot %i",
00533       time.h, time.m, time.s, dec->framepos,dec->frametot);
00534   act("samplerate %i channels %i bitrate %i",
00535       dec->samplerate,dec->channels,dec->bitrate);
00536   act("frames %i samples %i",dec->frames,samples);
00537 }

Generated on Sat Apr 17 17:38:48 2004 for MuSE by doxygen1.3