bool SoundManager::createOggMixer( bool stereoOutput)
{
if(stereoOutput)
{
if(s3eSoundGetInt(S3E_SOUND_STEREO_ENABLED))
deviceIsStereo = true;
}
int nSoundChannel = s3eSoundGetFreeChannel();
if(nSoundChannel == -1)
return false;
if(deviceIsStereo)
{
s3eSoundChannelRegister(nSoundChannel, S3E_CHANNEL_GEN_AUDIO, generateAudioCallback, this );
s3eSoundChannelRegister(nSoundChannel, S3E_CHANNEL_GEN_AUDIO_STEREO, generateAudioCallback, this );
}
else
s3eSoundChannelRegister(nSoundChannel, S3E_CHANNEL_GEN_AUDIO, generateAudioCallback, this );
int16 dummydata[16];
s3eSoundChannelPlay(nSoundChannel, dummydata, 8, 0, 0);
return true;
}
resources::RSound* SoundManager::Sample_Create(char const* sample, char const* pakfilename )
{
resources::RSound* mNewSample = _S(SoundManager)->getSound( sample );
if( mNewSample )
{
mNewSample->inc();
return mNewSample;
}
if( strstr( sample, ".ogg" ) || strstr( sample, ".OGG" ) )
mNewSample = COggSound::OggSample_Create( sample, pakfilename );
if( strstr( sample, ".wav" ) || strstr( sample, ".WAV" ) )
mNewSample = CWavSound::WavSample_Create( sample, pakfilename );
if( !mNewSample )
{
return NULL;
}
_S( SoundManager )->addSound( mNewSample );
return mNewSample;
}
тут у меня определяется по расширению что мы закачиваем и проигрываем - wav или ogg и соотвественно две реализации звуковых классов
которые унаследованы от одного базового класса RSound
загрузка и проигрыванеи звука внутри приложения выглядит примерно так
m_sample = framework::SoundManager::Sample_Create( "0091670256.wav" );
m_sample->play( false );
или если нам надо звук проигрывать бесконечно то так:
m_sample = framework::SoundManager::Sample_Create( "0091670256.wav" );
m_sample->play( true );
список семплов который проигрывается сейчас это просто массив + переменная в который храним сколько семплов в масиве в данный момент
MAX_SOUNDQUEUE я установил в 64.
int m_PlayingSamplesListLength;
resources::RSound* m_PlayingSamplesList[ MAX_SOUNDQUEUE ];
функция play содержит в себе крит секцию и добавление очередного семпла в список она вызывается изнутри звукового класса и сам объект передает в нее указатель на себя любимого.
bool SoundManager::play( resources::RSound* sample )
{
s3eThreadLockAcquire( m_Section );
if( m_PlayingSamplesListLength + 1 >= MAX_SOUNDQUEUE )
return false;
m_PlayingSamplesList[ m_PlayingSamplesListLength ] = sample;
m_PlayingSamplesListLength++;
s3eThreadLockRelease( m_Section );
return true;
}
главная каллбэк функция у меня выглядит так:
int32 SoundManager::generateAudioCallback(void* sys, void* user)
{
return ((SoundManager*)user)->generateAudioCallback( sys );
}
int32 SoundManager::generateAudioCallback( void* sys )
{
s3eThreadLockAcquire( m_Section );
int samplesAvailable = 0;
s3eSoundGenAudioInfo* info = (s3eSoundGenAudioInfo*)sys;
int16* target = (int16*)info->m_Target;
int inputSampleSize = true == deviceIsStereo ? 2 : 1;
memset(info->m_Target, 0, info->m_NumSamples * inputSampleSize * sizeof(int16));
formActiveChannelsAndDecode( samplesAvailable );
if( 0 == samplesAvailable )
{
s3eThreadLockRelease( m_Section );
removeDoneChannels();
return info->m_NumSamples;
}
int32 samplesMixed = mixSounds(info->m_NumSamples, samplesAvailable, target);
removeDoneChannels();
s3eThreadLockRelease( m_Section );
return samplesMixed;
}
сначала мы подсчитываем сколько всего семплов у нас готовы к проигрыванию в данный момент времени
void SoundManager::formActiveChannelsAndDecode( int& samplesAvailable )
{
samplesAvailable = 0x7FFFFFF;
if( 0 == m_PlayingSamplesListLength )
{
samplesAvailable = 0;
return;
}
for( int i = 0; i < m_PlayingSamplesListLength; i++ )
{
resources::RSound *channel = m_PlayingSamplesList[ i ];
if(!channel->isPaused() && !channel->isDone())
{
channel->decode();
int samplesReady = channel->get_decbufspace();
if(samplesAvailable > samplesReady)
samplesAvailable = samplesReady;
}
}
if( 0x7FFFFFF == samplesAvailable )
samplesAvailable = 0;
}
в этой функции происходит обработка звуков со всех проигрываемых семплов и заполнение данными канала.
int32 SoundManager::mixSounds(int numSamples, int hasSamples, int16* target)
{
numSamples = numSamples * 2 > hasSamples ? hasSamples / 2 : numSamples;
for(int i = 0; i < numSamples; ++i)
{
int16 yLeft = 0;
int16 yRight = 0;
for( int i = 0; i < m_PlayingSamplesListLength; i++ )
{
resources::RSound *channel = m_PlayingSamplesList[ i ];
yLeft = clipToInt16( yLeft + ((channel->getSampleL() * channel->volume) >> 8) );
yRight = clipToInt16( yRight + ((channel->getSampleR() * channel->volume) >> 8) );
channel->incSampleCounter();
}
*target++ = yLeft;
if(deviceIsStereo)
*target++ = yRight;
}
return numSamples;
}
и удаление из списка семплов которые отыглали свое или их застопили.