00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <iostream>
00023 #include <math.h>
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <unistd.h>
00027 #include <dirent.h>
00028 #include <sys/ioctl.h>
00029 #include <sys/stat.h>
00030 #include <errno.h>
00031 #include <fcntl.h>
00032
00033 #include <string.h>
00034 #include <signal.h>
00035 #include <sys/types.h>
00036 #include <sys/wait.h>
00037 #include <termios.h>
00038 #include <sys/time.h>
00039
00040 #include <config.h>
00041
00042 #include <jutils.h>
00043 #include <audioproc.h>
00044 #include <jmixer.h>
00045 #include <playlist.h>
00046 #include <inchannels.h>
00047 #include <dev_sound.h>
00048
00049 #ifdef HAVE_VORBIS
00050 #include <out_vorbis.h>
00051 #endif
00052
00053 #ifdef HAVE_LAME
00054 #include <out_lame.h>
00055 #endif
00056
00057 #define CODENAME "STREAMTIME"
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 #define PARACHAN \
00069 if(!chan[ch]) { \
00070 warning("%i:%s %s - channel %i is NULL", \
00071 __LINE__,__FILE__,__FUNCTION__,ch); \
00072 return(false); \
00073 }
00074
00075
00076 Stream_mixer::Stream_mixer() {
00077 int i;
00078 for(i=0;i<MAX_CHANNELS;i++)
00079 chan[i] = NULL;
00080 #ifdef HAVE_SCHEDULER
00081 register_sched(NULL);
00082 #endif
00083
00084
00085 memset(process_buffer,0,PROCBUF_SIZE*sizeof(int32_t));
00086 memset(audio_buffer,0,PROCBUF_SIZE*sizeof(int16_t));
00087
00088 dsp = 0;
00089 max = 0;
00090 have_gui = false;
00091
00092 dspout = false;
00093 linein = false;
00094 linein_vol = 1;
00095 fileout = false;
00096 quit = false;
00097
00098 for(i=0;i<8;i++) peak[i] = 0;
00099 cpeak = 0;
00100
00101
00102 snddev = new SoundDevice();
00103 if( snddev->open(true,true) ) {
00104 dsp = 1;
00105 fullduplex = true;
00106 }
00107
00108
00109 idseed = 0;
00110
00111 if(pthread_mutex_init (&_mutex,NULL) == -1)
00112 error("error initializing POSIX thread mutex");
00113 if(pthread_cond_init (&_cond, NULL) == -1)
00114 error("error initializing POSIX thread condtition");
00115 unlock();
00116 }
00117
00118 Stream_mixer::~Stream_mixer() {
00119 quit = true;
00120 func("Stream_mixer::~Stream_mixer()");
00121 int i;
00122
00123 if(dsp>0) {
00124 act("closing soundcard");
00125 snddev->close();
00126 delete snddev;
00127 }
00128
00129 act("deleting input channels");
00130 for(i=0;i<MAX_CHANNELS;i++) {
00131
00132 if(chan[i]) delete_channel(i);
00133 }
00134
00135 act("deleting output channels");
00136 OutChannel *outch = (OutChannel*) outchans.begin();
00137 while(outch) {
00138 delete_enc( outch->id );
00139 outch = (OutChannel*) outchans.begin();
00140 }
00141
00142 func("deleting thread mutexes");
00143 if(pthread_mutex_destroy(&_mutex) == -1)
00144 error("error destroying POSIX thread mutex");
00145 if(pthread_cond_destroy(&_cond) == -1)
00146 error("error destroying POSIX thread condition");
00147
00148 }
00149
00150 void Stream_mixer::register_gui(GUI *reg_gui) {
00151 char temp[256];
00152 gui = reg_gui;
00153 have_gui = true;
00154 sprintf(temp,"%s %s codename \"%s\"",PACKAGE, VERSION, CODENAME);
00155 gui->set_title(temp);
00156 }
00157
00158 bool Stream_mixer::open_soundcard(bool in, bool out) {
00159 if( ! snddev->open(in,out) ) return false;
00160 dsp = 1;
00161 fullduplex = true;
00162 return true;
00163 }
00164
00165 void Stream_mixer::close_soundcard() {
00166 snddev->close();
00167 }
00168
00169 void Stream_mixer::cafudda()
00170 {
00171 int i, c=0, cc;
00172 int total_bitrate=0;
00173
00174
00175 memset(process_buffer,0,MIX_CHUNK*8);
00176
00177
00178 peak[cpeak] = 0;
00179
00180 if(quit) {
00181 func("QUIT detected while cafudding");
00182 return;
00183 }
00184
00185 lock();
00186
00187 for(i=0;i<MAX_CHANNELS;i++) {
00188 if(chan[i] != NULL) {
00189 if(chan[i]->on) {
00190
00191 cc = chan[i]->erbapipa->read(MIX_CHUNK*2,process_buffer);
00192
00193 if(cc<0) continue;
00194
00195 c+=cc;
00196 if(have_gui)
00197 if(chan[i]->update) {
00198 updchan(i);
00199 chan[i]->update = false;
00200 }
00201 }
00202
00203 }
00204 }
00205
00206
00207 if(linein) {
00208 #ifndef PORTAUDIO
00209
00210 c += livein.mix(process_buffer);
00211
00212 #else
00213 linein_samples = snddev->read(linein_buf,MIX_CHUNK);
00214 for(cc=0; cc<linein_samples*2; cc++) {
00215
00216
00217 process_buffer[cc] += (int32_t) (linein_buf[cc] * linein_vol);
00218
00219 }
00220 c += linein_samples;
00221 #endif
00222 }
00223
00224
00225
00226
00227 #ifdef HAVE_SCHEDULER
00228 if (rsched && rsched->channel->opened) {
00229 c += rsched->channel->erbapipa->read(MIX_CHUNK,process_buffer);
00230 }
00231 #endif
00232
00233
00234
00235
00236
00237
00238
00239 if(c>0) {
00240
00241
00242
00243 clip_audio(MIX_CHUNK);
00244
00245 unlock();
00246
00247 out = (OutChannel*) outchans.begin();
00248 while(out) {
00249
00250 if(out->encoding
00251 && out->initialized
00252 && out->running) {
00253
00254 out->erbapipa->write(MIX_CHUNK*4,audio_buffer);
00255 total_bitrate += out->get_bitrate();
00256
00257 }
00258
00259 out = (OutChannel*) out->next;
00260
00261 }
00262
00263
00264 if(dspout) {
00265
00266
00267
00268 #ifndef PORTAUDIO
00269 write(dsp,audio_buffer,MIX_CHUNK*4);
00270 #else
00271 snddev->write(audio_buffer,MIX_CHUNK*2);
00272 #endif
00273
00274
00275
00276 }
00277
00278
00279 cpeak++;
00280 if(have_gui
00281 && cpeak==8
00282 && gui->meter_shown()) {
00283
00284 gui->vumeter_set( (peak[0]+peak[1]+peak[2]+peak[3]+
00285 peak[4]+peak[5]+peak[6]+peak[7])/8 );
00286 gui->bpsmeter_set( total_bitrate );
00287 cpeak = 0;
00288 }
00289
00290 } else {
00291
00292 if(dspout) {
00293 snddev->flush_output();
00294 snddev->flush_input();
00295 }
00296 unlock();
00297
00298 if(have_gui) {
00299 if(gui->meter_shown()) {
00300 gui->vumeter_set( 0 );
00301 gui->bpsmeter_set( 0 );
00302 }
00303 } else
00304 quit = true;
00305
00306 }
00307
00308
00309 if(have_gui) gui->signal();
00310
00311
00312
00313
00314
00315
00316
00317 #ifdef CARBON_GUI
00318 usleep(200);
00319 #else
00320 jsleep(0,20);
00321 #endif
00322 }
00323
00324 bool Stream_mixer::create_channel(int ch) {
00325
00326
00327 if(chan[ch]) {
00328 warning("channel %i allready exists");
00329 unlock();
00330 return true;
00331 }
00332
00333 Channel *nch;
00334 nch = new Channel();
00335
00336 nch->lock();
00337 nch->start();
00338 func("waiting for channel %i thread to start",ch);
00339 nch->wait();
00340
00341 nch->unlock();
00342
00343 lock();
00344 chan[ch] = nch;
00345 unlock();
00346
00347 return(true);
00348 }
00349
00350 bool Stream_mixer::delete_channel(int ch) {
00351
00352 PARACHAN
00353
00354 lock();
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369 delete chan[ch];
00370 chan[ch] = NULL;
00371
00372 unlock();
00373 return true;
00374 }
00375
00376 bool Stream_mixer::pause_channel(int ch) {
00377
00378 PARACHAN
00379
00380
00381 if(chan[ch]->opened) {
00382 if(!chan[ch]->on) {
00383 lock();
00384 if(!chan[ch]->play())
00385 error("can't play channel %u",ch,ch);
00386 unlock();
00387 } else {
00388 chan[ch]->on = false;
00389 chan[ch]->position = chan[ch]->time.f;
00390 return true;
00391 }
00392 } else warning("tried to switch pause on unopened channel %i",ch);
00393 return false;
00394 }
00395 bool Stream_mixer::pause_channel(int ch, bool stat) {
00396
00397 PARACHAN
00398
00399 if(chan[ch]->opened) {
00400 if(!stat) {
00401 lock();
00402 if(!chan[ch]->play())
00403 error("can't play channel %u",ch,ch);
00404 unlock();
00405 } else {
00406 chan[ch]->on = false;
00407 return true;
00408 }
00409 } else error("can't pause unopened channel %i",ch);
00410 return false;
00411 }
00412
00413 bool Stream_mixer::set_channel(int ch, int pos) {
00414 PARACHAN
00415
00416 if(!chan[ch]->playlist->sel(pos))
00417 return(false);
00418 else
00419 chan[ch]->opened = false;
00420
00421
00422
00423
00424
00425 return(true);
00426 }
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439 int Stream_mixer::play_channel(int ch) {
00440 int res = 0;
00441
00442
00443 PARACHAN
00444
00445 lock();
00446 if(!chan[ch]->play())
00447 error("can't play channel %u",ch);
00448 else
00449 res = (chan[ch]->seekable) ? 1 : 2;
00450 unlock();
00451
00452 return(res);
00453 }
00454
00455 void Stream_mixer::set_all_volumes(float *vol) {
00456 int ch;
00457 lock();
00458 for(ch=0;ch<MAX_CHANNELS;ch++) {
00459 if(chan[ch]!=NULL)
00460 chan[ch]->volume = vol[ch];
00461 }
00462 unlock();
00463 }
00464
00465 bool Stream_mixer::set_volume(int ch, float vol) {
00466
00467 PARACHAN
00468
00469 lock();
00470 chan[ch]->volume = vol;
00471 unlock();
00472 return true;
00473 }
00474
00475 void Stream_mixer::crossfade(int ch1, float vol1, int ch2, float vol2) {
00476 if(!chan[ch1] || !chan[ch2]) {
00477 warning("Stream_mixer::crossfade(%u,%f,%u,%f) called on a NULL channel",ch1,vol1,ch2,vol2);
00478 return;
00479 }
00480
00481 lock();
00482 chan[ch1]->volume = vol1;
00483 chan[ch2]->volume = vol2;
00484 unlock();
00485 }
00486
00487 void Stream_mixer::set_speed(int ch, int speed) {
00488 lock();
00489 chan[ch]->speed = speed;
00490 unlock();
00491
00492
00493
00494 }
00495
00496 bool Stream_mixer::stop_channel(int ch) {
00497
00498 PARACHAN
00499
00500 bool res = false;
00501
00502 lock();
00503 res = chan[ch]->stop();
00504 unlock();
00505
00506
00507
00508
00509 return(res);
00510 }
00511
00512 bool Stream_mixer::set_position(int ch, float pos) {
00513
00514
00515 PARACHAN
00516 bool res = false;
00517 if(!chan[ch]->opened) {
00518 error("can't seek position on channel %u",ch);
00519 return(res);
00520 }
00521
00522
00523
00524
00525
00526
00527
00528
00529 if(chan[ch]->seekable && chan[ch]->running) {
00530 lock();
00531
00532 chan[ch]->lock();
00533 res = chan[ch]->pos(pos);
00534 chan[ch]->unlock();
00535 if(!res) error("can't seek position %f on channel %u",pos,ch);
00536
00537 unlock();
00538 } else
00539 error("channel %u is not seekable",ch);
00540 return(res);
00541 }
00542
00543
00544
00545 bool Stream_mixer::move_song(int ch, int pos, int nch, int npos) {
00546 Entry *x = chan[ch]->playlist->pick(pos);
00547 func("move song %i on channel %i to channel %i in position %i",
00548 pos,ch,nch,npos);
00549 if(x) {
00550
00551
00552 chan[nch]->playlist->insert(x,npos);
00553 return(true);
00554 } else
00555 func("no song to move there!");
00556
00557 return(false);
00558 }
00559
00560 bool Stream_mixer::set_live(bool stat) {
00561 #ifndef PORTAUDIO
00562 if(dsp<1) {
00563 warning("ignoring live-in: soundcard not found");
00564 return(false);
00565 }
00566
00567 if(!( (dspout)
00568 &&(!fullduplex)
00569 &&(stat)) ) {
00570 lock();
00571 livein.on = linein = stat;
00572 unlock();
00573 }
00574
00575 return(livein.on);
00576 #else
00577 lock();
00578 if( snddev->input(stat) )
00579 linein = stat;
00580 unlock();
00581 return linein;
00582 #endif
00583 }
00584
00585 void Stream_mixer::set_mic_volume(int vol) {
00586 lock();
00587 linein_vol = vol;
00588 unlock();
00589 }
00590
00591
00592
00593 bool Stream_mixer::set_lineout(bool stat) {
00594 #ifndef PORTAUDIO
00595 if(dsp<1) {
00596 error("ignoring sound output: soundcard not found");
00597 return(false);
00598 }
00599
00600 if(!( (livein.on)
00601 &&(!fullduplex)
00602 &&(stat)) ) {
00603 lock();
00604 dspout = stat;
00605 unlock();
00606 }
00607 return(dspout&stat);
00608 #else
00609 lock();
00610 if( snddev->output(stat) )
00611 dspout = stat;
00612 unlock();
00613 return dspout;
00614 #endif
00615 }
00616
00617 bool Stream_mixer::set_playmode(int ch, int mode) {
00618
00619 switch(mode) {
00620 case PLAYMODE_PLAY:
00621 chan[ch]->playmode = PLAYMODE_PLAY;
00622 break;
00623 case PLAYMODE_LOOP:
00624 chan[ch]->playmode = PLAYMODE_LOOP;
00625 break;
00626 case PLAYMODE_CONT:
00627 chan[ch]->playmode = PLAYMODE_CONT;
00628 break;
00629 }
00630 return true;
00631 }
00632
00633
00634
00635
00636 int selector(const struct dirent *dir) {
00637 if( strncasecmp(dir->d_name+strlen(dir->d_name)-4,".mp3",4)==0
00638 #ifdef HAVE_VORBIS
00639 || strncasecmp(dir->d_name+strlen(dir->d_name)-4,".ogg",4)==0
00640 #endif
00641 #ifdef HAVE_SNDFILE
00642 || strncasecmp(dir->d_name+strlen(dir->d_name)-4,".wav",4)==0
00643 || strncasecmp(dir->d_name+strlen(dir->d_name)-4,".aif",4)==0
00644 || strncasecmp(dir->d_name+strlen(dir->d_name)-5,".aiff",4)==0
00645 || strncasecmp(dir->d_name+strlen(dir->d_name)-4,".snd",4)==0
00646 || strncasecmp(dir->d_name+strlen(dir->d_name)-3,".au",4)==0
00647 || strncasecmp(dir->d_name+strlen(dir->d_name)-4,".raw",4)==0
00648 || strncasecmp(dir->d_name+strlen(dir->d_name)-4,".paf",4)==0
00649 || strncasecmp(dir->d_name+strlen(dir->d_name)-4,".iff",4)==0
00650 || strncasecmp(dir->d_name+strlen(dir->d_name)-4,".svx",4)==0
00651 || strncasecmp(dir->d_name+strlen(dir->d_name)-3,".sf",4)==0
00652 || strncasecmp(dir->d_name+strlen(dir->d_name)-4,".voc",4)==0
00653 || strncasecmp(dir->d_name+strlen(dir->d_name)-4,".w64",4)==0
00654 || strncasecmp(dir->d_name+strlen(dir->d_name)-4,".pvf",4)==0
00655 || strncasecmp(dir->d_name+strlen(dir->d_name)-3,".xi",4)==0
00656 || strncasecmp(dir->d_name+strlen(dir->d_name)-4,".htk",4)==0
00657 || strncasecmp(dir->d_name+strlen(dir->d_name)-4,".mat",4)==0
00658 #endif
00659 || strncasecmp(dir->d_name+strlen(dir->d_name)-3,".pl",3)==0
00660 || strncasecmp(dir->d_name+strlen(dir->d_name)-4,".pls",4)==0
00661 || strncasecmp(dir->d_name+strlen(dir->d_name)-4,".m3u",4)==0 )
00662 return(1);
00663
00664
00665
00666
00667
00668 return(0);
00669 }
00670
00671
00672
00673
00674 bool Stream_mixer::add_to_playlist(int ch, const char *file) {
00675
00676 if(!file) {
00677 warning("Stream_mixer::add_to_playlist(%i,NULL) called",ch);
00678 return(false);
00679 }
00680
00681 if(!chan[ch]) {
00682 warning("%i:%s %s - called on NULL channel %i",
00683 __LINE__,__FILE__,__FUNCTION__,ch);
00684 warning("call jmixer::create_channel first");
00685 return(false);
00686 }
00687
00688 char temp[MAX_PATH_SIZE];
00689
00690 char *path, *p;
00691
00692 strncpy(temp,file,MAX_PATH_SIZE);
00693 chomp(temp);
00694 func("add to playlist %s", temp);
00695
00696 if(strncasecmp(temp,"http://",7)==0) {
00697 func("it's a network stream url");
00698
00699 path = chan[ch]->playlist->addurl(temp);
00700
00701 if(have_gui) gui->add_playlist(ch,path);
00702 return(true);
00703 }
00704
00705
00706
00707 if(strncasecmp(temp,"file://",7)==0) {
00708 func("it's a file url (drag & drop)");
00709 strncpy(temp,&file[7],MAX_PATH_SIZE);
00710 path = chan[ch]->playlist->addurl(temp);
00711 if(have_gui) gui->add_playlist(ch,path);
00712 return(true);
00713 }
00714
00715 if(strncasecmp(temp,"jack://",7)==0) {
00716 #ifdef HAVE_JACK
00717 func("it's a jack client input channel");
00718 strncpy(temp,file,MAX_PATH_SIZE);
00719 path = chan[ch]->playlist->addurl(temp);
00720 if(have_gui) gui->add_playlist(ch,path);
00721 return(true);
00722 #else
00723 error("jack daemon support not compiled, client \'%s\' cannot be activated",&temp[7]);
00724 return(false);
00725 #endif
00726 }
00727
00728
00729 FILE *fd = NULL;
00730 fd = fopen(temp,"r");
00731 if(!fd) {
00732 warning("is not a readable file",temp);
00733 return(false);
00734 } else fclose(fd);
00735
00736 bool res = false;
00737
00738
00739
00740
00741
00742 if( strncasecmp(temp+strlen(temp)-4,".ogg",4)==0
00743 || strncasecmp(temp+strlen(temp)-4,".mp3",4)==0
00744 || strncasecmp(temp+strlen(temp)-4,".wav",4)==0
00745 || strncasecmp(temp+strlen(temp)-4,".aif",4)==0
00746 || strncasecmp(temp+strlen(temp)-5,".aiff",4)==0
00747 || strncasecmp(temp+strlen(temp)-4,".snd",4)==0
00748 || strncasecmp(temp+strlen(temp)-3,".au",4)==0
00749 || strncasecmp(temp+strlen(temp)-4,".raw",4)==0
00750 || strncasecmp(temp+strlen(temp)-4,".paf",4)==0
00751 || strncasecmp(temp+strlen(temp)-4,".iff",4)==0
00752 || strncasecmp(temp+strlen(temp)-4,".svx",4)==0
00753 || strncasecmp(temp+strlen(temp)-3,".sf",4)==0
00754 || strncasecmp(temp+strlen(temp)-4,".voc",4)==0
00755 || strncasecmp(temp+strlen(temp)-4,".w64",4)==0
00756 || strncasecmp(temp+strlen(temp)-4,".pvf",4)==0
00757 || strncasecmp(temp+strlen(temp)-3,".xi",4)==0
00758 || strncasecmp(temp+strlen(temp)-4,".htk",4)==0
00759 || strncasecmp(temp+strlen(temp)-4,".mat",4)==0
00760 ) {
00761 func("it's a local file",temp);
00762
00763 path = chan[ch]->playlist->addurl(temp);
00764
00765
00766 if(have_gui) {
00767 p = path+strlen(path);
00768 while(*p!='/') p--; p++;
00769 gui->add_playlist(ch,p);
00770 }
00771
00772 res = true;
00773
00774
00775 } else if( strncasecmp(temp+strlen(temp)-3,".pl",3)==0
00776 || strncasecmp(temp+strlen(temp)-4,".pls",4)==0
00777 || strncasecmp(temp+strlen(temp)-4,".m3u",4)==0 ) {
00778 func("it's a playlist");
00779
00780 char votantonio[MAX_PATH_SIZE];
00781 fd = fopen(temp,"r");
00782 while(fgets(votantonio,MAX_PATH_SIZE,fd)!=NULL) {
00783 chomp(votantonio);
00784
00785
00786
00787
00788
00789 add_to_playlist(ch,votantonio);
00790 }
00791 fclose(fd);
00792 res = true;
00793
00794
00795 } else {
00796
00797 struct stat prcd;
00798 if(stat(temp,&prcd)<0) {
00799 error("can't read file status");
00800 warning("cannot stat %s : %s",temp,strerror(errno));
00801 } else if(prcd.st_mode & S_IFDIR) {
00802 func("it's a directory");
00803 const struct dirent **filelist;
00804
00805 int found = scandir(temp,&filelist,selector,alphasort);
00806 if(found<1) error("%i files found: %s",found,strerror(errno));
00807 else {
00808 int c;
00809 for(c=0;c<found;c++) {
00810 char barakus[MAX_PATH_SIZE];
00811 snprintf(barakus,MAX_PATH_SIZE,"%s/%s",temp,filelist[c]->d_name);
00812
00813 add_to_playlist(ch,barakus);
00814 }
00815 res = true;
00816 }
00817
00818 } else {
00819 error("file extension is not recognized");
00820 error("can't add to playlist %s",temp);
00821 }
00822 }
00823
00824 return(res);
00825 }
00826
00827 void Stream_mixer::rem_from_playlist(int ch, int pos) {
00828
00829 if(ch>MAX_CHANNELS) {
00830 warning("Stream_mixer::rem_from_playlist(%u,%u) : channel does'nt exists");
00831 return;
00832 }
00833
00834
00835
00836 chan[ch]->playlist->rem(pos);
00837
00838 pos = (pos>chan[ch]->playlist->len()) ?
00839 chan[ch]->playlist->len() : pos;
00840 if(pos>0) {
00841 chan[ch]->playlist->sel(pos);
00842 if(have_gui) gui->sel_playlist(ch,pos-1);
00843 }
00844
00845 }
00846
00847 int Stream_mixer::create_enc(enum codec enc) {
00848 OutChannel *outch = NULL;
00849 switch(enc) {
00850
00851 #ifdef HAVE_VORBIS
00852 case OGG:
00853 outch = new OutVorbis;
00854
00855 if( ! ((OutVorbis*)outch)->init() ) {
00856 error("error initializing %s",outch->name);
00857 delete (OutVorbis*)outch;
00858 return -1;
00859 }
00860 break;
00861 #endif
00862
00863 #ifdef HAVE_LAME
00864 case MP3:
00865 outch= new OutLame;
00866 if( ! ((OutLame*)outch)->init() ) {
00867 error("error initializing %s",outch->name);
00868 delete (OutLame*)outch;
00869 return -1;
00870
00871 }
00872 break;
00873 #endif
00874
00875 default: break;
00876
00877 }
00878
00879 outchans.add(outch);
00880
00881 idseed += 1000;
00882
00883 outch->id = idseed;
00884
00885 notice("%s %s initialized",outch->name,outch->version);
00886 return outch->id;
00887 }
00888
00889 void Stream_mixer::delete_enc(int id) {
00890 OutChannel *outch = (OutChannel*) outchans.pick_id(id);
00891 if(!outch) {
00892 warning("delete_enc: invalid encoder requested ID:%i",id);
00893 return;
00894 }
00895
00896 lock();
00897
00898 outch->rem();
00899
00900 if(outch->running) {
00901 outch->quit = true;
00902 jsleep(0,50);
00903 outch->lock(); outch->unlock();
00904 outch->flush();
00905
00906 }
00907
00908 delete outch;
00909 unlock();
00910 }
00911
00912 OutChannel *Stream_mixer::get_enc(int id) {
00913 return (OutChannel*)outchans.pick_id(id);
00914 }
00915
00916 bool Stream_mixer::apply_enc(int id) {
00917 OutChannel *outch = (OutChannel*)outchans.pick_id(id);
00918 if(!outch) {
00919 warning("apply_enc: invalid encoder requested ID:%i",id);
00920 return false;
00921 }
00922
00923
00924
00925 char *qstr = outch->quality_desc;
00926
00927 lock();
00928 outch->lock();
00929
00930 outch->initialized = outch->apply_profile();
00931
00932 outch->unlock();
00933 unlock();
00934
00935 if(outch->initialized)
00936 notice("%s quality %uKbps/s %uHz %s", outch->name, outch->bps(), outch->freq(),
00937 (outch->channels()==1)?" mono ":" stereo ");
00938 else
00939 error("ERROR setting %s to quality %uKbps/s %uHz %s", outch->name, outch->bps(), outch->freq(),
00940 (outch->channels()==1)?" mono ":" stereo ");
00941
00942 return outch->initialized;
00943 }
00944
00945
00946
00947 void Stream_mixer::updchan(int ch) {
00948 if(!chan[ch]) return;
00949 if(chan[ch]->seekable) {
00950 gui->lock();
00951
00952 snprintf(gui->ch_lcd[ch],9,"%02u:%02u:%02u",
00953 chan[ch]->time.h,chan[ch]->time.m,chan[ch]->time.s);
00954 gui->unlock();
00955
00956
00957 gui->set_lcd(ch, gui->ch_lcd[ch]);
00958
00959
00960
00961 gui->lock();
00962 gui->ch_pos[ch] = chan[ch]->state;
00963 gui->unlock();
00964 gui->set_pos(ch, chan[ch]->state);
00965
00966 #ifdef CARBON_GUI
00967 gui->sel_playlist(ch,chan[ch]->playlist->selected_pos());
00968 #endif
00969
00970 }
00971 }
00972
00977 void Stream_mixer::clip_audio(int samples) {
00978 int c;
00979 static float k = 1.0;
00980 int pproc,sum = 0;
00981 #ifdef MOP_LOGGING
00982 static int mopct = 0, supsum = 0;
00983 #endif
00984
00985 if(samples==0) return;
00986 int words = samples*2;
00987
00988 for(c=0;c<words;c++) {
00989
00990 pproc = (int)(((float)(process_buffer[c]))*k);
00991
00992 if(pproc > 32767) {
00993
00994 sum += (pproc-32767);
00995 audio_buffer[c] = peak[cpeak] = 32767;
00996 }
00997 else if(pproc < -32768) {
00998
00999 sum += (-pproc-32768);
01000 audio_buffer[c] = -32768;
01001 }
01002 else {
01003 audio_buffer[c] = (short)pproc;
01004 if (pproc>peak[cpeak])
01005 peak[cpeak] = pproc;
01006 }
01007 }
01008 k = (k * MOP_ADV_RETM +
01009 1.0 / ((1.0 + MOP_ADV_KARE *
01010 (sum / (float)(samples*32767))
01011 ))
01012 ) / (MOP_ADV_RETM + 1.0);
01013
01014 #ifdef MOP_LOGGING
01015
01016 if ((mopct % 128) == 0) {
01017 supsum = spsump/128;
01018 warning("JMIX::clip_audio(%i) : k = (%f,%ld)",samples,k,supsum);
01019 supsum = sum;
01020 }
01021 else
01022 supsum += sum;
01023 mopct++;
01024 #endif
01025
01026 }