| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137 |
- //
- // Urho3D Engine
- // Copyright (c) 2008-2011 Lasse Öörni
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- //
- #include "Precompiled.h"
- #include "Audio.h"
- #include "Channel.h"
- #include "Sound.h"
- #include <cstring>
- #include "DebugNew.h"
- #define INC_POS_LOOPED() \
- pos += intAdd; \
- fractPos += fractAdd; \
- if (fractPos > 65535) \
- { \
- fractPos &= 65535; \
- ++pos; \
- } \
- while (pos >= end) \
- pos -= (end - repeat); \
- #define INC_POS_ONESHOT() \
- pos += intAdd; \
- fractPos += fractAdd; \
- if (fractPos > 65535) \
- { \
- fractPos &= 65535; \
- ++pos; \
- } \
- if (pos >= end) \
- { \
- pos = 0; \
- break; \
- } \
- #define INC_POS_STEREO_LOOPED() \
- pos += (intAdd << 1); \
- fractPos += fractAdd; \
- if (fractPos > 65535) \
- { \
- fractPos &= 65535; \
- pos += 2; \
- } \
- while (pos >= end) \
- pos -= (end - repeat); \
- #define INC_POS_STEREO_ONESHOT() \
- pos += (intAdd << 1); \
- fractPos += fractAdd; \
- if (fractPos > 65535) \
- { \
- fractPos &= 65535; \
- pos += 2; \
- } \
- if (pos >= end) \
- { \
- pos = 0; \
- break; \
- } \
- #define GET_IP_SAMPLE() (((((int)pos[1] - (int)pos[0]) * fractPos) / 65536) + (int)pos[0])
- #define GET_IP_SAMPLE_LEFT() (((((int)pos[2] - (int)pos[0]) * fractPos) / 65536) + (int)pos[0])
- #define GET_IP_SAMPLE_RIGHT() (((((int)pos[3] - (int)pos[1]) * fractPos) / 65536) + (int)pos[1])
- // Compressed audio decode buffer length in milliseconds
- static const int DECODE_BUFFER_LENGTH = 100;
- Channel::Channel(Audio* audio) :
- mAudio(audio),
- mPos(0),
- mFractPos(0),
- mTimePos(0.0f),
- mChannelType(CHANNEL_EFFECT),
- mFrequency(0.0f),
- mGain(1.0f),
- mAttenuation(1.0f),
- mPanning(0.0f),
- mDecoder(0),
- mDecodePos(0)
- {
- if (mAudio)
- mAudio->addChannel(this);
- }
- Channel::~Channel()
- {
- if (mAudio)
- mAudio->removeChannel(this);
-
- freeDecoder();
- }
- void Channel::play(Sound* sound)
- {
- if (!mAudio)
- return;
-
- // If channel is currently playing, have to lock the audio mutex
- if (mPos)
- {
- MutexLock lock(mAudio->getMutex());
- playLockless(sound);
- }
- else
- playLockless(sound);
- }
- void Channel::play(Sound* sound, float frequency)
- {
- setFrequency(frequency);
- play(sound);
- }
- void Channel::play(Sound* sound, float frequency, float gain)
- {
- setFrequency(frequency);
- setGain(gain);
- play(sound);
- }
- void Channel::play(Sound* sound, float frequency, float gain, float panning)
- {
- setFrequency(frequency);
- setGain(gain);
- setPanning(panning);
- play(sound);
- }
- void Channel::stop()
- {
- if (!mAudio)
- return;
-
- // If channel is currently playing, have to lock the audio mutex
- if (mPos)
- {
- MutexLock lock(mAudio->getMutex());
- stopLockless();
- }
-
- // Free the compressed sound decoder now if any
- freeDecoder();
- mSound.reset();
- }
- void Channel::setChannelType(ChannelType type)
- {
- if ((type == CHANNEL_MASTER) || (type >= MAX_CHANNEL_TYPES))
- return;
-
- mChannelType = type;
- }
- void Channel::setFrequency(float frequency)
- {
- mFrequency = clamp(frequency, 0.0f, 535232.0f);
- }
- void Channel::setGain(float gain)
- {
- mGain = max(gain, 0.0f);
- }
- void Channel::setAttenuation(float attenuation)
- {
- mAttenuation = clamp(attenuation, 0.0f, 1.0f);
- }
- void Channel::setPanning(float panning)
- {
- mPanning = clamp(panning, -1.0f, 1.0f);
- }
- void Channel::setIntFrequency(unsigned frequency)
- {
- mFrequency = clamp((float)frequency, 0.0f, 535232.0f);
- }
- void Channel::setIntVolume(int volume)
- {
- mGain = max((float)volume / 64.0f, 0.0f);
- }
- void Channel::setIntPanning(int panning)
- {
- mPanning = clamp(((float)panning / 255.0f) * 2.0f - 1.0f, -1.0f, 1.0f);
- }
- bool Channel::isPlaying() const
- {
- return mSound.getPtr() != 0;
- }
- void Channel::setPlayPosition(signed char* pos)
- {
- if ((!mAudio) || (!mSound))
- return;
-
- MutexLock lock(mAudio->getMutex());
- setPlayPositionLockless(pos);
- }
- void Channel::playLockless(Sound* sound)
- {
- // Reset the time position in any case
- mTimePos = 0.0f;
-
- if (sound)
- {
- if (!sound->isCompressed())
- {
- // Uncompressed sound start
- signed char* start = sound->getStart();
- if (start)
- {
- // Free decoder in case previous sound was compressed
- freeDecoder();
- mSound = sound;
- mPos = start;
- mFractPos = 0;
- return;
- }
- }
- else
- {
- // Compressed sound start
- if (sound == mSound)
- {
- // If same compressed sound is already playing, rewind the decoder
- mSound->rewindDecoder(mDecoder);
- return;
- }
- else
- {
- // Else just set the new sound with a dummy start position. The mixing routine will allocate the new decoder
- freeDecoder();
- mSound = sound;
- mPos = sound->getStart();
- return;
- }
- }
- }
-
- // If sound pointer is null or if sound has no data, stop playback
- freeDecoder();
- mSound.reset();
- mPos = 0;
- }
- void Channel::stopLockless()
- {
- mPos = 0;
- mTimePos = 0.0f;
- }
- void Channel::setPlayPositionLockless(signed char* pos)
- {
- // Setting position on a compressed sound is not supported
- if ((!mSound) || (mSound->isCompressed()))
- return;
-
- signed char* start = mSound->getStart();
- signed char* end = mSound->getEnd();
- if (pos < start)
- pos = start;
- if ((mSound->isSixteenBit()) && ((pos - start) & 1))
- ++pos;
- if (pos > end)
- pos = end;
-
- mPos = pos;
- mTimePos = (float)((int)pos - (int)mSound->getStart()) / (mSound->getSampleSize() * mSound->getFrequency());
- }
- void Channel::update(float timeStep)
- {
- if (!mAudio)
- return;
-
- // If there is no actual audio output, perform fake mixing into a nonexistent buffer to check stopping/looping
- if (!mAudio->hasBuffer())
- mixNull(timeStep);
-
- // Free the sound if playback has stopped
- if ((mSound) && (!mPos))
- {
- freeDecoder();
- mSound.reset();
- }
- }
- void Channel::mix(int* dest, unsigned samples, int mixRate, bool stereo, bool interpolate)
- {
- if ((!mPos) || (!mSound))
- return;
-
- if (mSound->isCompressed())
- {
- if (mDecoder)
- {
- // If decoder already exists, decode new compressed audio
- bool eof = false;
- unsigned currentPos = mPos - mDecodeBuffer->getStart();
- if (currentPos != mDecodePos)
- {
- // If buffer has wrapped, decode first to the end
- if (currentPos < mDecodePos)
- {
- unsigned bytes = mDecodeBuffer->getDataSize() - mDecodePos;
- unsigned outBytes = mSound->decode(mDecoder, mDecodeBuffer->getStart() + mDecodePos, bytes);
- // If produced less output, end of sound encountered. Fill rest with zero
- if (outBytes < bytes)
- {
- memset(mDecodeBuffer->getStart() + mDecodePos + outBytes, 0, bytes - outBytes);
- eof = true;
- }
- mDecodePos = 0;
- }
- if (currentPos > mDecodePos)
- {
- unsigned bytes = currentPos - mDecodePos;
- unsigned outBytes = mSound->decode(mDecoder, mDecodeBuffer->getStart() + mDecodePos, bytes);
- // If produced less output, end of sound encountered. Fill rest with zero
- if (outBytes < bytes)
- {
- memset(mDecodeBuffer->getStart() + mDecodePos + outBytes, 0, bytes - outBytes);
- if (mSound->isLooped())
- eof = true;
- }
-
- // If wrote to buffer start, correct interpolation wraparound
- if (!mDecodePos)
- mDecodeBuffer->fixInterpolation();
- }
- }
-
- // If end of stream encountered, check whether we should rewind or stop
- if (eof)
- {
- if (mSound->isLooped())
- {
- mSound->rewindDecoder(mDecoder);
- mTimePos = 0.0f;
- }
- else
- mDecodeBuffer->setOneshot(); // Stop after the current decode buffer has been played
- }
-
- mDecodePos = currentPos;
- }
- else
- {
- // Setup the decoder and decode buffer
- mDecoder = mSound->allocateDecoder();
- unsigned sampleSize = mSound->getSampleSize();
- unsigned decodeBufferSize = sampleSize * mSound->getIntFrequency() * DECODE_BUFFER_LENGTH / 1000;
- mDecodeBuffer = new Sound();
- mDecodeBuffer->setSize(decodeBufferSize);
- mDecodeBuffer->setFormat(mSound->getIntFrequency(), true, mSound->isStereo());
-
- // Clear the decode buffer, then fill with initial audio data and set it to loop
- memset(mDecodeBuffer->getStart(), 0, decodeBufferSize);
- mSound->decode(mDecoder, mDecodeBuffer->getStart(), decodeBufferSize);
- mDecodeBuffer->setLooped();
- mDecodePos = 0;
-
- // Start playing the decode buffer
- mPos = mDecodeBuffer->getStart();
- mFractPos = 0;
- }
- }
-
- // If compressed, play the decode buffer. Otherwise play the original sound
- Sound* sound = mSound->isCompressed() ? mDecodeBuffer : mSound;
- if (!sound)
- return;
-
- // Choose the correct mixing routine
- if (!sound->isStereo())
- {
- if (interpolate)
- {
- if (stereo)
- mixMonoToStereoIP(sound, dest, samples, mixRate);
- else
- mixMonoToMonoIP(sound, dest, samples, mixRate);
- }
- else
- {
- if (stereo)
- mixMonoToStereo(sound, dest, samples, mixRate);
- else
- mixMonoToMono(sound, dest, samples, mixRate);
- }
- }
- else
- {
- if (interpolate)
- {
- if (stereo)
- mixStereoToStereoIP(sound, dest, samples, mixRate);
- else
- mixStereoToMonoIP(sound, dest, samples, mixRate);
- }
- else
- {
- if (stereo)
- mixStereoToStereo(sound, dest, samples, mixRate);
- else
- mixStereoToMono(sound, dest, samples, mixRate);
- }
- }
-
- // Update the time position
- if (!mSound->isCompressed())
- mTimePos = (float)((int)mPos - (int)mSound->getStart()) / (mSound->getSampleSize() * mSound->getFrequency());
- else
- mTimePos += ((float)samples / (float)mixRate) * mFrequency / mSound->getFrequency();
- }
- void Channel::mixMonoToMono(Sound* sound, int* dest, unsigned samples, int mixRate)
- {
- float totalGain = mAudio->getChannelMasterGain(mChannelType) * mAttenuation * mGain;
- int vol = (int)(256.0f * totalGain + 0.5f);
- if (!vol)
- {
- mixZeroVolume(sound, samples, mixRate);
- return;
- }
-
- float add = mFrequency / (float)mixRate;
- int intAdd = (int)add;
- int fractAdd = (int)((add - floorf(add)) * 65536.0f);
- int fractPos = mFractPos;
-
- if (sound->isSixteenBit())
- {
- short* pos = (short*)mPos;
- short* end = (short*)sound->getEnd();
- short* repeat = (short*)sound->getRepeat();
-
- if (sound->isLooped())
- {
- while (samples--)
- {
- *dest = *dest + (*pos * vol) / 256;
- ++dest;
- INC_POS_LOOPED();
- }
- mPos = (signed char*)pos;
- }
- else
- {
- while (samples--)
- {
- *dest = *dest + (*pos * vol) / 256;
- ++dest;
- INC_POS_ONESHOT();
- }
- mPos = (signed char*)pos;
- }
- }
- else
- {
- signed char* pos = (signed char*)mPos;
- signed char* end = sound->getEnd();
- signed char* repeat = sound->getRepeat();
-
- if (sound->isLooped())
- {
- while (samples--)
- {
- *dest = *dest + *pos * vol;
- ++dest;
- INC_POS_LOOPED();
- }
- mPos = pos;
- }
- else
- {
- while (samples--)
- {
- *dest = *dest + *pos * vol;
- ++dest;
- INC_POS_ONESHOT();
- }
- mPos = pos;
- }
- }
-
- mFractPos = fractPos;
- }
- void Channel::mixMonoToStereo(Sound* sound, int* dest, unsigned samples, int mixRate)
- {
- float totalGain = mAudio->getChannelMasterGain(mChannelType) * mAttenuation * mGain;
- int leftVol = (int)((-mPanning + 1.0f) * (256.0f * totalGain + 0.5f));
- int rightVol = (int)((mPanning + 1.0f) * (256.0f * totalGain + 0.5f));
- if ((!leftVol) && (!rightVol))
- {
- mixZeroVolume(sound, samples, mixRate);
- return;
- }
-
- float add = mFrequency / (float)mixRate;
- int intAdd = (int)add;
- int fractAdd = (int)((add - floorf(add)) * 65536.0f);
- int fractPos = mFractPos;
-
- if (sound->isSixteenBit())
- {
- short* pos = (short*)mPos;
- short* end = (short*)sound->getEnd();
- short* repeat = (short*)sound->getRepeat();
-
- if (sound->isLooped())
- {
- while (samples--)
- {
- *dest = *dest + (*pos * leftVol) / 256;
- ++dest;
- *dest = *dest + (*pos * rightVol) / 256;
- ++dest;
- INC_POS_LOOPED();
- }
- mPos = (signed char*)pos;
- }
- else
- {
- while (samples--)
- {
- *dest = *dest + (*pos * leftVol) / 256;
- ++dest;
- *dest = *dest + (*pos * rightVol) / 256;
- ++dest;
- INC_POS_ONESHOT();
- }
- mPos = (signed char*)pos;
- }
- }
- else
- {
- signed char* pos = (signed char*)mPos;
- signed char* end = sound->getEnd();
- signed char* repeat = sound->getRepeat();
-
- if (sound->isLooped())
- {
- while (samples--)
- {
- *dest = *dest + *pos * leftVol;
- ++dest;
- *dest = *dest + *pos * rightVol;
- ++dest;
- INC_POS_LOOPED();
- }
- mPos = pos;
- }
- else
- {
- while (samples--)
- {
- *dest = *dest + *pos * leftVol;
- ++dest;
- *dest = *dest + *pos * rightVol;
- ++dest;
- INC_POS_ONESHOT();
- }
- mPos = pos;
- }
- }
-
- mFractPos = fractPos;
- }
- void Channel::mixMonoToMonoIP(Sound* sound, int* dest, unsigned samples, int mixRate)
- {
- float totalGain = mAudio->getChannelMasterGain(mChannelType) * mAttenuation * mGain;
- int vol = (int)(256.0f * totalGain + 0.5f);
- if (!vol)
- {
- mixZeroVolume(sound, samples, mixRate);
- return;
- }
-
- float add = mFrequency / (float)mixRate;
- int intAdd = (int)add;
- int fractAdd = (int)((add - floorf(add)) * 65536.0f);
- int fractPos = mFractPos;
-
- if (sound->isSixteenBit())
- {
- short* pos = (short*)mPos;
- short* end = (short*)sound->getEnd();
- short* repeat = (short*)sound->getRepeat();
-
- if (sound->isLooped())
- {
- while (samples--)
- {
- *dest = *dest + (GET_IP_SAMPLE() * vol) / 256;
- ++dest;
- INC_POS_LOOPED();
- }
- mPos = (signed char*)pos;
- }
- else
- {
- while (samples--)
- {
- *dest = *dest + (GET_IP_SAMPLE() * vol) / 256;
- ++dest;
- INC_POS_ONESHOT();
- }
- mPos = (signed char*)pos;
- }
- }
- else
- {
- signed char* pos = (signed char*)mPos;
- signed char* end = sound->getEnd();
- signed char* repeat = sound->getRepeat();
-
- if (sound->isLooped())
- {
- while (samples--)
- {
- *dest = *dest + GET_IP_SAMPLE() * vol;
- ++dest;
- INC_POS_LOOPED();
- }
- mPos = pos;
- }
- else
- {
- while (samples--)
- {
- *dest = *dest + GET_IP_SAMPLE() * vol;
- ++dest;
- INC_POS_ONESHOT();
- }
- mPos = pos;
- }
- }
-
- mFractPos = fractPos;
- }
- void Channel::mixMonoToStereoIP(Sound* sound, int* dest, unsigned samples, int mixRate)
- {
- float totalGain = mAudio->getChannelMasterGain(mChannelType) * mAttenuation * mGain;
- int leftVol = (int)((-mPanning + 1.0f) * (256.0f * totalGain + 0.5f));
- int rightVol = (int)((mPanning + 1.0f) * (256.0f * totalGain + 0.5f));
- if ((!leftVol) && (!rightVol))
- {
- mixZeroVolume(sound, samples, mixRate);
- return;
- }
-
- float add = mFrequency / (float)mixRate;
- int intAdd = (int)add;
- int fractAdd = (int)((add - floorf(add)) * 65536.0f);
- int fractPos = mFractPos;
-
- if (sound->isSixteenBit())
- {
- short* pos = (short*)mPos;
- short* end = (short*)sound->getEnd();
- short* repeat = (short*)sound->getRepeat();
-
- if (sound->isLooped())
- {
- while (samples--)
- {
- int s = GET_IP_SAMPLE();
- *dest = *dest + (s * leftVol) / 256;
- ++dest;
- *dest = *dest + (s * rightVol) / 256;
- ++dest;
- INC_POS_LOOPED();
- }
- mPos = (signed char*)pos;
- }
- else
- {
- while (samples--)
- {
- int s = GET_IP_SAMPLE();
- *dest = *dest + (s * leftVol) / 256;
- ++dest;
- *dest = *dest + (s * rightVol) / 256;
- ++dest;
- INC_POS_ONESHOT();
- }
- mPos = (signed char*)pos;
- }
- }
- else
- {
- signed char* pos = (signed char*)mPos;
- signed char* end = sound->getEnd();
- signed char* repeat = sound->getRepeat();
-
- if (sound->isLooped())
- {
- while (samples--)
- {
- int s = GET_IP_SAMPLE();
- *dest = *dest + s * leftVol;
- ++dest;
- *dest = *dest + s * rightVol;
- ++dest;
- INC_POS_LOOPED();
- }
- mPos = pos;
- }
- else
- {
- while (samples--)
- {
- int s = GET_IP_SAMPLE();
- *dest = *dest + s * leftVol;
- ++dest;
- *dest = *dest + s * rightVol;
- ++dest;
- INC_POS_ONESHOT();
- }
- mPos = pos;
- }
- }
-
- mFractPos = fractPos;
- }
- void Channel::mixStereoToMono(Sound* sound, int* dest, unsigned samples, int mixRate)
- {
- float totalGain = mAudio->getChannelMasterGain(mChannelType) * mAttenuation * mGain;
- int vol = (int)(256.0f * totalGain + 0.5f);
- if (!vol)
- {
- mixZeroVolume(sound, samples, mixRate);
- return;
- }
-
- float add = mFrequency / (float)mixRate;
- int intAdd = (int)add;
- int fractAdd = (int)((add - floorf(add)) * 65536.0f);
- int fractPos = mFractPos;
-
- if (sound->isSixteenBit())
- {
- short* pos = (short*)mPos;
- short* end = (short*)sound->getEnd();
- short* repeat = (short*)sound->getRepeat();
-
- if (sound->isLooped())
- {
- while (samples--)
- {
- int s = ((int)pos[0] + (int)pos[1]) / 2;
- *dest = *dest + (s * vol) / 256;
- ++dest;
- INC_POS_STEREO_LOOPED();
- }
- mPos = (signed char*)pos;
- }
- else
- {
- while (samples--)
- {
- int s = ((int)pos[0] + (int)pos[1]) / 2;
- *dest = *dest + (s * vol) / 256;
- ++dest;
- INC_POS_STEREO_ONESHOT();
- }
- mPos = (signed char*)pos;
- }
- }
- else
- {
- signed char* pos = (signed char*)mPos;
- signed char* end = sound->getEnd();
- signed char* repeat = sound->getRepeat();
-
- if (sound->isLooped())
- {
- while (samples--)
- {
- int s = ((int)pos[0] + (int)pos[1]) / 2;
- *dest = *dest + s * vol;
- ++dest;
- INC_POS_STEREO_LOOPED();
- }
- mPos = pos;
- }
- else
- {
- while (samples--)
- {
- int s = ((int)pos[0] + (int)pos[1]) / 2;
- *dest = *dest + s * vol;
- ++dest;
- INC_POS_STEREO_ONESHOT();
- }
- mPos = pos;
- }
- }
-
- mFractPos = fractPos;
- }
- void Channel::mixStereoToStereo(Sound* sound, int* dest, unsigned samples, int mixRate)
- {
- float totalGain = mAudio->getChannelMasterGain(mChannelType) * mAttenuation * mGain;
- int vol = (int)(256.0f * totalGain + 0.5f);
- if (!vol)
- {
- mixZeroVolume(sound, samples, mixRate);
- return;
- }
-
- float add = mFrequency / (float)mixRate;
- int intAdd = (int)add;
- int fractAdd = (int)((add - floorf(add)) * 65536.0f);
- int fractPos = mFractPos;
-
- if (sound->isSixteenBit())
- {
- short* pos = (short*)mPos;
- short* end = (short*)sound->getEnd();
- short* repeat = (short*)sound->getRepeat();
-
- if (sound->isLooped())
- {
- while (samples--)
- {
- *dest = *dest + (pos[0] * vol) / 256;
- ++dest;
- *dest = *dest + (pos[1] * vol) / 256;
- ++dest;
- INC_POS_STEREO_LOOPED();
- }
- mPos = (signed char*)pos;
- }
- else
- {
- while (samples--)
- {
- *dest = *dest + (pos[0] * vol) / 256;
- ++dest;
- *dest = *dest + (pos[1] * vol) / 256;
- ++dest;
- INC_POS_STEREO_ONESHOT();
- }
- mPos = (signed char*)pos;
- }
- }
- else
- {
- signed char* pos = (signed char*)mPos;
- signed char* end = sound->getEnd();
- signed char* repeat = sound->getRepeat();
-
- if (sound->isLooped())
- {
- while (samples--)
- {
- *dest = *dest + pos[0] * vol;
- ++dest;
- *dest = *dest + pos[1] * vol;
- ++dest;
- INC_POS_STEREO_LOOPED();
- }
- mPos = pos;
- }
- else
- {
- while (samples--)
- {
- *dest = *dest + pos[0] * vol;
- ++dest;
- *dest = *dest + pos[1] * vol;
- ++dest;
- INC_POS_STEREO_ONESHOT();
- }
- mPos = pos;
- }
- }
-
- mFractPos = fractPos;
- }
- void Channel::mixStereoToMonoIP(Sound* sound, int* dest, unsigned samples, int mixRate)
- {
- float totalGain = mAudio->getChannelMasterGain(mChannelType) * mAttenuation * mGain;
- int vol = (int)(256.0f * totalGain + 0.5f);
- if (!vol)
- {
- mixZeroVolume(sound, samples, mixRate);
- return;
- }
-
- float add = mFrequency / (float)mixRate;
- int intAdd = (int)add;
- int fractAdd = (int)((add - floorf(add)) * 65536.0f);
- int fractPos = mFractPos;
-
- if (sound->isSixteenBit())
- {
- short* pos = (short*)mPos;
- short* end = (short*)sound->getEnd();
- short* repeat = (short*)sound->getRepeat();
-
- if (sound->isLooped())
- {
- while (samples--)
- {
- int s = (GET_IP_SAMPLE_LEFT() + GET_IP_SAMPLE_RIGHT()) / 2;
- *dest = *dest + (s * vol) / 256;
- ++dest;
- INC_POS_STEREO_LOOPED();
- }
- mPos = (signed char*)pos;
- }
- else
- {
- while (samples--)
- {
- int s = (GET_IP_SAMPLE_LEFT() + GET_IP_SAMPLE_RIGHT()) / 2;
- *dest = *dest + (s * vol) / 256;
- ++dest;
- INC_POS_STEREO_ONESHOT();
- }
- mPos = (signed char*)pos;
- }
- }
- else
- {
- signed char* pos = (signed char*)mPos;
- signed char* end = sound->getEnd();
- signed char* repeat = sound->getRepeat();
-
- if (sound->isLooped())
- {
- while (samples--)
- {
- int s = (GET_IP_SAMPLE_LEFT() + GET_IP_SAMPLE_RIGHT()) / 2;
- *dest = *dest + s * vol;
- ++dest;
- INC_POS_STEREO_LOOPED();
- }
- mPos = pos;
- }
- else
- {
- while (samples--)
- {
- int s = (GET_IP_SAMPLE_LEFT() + GET_IP_SAMPLE_RIGHT()) / 2;
- *dest = *dest + s * vol;
- ++dest;
- INC_POS_STEREO_ONESHOT();
- }
- mPos = pos;
- }
- }
-
- mFractPos = fractPos;
- }
- void Channel::mixStereoToStereoIP(Sound* sound, int* dest, unsigned samples, int mixRate)
- {
- float totalGain = mAudio->getChannelMasterGain(mChannelType) * mAttenuation * mGain;
- int vol = (int)(256.0f * totalGain + 0.5f);
- if (!vol)
- {
- mixZeroVolume(sound, samples, mixRate);
- return;
- }
-
- float add = mFrequency / (float)mixRate;
- int intAdd = (int)add;
- int fractAdd = (int)((add - floorf(add)) * 65536.0f);
- int fractPos = mFractPos;
-
- if (sound->isSixteenBit())
- {
- short* pos = (short*)mPos;
- short* end = (short*)sound->getEnd();
- short* repeat = (short*)sound->getRepeat();
-
- if (sound->isLooped())
- {
- while (samples--)
- {
- *dest = *dest + (GET_IP_SAMPLE_LEFT() * vol) / 256;
- ++dest;
- *dest = *dest + (GET_IP_SAMPLE_RIGHT() * vol) / 256;
- ++dest;
- INC_POS_STEREO_LOOPED();
- }
- mPos = (signed char*)pos;
- }
- else
- {
- while (samples--)
- {
- *dest = *dest + (GET_IP_SAMPLE_LEFT() * vol) / 256;
- ++dest;
- *dest = *dest + (GET_IP_SAMPLE_RIGHT() * vol) / 256;
- ++dest;
- INC_POS_STEREO_ONESHOT();
- }
- mPos = (signed char*)pos;
- }
- }
- else
- {
- signed char* pos = (signed char*)mPos;
- signed char* end = sound->getEnd();
- signed char* repeat = sound->getRepeat();
-
- if (sound->isLooped())
- {
- while (samples--)
- {
- *dest = *dest + GET_IP_SAMPLE_LEFT() * vol;
- ++dest;
- *dest = *dest + GET_IP_SAMPLE_RIGHT() * vol;
- ++dest;
- INC_POS_STEREO_LOOPED();
- }
- mPos = pos;
- }
- else
- {
- while (samples--)
- {
- *dest = *dest + GET_IP_SAMPLE_LEFT() * vol;
- ++dest;
- *dest = *dest + GET_IP_SAMPLE_RIGHT() * vol;
- ++dest;
- INC_POS_STEREO_ONESHOT();
- }
- mPos = pos;
- }
- }
-
- mFractPos = fractPos;
- }
- void Channel::mixZeroVolume(Sound* sound, unsigned samples, int mixRate)
- {
- float add = mFrequency * (float)samples / (float)mixRate;
- int intAdd = (int)add;
- int fractAdd = (int)((add - floorf(add)) * 65536.0f);
- unsigned sampleSize = sound->getSampleSize();
-
- mFractPos += fractAdd;
- if (mFractPos > 65535)
- {
- mFractPos &= 65535;
- mPos += sampleSize;
- }
- mPos += intAdd * sampleSize;
-
- if (mPos > sound->getEnd())
- {
- if (sound->isLooped())
- {
- while (mPos >= sound->getEnd())
- {
- mPos -= (sound->getEnd() - sound->getRepeat());
- }
- }
- else
- mPos = 0;
- }
- }
- void Channel::mixNull(float timeStep)
- {
- if ((!mPos) || (!mSound))
- return;
-
- // Advance only the time position
- mTimePos += timeStep * mFrequency / mSound->getFrequency();
-
- if (mSound->isLooped())
- {
- // For simulated playback, simply reset the time position to zero when the sound loops
- if (mTimePos >= mSound->getLength())
- mTimePos -= mSound->getLength();
- }
- else
- {
- if (mTimePos >= mSound->getLength())
- {
- mPos = 0;
- mTimePos = 0.0f;
- }
- }
- }
- void Channel::freeDecoder()
- {
- if ((mSound) && (mDecoder))
- {
- mSound->freeDecoder(mDecoder);
- mDecoder = 0;
- }
-
- mDecodeBuffer.reset();
- }
|