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