Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

sound.cc

Go to the documentation of this file.
00001 
00002 // Flash Plugin and Player
00003 // Copyright (C) 1998,1999 Olivier Debon
00004 // 
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 // 
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00018 // 
00020 //  Author : Olivier Debon  <odebon@club-internet.fr>
00021 //
00022 
00023 #include "swf.h"
00024 
00025 #include <unistd.h>
00026 #include <fcntl.h>
00027 #include <sys/ioctl.h>
00028 #ifndef NOSOUND
00029 #include <linux/soundcard.h>
00030 #endif
00031 
00032 #ifdef RCSID
00033 static char *rcsid = "$Id: sound.cc,v 1.1.1.1 2002/01/25 22:14:59 kergoth Exp $";
00034 #endif
00035 
00036 #define PRINT 0
00037 
00039 
00040 Sound::Sound(long id) : Character(SoundType, id)
00041 {
00042         samples = 0;
00043         stereo = 0;
00044         soundRate = 0;
00045         sampleSize = 1;
00046 }
00047 
00048 Sound::~Sound()
00049 {
00050         if (samples) {
00051                 delete samples;
00052         }
00053 }
00054 
00055 void
00056 Sound::setSoundFlags(long f) {
00057         switch (GET_SOUND_RATE_CODE(f)) {
00058                 case 0:
00059                         soundRate = 5500;
00060                         break;
00061                 case 1:
00062                         soundRate = 11000;
00063                         break;
00064                 case 2:
00065                         soundRate = 22000;
00066                         break;
00067                 case 3:
00068                         soundRate = 44000;
00069                         break;
00070         }
00071         if (f & soundIs16bit) {
00072                 sampleSize = 2;
00073         }
00074         if (f & soundIsStereo) {
00075                 stereo = 1;
00076         }
00077 
00078 #if PRINT
00079         printf("-----\nFlags = %2x\n", f);
00080         printf("Rate = %d kHz  ", soundRate);
00081         printf("SampleSize = %d byte(s) ", sampleSize);
00082         if (f & soundIsStereo) {
00083                 printf("Stereo  ");
00084         } else {
00085                 printf("Mono  ");
00086         }
00087         if (f & soundIsADPCMCompressed) {
00088                 printf("ADPCM\n");
00089         } else {
00090                 printf("Raw\n");
00091         }
00092 #endif
00093 }
00094 
00095 char *
00096 Sound::setNbSamples(long n) {
00097         long size;
00098 
00099         nbSamples = n;
00100 
00101         size = nbSamples * (stereo ? 2 : 1) * sampleSize;
00102 
00103         samples = new char[ size ];
00104 
00105         memset((char *)samples,0, size);
00106 
00107         return samples;
00108 }
00109 
00110 long
00111 Sound::getRate() {
00112         return soundRate;
00113 }
00114 
00115 long
00116 Sound::getChannel() {
00117         return stereo ? 2 : 1;
00118 }
00119 
00120 long
00121 Sound::getNbSamples() {
00122         return nbSamples;
00123 }
00124 
00125 long
00126 Sound::getSampleSize() {
00127         return sampleSize;
00128 }
00129 
00130 char *
00131 Sound::getSamples() {
00132         return samples;
00133 }
00134 
00136 
00137 long  SoundMixer::dsp = -1;     // Init of descriptor
00138 long  SoundMixer::blockSize = 0;        // Driver sound buffer size
00139 long  SoundMixer::nbInst = 0;   // Nb SoundMixer instances
00140 long  SoundMixer::sampleSize = 0;
00141 long  SoundMixer::stereo = 0;
00142 long  SoundMixer::soundRate = 0;
00143 char *SoundMixer::buffer = 0;
00144 
00145 SoundMixer::SoundMixer(char *device)
00146 {
00147 #ifndef NOSOUND
00148         int status;
00149         long fmt;
00150 
00151         list = 0;       // No sound to play
00152 
00153         if (nbInst++) {
00154                 // Device is already open
00155                 return;
00156         }
00157 
00158         dsp = open(device,O_WRONLY);
00159         if (dsp < 0) {
00160                 perror("open dsp");
00161                 return;
00162         }
00163 
00164         // Reset device
00165         status = ioctl(dsp, SNDCTL_DSP_RESET);
00166         if (status < 0) perror("ioctl SNDCTL_DSP_RESET");
00167 
00168         // Set sample size
00169         fmt = AFMT_S16_LE;
00170         sampleSize = 2;
00171         status = ioctl(dsp, SNDCTL_DSP_SETFMT, &fmt);
00172         if (status < 0) perror("ioctl SNDCTL_DSP_SETFMT");
00173 
00174         if (status) {
00175                 fmt = AFMT_U8;
00176                 sampleSize = 1;
00177                 status = ioctl(dsp, SNDCTL_DSP_SETFMT, &fmt);
00178                 if (status < 0) perror("ioctl SNDCTL_DSP_SETFMT");
00179         }
00180 
00181         // Set stereo channel
00182         stereo = 1;
00183         status = ioctl(dsp, SNDCTL_DSP_STEREO, &stereo);
00184 
00185         if (status) {
00186                 stereo = 0;
00187         }
00188 
00189         // Set sound rate in Hertz
00190         soundRate = 11000;
00191         status = ioctl(dsp, SNDCTL_DSP_SPEED, &soundRate);
00192         if (status < 0) perror("ioctl SNDCTL_DSP_SPEED");
00193 
00194         // Get device buffer size
00195         status = ioctl(dsp, SNDCTL_DSP_GETBLKSIZE, &blockSize);
00196         if (status < 0) perror("ioctl SNDCTL_DSP_GETBLKSIZE");
00197         if (blockSize < 1024) {
00198                 blockSize = 32768;
00199         }
00200         blockSize *= 2;
00201 
00202         buffer = (char *)malloc(blockSize);
00203         if (buffer == 0) {
00204                 close(dsp);
00205                 dsp = -1;
00206         }
00207 
00208 #if PRINT
00209         int caps;
00210 
00211         ioctl(dsp,SNDCTL_DSP_GETCAPS, &caps);
00212         printf("Audio capabilities = %x\n", caps);
00213         printf("Sound Rate  = %d\n", soundRate);
00214         printf("Stereo      = %d\n", stereo);
00215         printf("Sample Size = %d\n", sampleSize);
00216         printf("Buffer Size = %d\n", blockSize);
00217 #endif /* PRINT */
00218 
00219 #endif  /* NOSOUND */
00220 }
00221 
00222 SoundMixer::~SoundMixer()
00223 {
00224         if (--nbInst == 0) {
00225                 if (dsp > 0) {
00226                         close(dsp);
00227                         free(buffer);
00228                 }
00229         }
00230 }
00231 
00232 void
00233 SoundMixer::stopSounds()
00234 {
00235 #ifndef NOSOUND
00236         SoundList *sl,*del;
00237 
00238         for(sl = list; sl; ) {
00239                 del = sl;
00240                 sl = sl->next;
00241                 delete del;
00242         }
00243         list = 0;
00244 #endif
00245 }
00246 
00247 void
00248 SoundMixer::startSound(Sound *sound)
00249 {
00250 #ifndef NOSOUND
00251         SoundList *sl;
00252 
00253         if (sound) {
00254                 // Add sound in list
00255                 sl = new SoundList;
00256                 sl->rate = sound->getRate();
00257                 sl->stereo = (sound->getChannel() == 2);
00258                 sl->sampleSize = sound->getSampleSize();
00259                 sl->current = sound->getSamples();
00260                 sl->remaining = sound->getSampleSize()*sound->getNbSamples()*sound->getChannel();
00261                 sl->next = list;
00262                 list = sl;
00263         }
00264 #endif
00265 }
00266 
00267 long
00268 SoundMixer::playSounds()
00269 {
00270 #ifndef NOSOUND
00271         audio_buf_info   bufInfo;
00272         long             nbBytes, n;
00273         SoundList       *sl,*prev;
00274         int              status;
00275 
00276         // Init failed
00277         if (dsp < 0) return 0;
00278 
00279         // No sound to play
00280         if (list == 0) return 0;
00281 
00282         // Get free DMA buffer space
00283         status = ioctl(dsp, SNDCTL_DSP_GETOSPACE, &bufInfo);
00284 
00285         // Free space is not large enough to output data without blocking
00286         // But there are still sounds to play. We must wait.
00287         if (bufInfo.bytes < blockSize) return 1;
00288 
00289         nbBytes = 0;
00290 
00291         // Fill buffer with silence.
00292         memset((void*)buffer, 0, blockSize);
00293 
00294         prev = 0;
00295         sl = list;
00296         while(sl) {
00297 
00298                 // Ask sound to fill the buffer
00299                 // according to device capabilities
00300                 n = fillSoundBuffer(sl, buffer, blockSize);
00301 
00302                 // Remember the largest written size
00303                 if (n > nbBytes) {
00304                         nbBytes = n;
00305                 }
00306 
00307                 // No more samples for this sound
00308                 if (sl->remaining == 0) {
00309                         // Remove sound from list
00310                         if (prev) {
00311                                 prev->next = sl->next;
00312                                 delete sl;
00313                                 sl = prev->next;
00314                         } else {
00315                                 list = sl->next;
00316                                 delete sl;
00317                                 sl = list;
00318                         }
00319                 } else {
00320                         sl = sl->next;
00321                 }
00322         }
00323 
00324         if (nbBytes) {
00325                 // At last ! Play It !
00326                 write(dsp,buffer,nbBytes);
00327                 status = ioctl(dsp, SNDCTL_DSP_POST);
00328         }
00329 
00330         return nbBytes;
00331 #else
00332         return 0;
00333 #endif
00334 }
00335 
00336 long
00337 SoundMixer::fillSoundBuffer(SoundList *sl, char *buff, long buffSize)
00338 {
00339         long sampleLeft, sampleRight;
00340         long skipOut, skipOutInit;
00341         long skipIn, skipInInit;
00342         long freqRatio;
00343         long totalOut = 0;
00344 
00345         sampleLeft = sampleRight = 0;
00346         skipOutInit = skipInInit = 0;
00347 
00348         freqRatio = sl->rate / soundRate;
00349         if (freqRatio) {
00350                 skipOutInit = freqRatio - 1;
00351                 skipInInit = 0;
00352         }
00353 
00354         freqRatio = soundRate / sl->rate;
00355         if (freqRatio) {
00356                 skipInInit = freqRatio - 1;
00357                 skipOutInit = 0;
00358         }
00359 
00360         skipOut = skipOutInit;
00361         skipIn = skipInInit;
00362         while (buffSize && sl->remaining) {
00363                 if (skipIn-- == 0) {
00364                         // Get sampleLeft
00365                         if (sl->sampleSize == 2) {
00366                                 sampleLeft = (long)(*(short *)(sl->current));
00367                                 if (sampleSize == 1) {
00368                                         sampleLeft = (sampleLeft >> 8) &0xff;
00369                                 }
00370                         } else {
00371                                 sampleLeft = (long)*(sl->current);
00372                                 if (sampleSize == 2) {
00373                                         sampleLeft <<= 8;
00374                                 }
00375                         }
00376                         sl->current += sl->sampleSize;
00377                         sl->remaining -= sl->sampleSize;
00378 
00379                         if (sl->stereo) {
00380                                 // Get sampleRight
00381                                 if (sl->sampleSize == 2) {
00382                                         sampleRight = (long)(*(short *)(sl->current));
00383                                         if (sampleSize == 1) {
00384                                                 sampleRight = (sampleRight >> 8) &0xff;
00385                                         }
00386                                 } else {
00387                                         sampleRight = (long)*(sl->current);
00388                                         if (sampleSize == 2) {
00389                                                 sampleRight <<= 8;
00390                                         }
00391                                 }
00392                                 sl->current += sl->sampleSize;
00393                                 sl->remaining -= sl->sampleSize;
00394 
00395                         } else {
00396                                 sampleRight = sampleLeft;
00397                         }
00398                         
00399                         skipIn = skipInInit;
00400                 }
00401 
00402                 if (skipOut-- == 0) {
00403                         // Output
00404                         if (stereo) {
00405                                 if (sampleSize == 2) {
00406                                         *((short *)buff) += sampleLeft/2;
00407                                         buffSize -= sampleSize;
00408                                         buff += sampleSize;
00409                                         *((short *)buff) += sampleRight/2;
00410                                         buffSize -= sampleSize;
00411                                         buff += sampleSize;
00412                                 } else {
00413                                         *((char *)buff) += sampleLeft/2;
00414                                         buffSize -= sampleSize;
00415                                         buff += sampleSize;
00416                                         *((char *)buff) += sampleRight/2;
00417                                         buffSize -= sampleSize;
00418                                         buff += sampleSize;
00419                                 }
00420                                 totalOut += 2*sampleSize;
00421                         } else {
00422                                 if (sampleSize == 2) {
00423                                         *((short *)buff) += (sampleLeft+sampleRight)>>2;
00424                                         buffSize -= sampleSize;
00425                                         buff += sampleSize;
00426                                 } else {
00427                                         *((char *)buff) += (sampleLeft+sampleRight)>>2;
00428                                         buffSize -= sampleSize;
00429                                         buff += sampleSize;
00430                                 }
00431                                 totalOut += sampleSize;
00432                         }
00433 
00434                         skipOut = skipOutInit;
00435                 }
00436         }
00437 
00438         return totalOut;
00439 }

Generated on Sat Nov 5 16:15:36 2005 for OPIE by  doxygen 1.4.2