home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Acorn User 10
/
AU_CD10.iso
/
Archived
/
Updates
/
Flash
/
flashplayer
/
flashlib
/
c++
/
sound
< prev
next >
Wrap
Text File
|
2000-06-04
|
13KB
|
561 lines
/////////////////////////////////////////////////////////////
// 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;
}