home *** CD-ROM | disk | FTP | other *** search
- /////////////////////////////////////////////////////////////
- // Flash Plugin and Player
- // Copyright (C) 1998,1999 Olivier Debon
- //
- // This program is free software; you can redistribute it and/or
- // modify it under the terms of the GNU General Public License
- // as published by the Free Software Foundation; either version 2
- // of the License, or (at your option) any later version.
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with this program; if not, write to the Free Software
- // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- //
- ///////////////////////////////////////////////////////////////
- // Author : Olivier Debon <odebon@club-internet.fr>
- //
-
- #include "swf.h"
- #include <time.h>
-
- #ifndef NOSOUND
- #include "soundcode.h"
- #endif
-
- #ifdef RCSID
- static char *rcsid = "$Id: sound.cc,v 1.11 1999/01/31 21:14:22 olivier Exp $";
- #endif
-
- #define PRINT 0
-
- //////////// SOUND
-
- Sound::Sound(long id) : Character(SoundType, id)
- {
- samples = 0;
- stereo = 0;
- soundRate = 0;
- sampleSize = 1;
- }
-
- Sound::~Sound()
- {
- if (samples) {
- delete samples;
- }
- }
-
- void
- Sound::setSoundFlags(long f) {
- switch (GET_SOUND_RATE_CODE(f)) {
- case 0:
- soundRate = 5512;
- break;
- case 1:
- soundRate = 11025;
- break;
- case 2:
- soundRate = 22050;
- break;
- case 3:
- soundRate = 44100;
- break;
- }
- if (f & soundIsStereo) stereo = 1;
- if (f & soundIs16bit) sampleSize = 2;
- }
-
- char *
- Sound::setNbSamples(long n) {
- long size;
-
- nbSamples = n;
-
- size = nbSamples * (stereo ? 2 : 1) * sampleSize;
- samples = new char[ size ];
- memset((char *)samples,0, size);
-
- return samples;
- }
-
- long
- Sound::getRate() {
- return soundRate;
- }
-
- long
- Sound::getChannel() {
- return stereo ? 2 : 1;
- }
-
- long
- Sound::getNbSamples() {
- return nbSamples;
- }
-
- long
- Sound::getSampleSize() {
- return sampleSize;
- }
-
- char *
- Sound::getSamples() {
- return samples;
- }
-
- //////////// SOUND MIXER
-
- long SoundMixer::dsp = -1; // Init of descriptor
- long SoundMixer::blockSize = 0; // Driver sound buffer size
- long SoundMixer::nbInst = 0; // Nb SoundMixer instances
- long SoundMixer::sampleSize = 0;
- long SoundMixer::stereo = 0;
- long SoundMixer::soundRate = 0;
- char *SoundMixer::buffer = 0;
-
- SoundMixer::SoundMixer(char *device)
- {
- #ifndef NOSOUND
- list = 0; // No sound to play
-
- if (nbInst++) {
- // Device is already open
- return;
- }
-
- // Set stereo channel and frequency
- stereo = 0; // set to 1 to use stereo or 0 for mono
- soundRate = 22050; // either 22050 or 44100
-
- // Get device buffer size and start playback
- if (stereo)
- blockSize = 2*soundcode_play(soundRate, 2);
- else
- blockSize = soundcode_play(soundRate, 1);
- if (blockSize < 0) {
- dsp = -1;
- return;
- }
- buffer = (char *)malloc(blockSize);
- if (!buffer) {
- soundcode_stop();
- dsp = -1;
- return;
- }
- dsp = 1;
- #endif
- }
-
- SoundMixer::~SoundMixer()
- {
- #ifndef NOSOUND
- if (--nbInst == 0) {
- if (dsp > 0) {
- soundcode_stop();
- free(buffer);
- }
- }
- #endif
- }
-
- void
- SoundMixer::stopSounds()
- {
- #ifndef NOSOUND
- SoundList *sl,*del;
-
- for(sl = list; sl; ) {
- del = sl;
- sl = sl->next;
- delete del;
- }
- list = 0;
- #endif
- }
-
-
- void
- SoundMixer::startSound(Sound *sound, long loops, long flags)
- {
- #ifndef NOSOUND
- SoundList *sl;
- int rd, wr, bytes, size;
- char *start;
-
- if (dsp < 0) return;
- if (!sound) return;
-
- if (flags == 0x01) { // no multiple
- SoundList *prev;
- char *sampleptr;
- int alreadyplaying;
-
- sl = list;
- alreadyplaying = 0;
- prev = 0;
- sampleptr = sound->getSamples();
- while (sl) {
- // scan list of sound to find one that matches
- if (sl->source == sampleptr) alreadyplaying = 1;
- sl = sl->next;
- }
- if (alreadyplaying) return;
- }
- if (flags == 0x02) { // stop
- SoundList *prev;
- char *sampleptr;
-
- sl = list;
- prev = 0;
- sampleptr = sound->getSamples();
- while (sl) {
- // scan list of sound to find one that matches
- if (sl->source == sampleptr) {
- if (prev) {
- prev->next = sl->next;
- delete sl;
- sl = prev->next;
- } else {
- list = sl->next;
- delete sl;
- sl = list;
- }
- } else
- sl = sl->next;
- }
- return;
- }
-
- // Add sound in list
- sl = new SoundList;
- sl->rate = sound->getRate();
- sl->stereo = (sound->getChannel() == 2);
- sl->sampleSize = sound->getSampleSize();
- sl->current = sound->getSamples();
- sl->source = sl->current;
- sl->remaining = sound->getSampleSize()*sound->getNbSamples()*sound->getChannel();
- sl->total = sl->remaining;
- sl->loops = loops;
- sl->next = list;
- list = sl;
- // halt playback
- soundcode_control(SOUNDCODEFLAGS_REPEAT, -1, -1, NULL, NULL, NULL, NULL, NULL);
- // get info about the unplayed samples in the buffer
- soundcode_control(-1, -1, -1, NULL, &rd, &wr, (short **)&start, &size);
- rd *= 2; // convert from samples to bytes
- wr *= 2;
- if (wr >= size) wr = 0;
- if (rd >= size) rd = 0;
- // mix sound with contents of buffer
- if (rd < wr) {
- bytes = fillSoundBuffer(sl, start + rd, wr - rd);
- } else if (rd > wr) {
- bytes = fillSoundBuffer(sl, start + rd, size - rd);
- if (sl->remaining) {
- bytes += fillSoundBuffer(sl, start, wr);
- }
- } else { // rd == wr -> buffer is empty
- // use the generic buffer filling routine
- playSounds();
- bytes = 0;
- }
- // continue playback
- soundcode_control(0, -1, -1, NULL, NULL, NULL, NULL, NULL);
- //
- if (bytes) {
- if (sl->remaining == 0) {
- list = sl->next;
- delete sl;
- }
- }
- #endif
- }
-
-
- long
- SoundMixer::playSounds()
- {
- #ifdef NOSOUND
- return 0;
- #else
- FILE *fp;
- long nbBytes, n;
- int freespace;
- SoundList *sl,*prev;
-
- // Init failed
- if (dsp < 0) return 0;
-
- // No sound to play
- if (list == 0) return 0;
-
- soundcode_readposition(NULL, &freespace);
- if (stereo)
- freespace *= 4;
- else
- freespace *= 2;
- // Free space is not large enough to output data without blocking
- // But there are still sounds to play. We must wait.
- if (freespace < blockSize) return 1;
-
- nbBytes = 0;
- // Fill buffer with silence.
- memset((void*)buffer, 0, blockSize);
- prev = 0;
- sl = list;
- while(sl) {
-
- // Ask sound to fill the buffer
- // according to device capabilities
- n = fillSoundBuffer(sl, buffer, blockSize);
-
- // Remember the largest written size
- if (n > nbBytes) {
- nbBytes = n;
- }
-
- // No more samples for this sound
- if (sl->remaining == 0) {
- // Remove sound from list
- if (prev) {
- prev->next = sl->next;
- delete sl;
- sl = prev->next;
- } else {
- list = sl->next;
- delete sl;
- sl = list;
- }
- } else {
- sl = sl->next;
- }
- break; // LJBS no mixing, one sample
- }
- if (nbBytes) {
- int used, given;
- if (stereo) {
- soundcode_fill((short *)buffer, nbBytes/(2*2), &used, &given);
- } else {
- soundcode_fill((short *)buffer, nbBytes/2, &used, &given);
- }
- }
- return nbBytes;
- #endif
- }
-
- long
- SoundMixer::fillSoundBuffer(SoundList *sl, char *buff, long buffSize)
- {
- long sampleLeft, sampleRight;
- long skipOut, skipOutInit;
- long skipIn, skipInInit;
- long freqRatio;
- long totalOut = 0;
-
- sampleLeft = sampleRight = 0;
- skipOutInit = skipInInit = 0;
-
- freqRatio = sl->rate / soundRate;
- if (freqRatio) {
- skipOutInit = freqRatio - 1;
- skipInInit = 0;
- }
-
- freqRatio = soundRate / sl->rate;
- if (freqRatio) {
- skipInInit = freqRatio - 1;
- skipOutInit = 0;
- }
-
- skipOut = skipOutInit;
- skipIn = skipInInit;
-
- if ((sl->sampleSize == 2) && (sl->stereo)) {
- // STEREO 16 BIT
- while (buffSize && sl->remaining) {
- if (skipIn-- == 0) {
- // Get sampleLeft
- sampleLeft = (long)(*(short *)(sl->current));
- sl->current += 2;
- // Get sampleRight
- sampleRight = (long)(*(short *)(sl->current));
- sl->current += 2;
-
- sl->remaining -= 2*2;
-
- skipIn = skipInInit;
- }
-
- if (skipOut-- == 0) {
- // Output
- *((short *)buff) += sampleLeft/2;
- buff += 2;
- *((short *)buff) += sampleRight/2;
- buff += 2;
-
- buffSize -= 2*2;
- totalOut += 2*2;
-
- skipOut = skipOutInit;
- }
- if (!sl->remaining)
- if (--sl->loops) {
- sl->remaining = sl->total;
- sl->current = sl->source;
- }
- }
-
- } else if (sl->sampleSize == 2) {
- // MONO 16 BIT
- while (buffSize && sl->remaining) {
- if (skipIn-- == 0) {
- // Get sampleLeft
- sampleLeft = (long)(*(short *)(sl->current));
- sl->current += 2;
- sl->remaining -= 2;
-
- skipIn = skipInInit;
- }
-
- if (skipOut-- == 0) {
- // Output
- *((short *)buff) += sampleLeft/2;
- buffSize -= 2;
- buff += 2;
- totalOut += 2;
-
- skipOut = skipOutInit;
- }
- if (!sl->remaining)
- if (--sl->loops) {
- sl->remaining = sl->total;
- sl->current = sl->source;
- }
- }
-
- } else if ((sl->sampleSize == 1) && (sl->stereo)) {
- // STEREO 8 BIT
- while (buffSize && sl->remaining) {
- if (skipIn-- == 0) {
- // Get sampleLeft
- sampleLeft = (long)*(sl->current);
- sampleLeft <<= 8;
- sl->current += 1;
- sl->remaining -= 1;
-
- // Get sampleRight
- sampleRight = (long)*(sl->current);
- sl->current += 1;
- sl->remaining -= 1;
-
- skipIn = skipInInit;
- }
-
- if (skipOut-- == 0) {
- // Output
- *((short *)buff) += sampleLeft/2;
- buffSize -= 2;
- buff += 2;
- *((short *)buff) += sampleRight/2;
- buffSize -= 2;
- buff += 2;
- totalOut += 2*2;
-
- skipOut = skipOutInit;
- }
- if (!sl->remaining)
- if (--sl->loops) {
- sl->remaining = sl->total;
- sl->current = sl->source;
- }
- }
-
- } else if (sl->sampleSize == 1) {
- // MONO 8 BIT
- while (buffSize && sl->remaining) {
- if (skipIn-- == 0) {
- // Get sampleLeft
- sampleLeft = (long)*(sl->current);
- sampleLeft <<= 8;
- sl->current += 1;
- sl->remaining -= 1;
-
- skipIn = skipInInit;
- }
-
- if (skipOut-- == 0) {
- // Output
- *((short *)buff) += sampleLeft/2;
- buffSize -= 2;
- buff += 2;
- totalOut += 2;
-
- skipOut = skipOutInit;
- }
- if (!sl->remaining)
- if (--sl->loops) {
- sl->remaining = sl->total;
- sl->current = sl->source;
- }
- }
- }
- /*
- while (buffSize && sl->remaining) {
- if (skipIn-- == 0) {
- // Get sampleLeft
- if (sl->sampleSize == 2) {
- sampleLeft = (long)(*(short *)(sl->current));
- } else {
- sampleLeft = (long)*(sl->current);
- sampleLeft <<= 8;
- }
- sl->current += sl->sampleSize;
- sl->remaining -= sl->sampleSize;
-
- if (sl->stereo) {
- // Get sampleRight
- if (sl->sampleSize == 2) {
- sampleRight = (long)(*(short *)(sl->current));
- } else {
- sampleRight = (long)*(sl->current);
- sampleRight <<= 8;
- }
- sl->current += sl->sampleSize;
- sl->remaining -= sl->sampleSize;
-
- } else {
- sampleRight = sampleLeft;
- }
-
- skipIn = skipInInit;
- }
-
- if (skipOut-- == 0) {
- // Output
- if (stereo) {
- *((short *)buff) += sampleLeft/2;
- buffSize -= 2;
- buff += 2;
- *((short *)buff) += sampleRight/2;
- buffSize -= 2;
- buff += 2;
- totalOut += 2*2;
- } else {
- *((short *)buff) += (sampleLeft+sampleRight)>>2;
- buffSize -= 2;
- buff += 2;
- totalOut += 2;
- }
-
- skipOut = skipOutInit;
- }
- }
- */
- return totalOut;
- }
-