BGameSound: cleanup and several fixes

* Use a template to avoid repeating the panning code for each type
* Rearrange the initialization of BSimpleGameSound so the data is only
copied 0 or 1 times (it was copied 2 or 3 times in some cases) between
the passed buffer and the final one,
* Don't execute the panning code on streams with only 1 channel as this
makes no sense and it will read and write outside the buffers
* Abort early in GameSoundBuffer::Play if fIsPlaying is false.

Fix the crashes in Worms Armageddon. Doesn't fix the sounds being mostly
white noise.
This commit is contained in:
Adrien Destugues 2014-12-11 16:02:59 +01:00
parent 94d14479bb
commit bf57c148f7
3 changed files with 73 additions and 82 deletions

View File

@ -44,35 +44,12 @@
// Sound Buffer Utility functions ---------------------------------------- // Sound Buffer Utility functions ----------------------------------------
inline void template<typename T>
ApplyMod(uint8 * data, uint8 * buffer, int64 index, float gain, float * pan) static inline void
ApplyMod(T* data, T* buffer, int64 index, float * pan)
{ {
data[index * 2] += uint8(float(buffer[index * 2]) * gain * pan[0]); data[index * 2] += T(float(buffer[index * 2]) * pan[0]);
data[index * 2 + 1] += uint8(float(buffer[index * 2 + 1]) * gain * pan[1]); data[index * 2 + 1] += T(float(buffer[index * 2 + 1]) * pan[1]);
}
inline void
ApplyMod(int16 * data, int16 * buffer, int32 index, float gain, float * pan)
{
data[index * 2] = int16(float(buffer[index * 2]) * gain * pan[0]);
data[index * 2 + 1] = int16(float(buffer[index * 2 + 1]) * gain * pan[1]);
}
inline void
ApplyMod(int32 * data, int32 * buffer, int32 index, float gain, float * pan)
{
data[index * 2] += int32(float(buffer[index * 2]) * gain * pan[0]);
data[index * 2 + 1] += int32(float(buffer[index * 2 + 1]) * gain * pan[1]);
}
inline void
ApplyMod(float * data, float * buffer, int32 index, float gain, float * pan)
{
data[index * 2] += buffer[index * 2] * gain * pan[0];
data[index * 2 + 1] += buffer[index * 2 + 1] * gain * pan[1];
} }
@ -94,7 +71,7 @@ GameSoundBuffer::GameSoundBuffer(const gs_audio_format * format)
fFrameSize = get_sample_size(format->format) * format->channel_count; fFrameSize = get_sample_size(format->format) * format->channel_count;
memcpy(&fFormat, format, sizeof(gs_audio_format)); fFormat = *format;
} }
@ -270,9 +247,14 @@ GameSoundBuffer::SetAttributes(gs_attribute * attributes,
void void
GameSoundBuffer::Play(void * data, int64 frames) GameSoundBuffer::Play(void * data, int64 frames)
{ {
// Mh... should we add some locking?
if (!fIsPlaying)
return;
if (fFormat.channel_count == 2) {
float pan[2]; float pan[2];
pan[0] = fPanRight; pan[0] = fPanRight * fGain;
pan[1] = fPanLeft; pan[1] = fPanLeft * fGain;
char * buffer = new char[fFrameSize * frames]; char * buffer = new char[fFrameSize * frames];
@ -282,7 +264,7 @@ GameSoundBuffer::Play(void * data, int64 frames)
case gs_audio_format::B_GS_U8: case gs_audio_format::B_GS_U8:
{ {
for (int64 i = 0; i < frames; i++) { for (int64 i = 0; i < frames; i++) {
ApplyMod((uint8*)data, (uint8*)buffer, i, fGain, pan); ApplyMod((uint8*)data, (uint8*)buffer, i, pan);
UpdateMods(); UpdateMods();
} }
@ -292,7 +274,7 @@ GameSoundBuffer::Play(void * data, int64 frames)
case gs_audio_format::B_GS_S16: case gs_audio_format::B_GS_S16:
{ {
for (int64 i = 0; i < frames; i++) { for (int64 i = 0; i < frames; i++) {
ApplyMod((int16*)data, (int16*)buffer, i, fGain, pan); ApplyMod((int16*)data, (int16*)buffer, i, pan);
UpdateMods(); UpdateMods();
} }
@ -302,7 +284,7 @@ GameSoundBuffer::Play(void * data, int64 frames)
case gs_audio_format::B_GS_S32: case gs_audio_format::B_GS_S32:
{ {
for (int64 i = 0; i < frames; i++) { for (int64 i = 0; i < frames; i++) {
ApplyMod((int32*)data, (int32*)buffer, i, fGain, pan); ApplyMod((int32*)data, (int32*)buffer, i, pan);
UpdateMods(); UpdateMods();
} }
@ -312,15 +294,23 @@ GameSoundBuffer::Play(void * data, int64 frames)
case gs_audio_format::B_GS_F: case gs_audio_format::B_GS_F:
{ {
for (int64 i = 0; i < frames; i++) { for (int64 i = 0; i < frames; i++) {
ApplyMod((float*)data, (float*)buffer, i, fGain, pan); ApplyMod((float*)data, (float*)buffer, i, pan);
UpdateMods(); UpdateMods();
} }
break; break;
} }
} }
delete[] buffer; delete[] buffer;
} else if (fFormat.channel_count == 1) {
// FIXME the output should be stereo, and we could pan mono sounds
// here. But currently the output has the same number of channels as
// the sound and we can't do this.
// FIXME also, we don't handle the gain here.
FillBuffer(data, frames);
} else
debugger("Invalid number of channels.");
} }
@ -492,9 +482,7 @@ SimpleSoundBuffer::SimpleSoundBuffer(const gs_audio_format * format,
fPosition(0) fPosition(0)
{ {
fBufferSize = frames * fFrameSize; fBufferSize = frames * fFrameSize;
fBuffer = new char[fBufferSize]; fBuffer = (char*)data;
memcpy(fBuffer, data, fBufferSize);
} }

View File

@ -150,10 +150,8 @@ BGameSoundDevice::CreateBuffer(gs_id* sound, const gs_audio_format* format,
int32 position = AllocateSound(); int32 position = AllocateSound();
if (position >= 0) { if (position >= 0) {
media_node systemMixer;
BMediaRoster::Roster()->GetAudioMixer(&systemMixer);
fSounds[position] = new SimpleSoundBuffer(format, data, frames); fSounds[position] = new SimpleSoundBuffer(format, data, frames);
err = fSounds[position]->Connect(&systemMixer); err = B_OK;
} }
if (err == B_OK) if (err == B_OK)
@ -174,11 +172,9 @@ BGameSoundDevice::CreateBuffer(gs_id* sound, const void* object,
int32 position = AllocateSound(); int32 position = AllocateSound();
if (position >= 0) { if (position >= 0) {
media_node systemMixer;
BMediaRoster::Roster()->GetAudioMixer(&systemMixer);
fSounds[position] = new StreamingSoundBuffer(format, object, fSounds[position] = new StreamingSoundBuffer(format, object,
inBufferFrameCount, inBufferCount); inBufferFrameCount, inBufferCount);
err = fSounds[position]->Connect(&systemMixer); err = B_OK;
} }
if (err == B_OK) if (err == B_OK)
@ -228,6 +224,9 @@ BGameSoundDevice::StartPlaying(gs_id sound)
return B_BAD_VALUE; return B_BAD_VALUE;
if (!fSounds[sound - 1]->IsPlaying()) { if (!fSounds[sound - 1]->IsPlaying()) {
media_node systemMixer;
BMediaRoster::Roster()->GetAudioMixer(&systemMixer);
fSounds[sound - 1]->Connect(&systemMixer);
// tell the producer to start playing the sound // tell the producer to start playing the sound
return fSounds[sound - 1]->StartPlaying(); return fSounds[sound - 1]->StartPlaying();
} }

View File

@ -51,8 +51,15 @@ BSimpleGameSound::BSimpleGameSound(const void *inData, size_t inFrameCount,
: :
BGameSound(device) BGameSound(device)
{ {
if (InitCheck() == B_OK) if (InitCheck() != B_OK)
SetInitError(Init(inData, inFrameCount, format)); return;
size_t frameSize
= get_sample_size(format->format) * format->channel_count;
uchar * data = new uchar[inFrameCount * frameSize];
memcpy(data, inData, inFrameCount * frameSize);
SetInitError(Init(data, inFrameCount, format));
} }
@ -177,14 +184,13 @@ BSimpleGameSound::Init(const entry_ref* inFile)
framesTotal += framesRead; framesTotal += framesRead;
} }
delete [] buffer;
gsformat.format = gs_audio_format::B_GS_U8; gsformat.format = gs_audio_format::B_GS_U8;
error = Init(data, frames, &gsformat); error = Init(data, frames, &gsformat);
// free the buffers we no longer need // free the buffers we no longer need
delete [] buffer;
delete [] data;
} else { } else {
// We need to determine the size, in bytes, of a single sample. // We need to determine the size, in bytes, of a single sample.
// At the same time, we will store the format of the audio buffer // At the same time, we will store the format of the audio buffer
@ -201,8 +207,6 @@ BSimpleGameSound::Init(const entry_ref* inFile)
} }
error = Init(data, frames, &gsformat); error = Init(data, frames, &gsformat);
delete [] data;
} }
file.ReleaseTrack(audioStream); file.ReleaseTrack(audioStream);