00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00020
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;
00138 long SoundMixer::blockSize = 0;
00139 long SoundMixer::nbInst = 0;
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;
00152
00153 if (nbInst++) {
00154
00155 return;
00156 }
00157
00158 dsp = open(device,O_WRONLY);
00159 if (dsp < 0) {
00160 perror("open dsp");
00161 return;
00162 }
00163
00164
00165 status = ioctl(dsp, SNDCTL_DSP_RESET);
00166 if (status < 0) perror("ioctl SNDCTL_DSP_RESET");
00167
00168
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
00182 stereo = 1;
00183 status = ioctl(dsp, SNDCTL_DSP_STEREO, &stereo);
00184
00185 if (status) {
00186 stereo = 0;
00187 }
00188
00189
00190 soundRate = 11000;
00191 status = ioctl(dsp, SNDCTL_DSP_SPEED, &soundRate);
00192 if (status < 0) perror("ioctl SNDCTL_DSP_SPEED");
00193
00194
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
00218
00219 #endif
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
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
00277 if (dsp < 0) return 0;
00278
00279
00280 if (list == 0) return 0;
00281
00282
00283 status = ioctl(dsp, SNDCTL_DSP_GETOSPACE, &bufInfo);
00284
00285
00286
00287 if (bufInfo.bytes < blockSize) return 1;
00288
00289 nbBytes = 0;
00290
00291
00292 memset((void*)buffer, 0, blockSize);
00293
00294 prev = 0;
00295 sl = list;
00296 while(sl) {
00297
00298
00299
00300 n = fillSoundBuffer(sl, buffer, blockSize);
00301
00302
00303 if (n > nbBytes) {
00304 nbBytes = n;
00305 }
00306
00307
00308 if (sl->remaining == 0) {
00309
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
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
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
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
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 }