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 ----------------------------------------
inline void
ApplyMod(uint8 * data, uint8 * buffer, int64 index, float gain, float * pan)
template<typename T>
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 + 1] += uint8(float(buffer[index * 2 + 1]) * gain * 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];
data[index * 2] += T(float(buffer[index * 2]) * pan[0]);
data[index * 2 + 1] += T(float(buffer[index * 2 + 1]) * pan[1]);
}
@ -94,7 +71,7 @@ GameSoundBuffer::GameSoundBuffer(const gs_audio_format * format)
fFrameSize = get_sample_size(format->format) * format->channel_count;
memcpy(&fFormat, format, sizeof(gs_audio_format));
fFormat = *format;
}
@ -245,7 +222,7 @@ GameSoundBuffer::SetAttributes(gs_attribute * attributes,
status_t error = B_OK;
for (size_t i = 0; i < attributeCount; i++) {
switch(attributes[i].attribute) {
switch (attributes[i].attribute) {
case B_GS_GAIN:
error = SetGain(attributes[i].value, attributes[i].duration);
break;
@ -270,57 +247,70 @@ GameSoundBuffer::SetAttributes(gs_attribute * attributes,
void
GameSoundBuffer::Play(void * data, int64 frames)
{
float pan[2];
pan[0] = fPanRight;
pan[1] = fPanLeft;
// Mh... should we add some locking?
if (!fIsPlaying)
return;
char * buffer = new char[fFrameSize * frames];
if (fFormat.channel_count == 2) {
float pan[2];
pan[0] = fPanRight * fGain;
pan[1] = fPanLeft * fGain;
FillBuffer(buffer, frames);
char * buffer = new char[fFrameSize * frames];
switch (fFormat.format) {
case gs_audio_format::B_GS_U8:
{
for (int64 i = 0; i < frames; i++) {
ApplyMod((uint8*)data, (uint8*)buffer, i, fGain, pan);
UpdateMods();
FillBuffer(buffer, frames);
switch (fFormat.format) {
case gs_audio_format::B_GS_U8:
{
for (int64 i = 0; i < frames; i++) {
ApplyMod((uint8*)data, (uint8*)buffer, i, pan);
UpdateMods();
}
break;
}
break;
}
case gs_audio_format::B_GS_S16:
{
for (int64 i = 0; i < frames; i++) {
ApplyMod((int16*)data, (int16*)buffer, i, pan);
UpdateMods();
}
case gs_audio_format::B_GS_S16:
{
for (int64 i = 0; i < frames; i++) {
ApplyMod((int16*)data, (int16*)buffer, i, fGain, pan);
UpdateMods();
break;
}
break;
}
case gs_audio_format::B_GS_S32:
{
for (int64 i = 0; i < frames; i++) {
ApplyMod((int32*)data, (int32*)buffer, i, pan);
UpdateMods();
}
case gs_audio_format::B_GS_S32:
{
for (int64 i = 0; i < frames; i++) {
ApplyMod((int32*)data, (int32*)buffer, i, fGain, pan);
UpdateMods();
break;
}
break;
}
case gs_audio_format::B_GS_F:
{
for (int64 i = 0; i < frames; i++) {
ApplyMod((float*)data, (float*)buffer, i, pan);
UpdateMods();
}
case gs_audio_format::B_GS_F:
{
for (int64 i = 0; i < frames; i++) {
ApplyMod((float*)data, (float*)buffer, i, fGain, pan);
UpdateMods();
break;
}
break;
}
}
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.");
delete[] buffer;
}
@ -353,7 +343,7 @@ GameSoundBuffer::UpdateMods()
}
void
void
GameSoundBuffer::Reset()
{
fGain = 1.0;
@ -492,9 +482,7 @@ SimpleSoundBuffer::SimpleSoundBuffer(const gs_audio_format * format,
fPosition(0)
{
fBufferSize = frames * fFrameSize;
fBuffer = new char[fBufferSize];
memcpy(fBuffer, data, fBufferSize);
fBuffer = (char*)data;
}

View File

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

View File

@ -51,8 +51,15 @@ BSimpleGameSound::BSimpleGameSound(const void *inData, size_t inFrameCount,
:
BGameSound(device)
{
if (InitCheck() == B_OK)
SetInitError(Init(inData, inFrameCount, format));
if (InitCheck() != B_OK)
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;
}
delete [] buffer;
gsformat.format = gs_audio_format::B_GS_U8;
error = Init(data, frames, &gsformat);
// free the buffers we no longer need
delete [] buffer;
delete [] data;
} else {
// 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
@ -201,8 +207,6 @@ BSimpleGameSound::Init(const entry_ref* inFile)
}
error = Init(data, frames, &gsformat);
delete [] data;
}
file.ReleaseTrack(audioStream);