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:
parent
94d14479bb
commit
bf57c148f7
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -245,7 +222,7 @@ GameSoundBuffer::SetAttributes(gs_attribute * attributes,
|
|||||||
status_t error = B_OK;
|
status_t error = B_OK;
|
||||||
|
|
||||||
for (size_t i = 0; i < attributeCount; i++) {
|
for (size_t i = 0; i < attributeCount; i++) {
|
||||||
switch(attributes[i].attribute) {
|
switch (attributes[i].attribute) {
|
||||||
case B_GS_GAIN:
|
case B_GS_GAIN:
|
||||||
error = SetGain(attributes[i].value, attributes[i].duration);
|
error = SetGain(attributes[i].value, attributes[i].duration);
|
||||||
break;
|
break;
|
||||||
@ -270,57 +247,70 @@ GameSoundBuffer::SetAttributes(gs_attribute * attributes,
|
|||||||
void
|
void
|
||||||
GameSoundBuffer::Play(void * data, int64 frames)
|
GameSoundBuffer::Play(void * data, int64 frames)
|
||||||
{
|
{
|
||||||
float pan[2];
|
// Mh... should we add some locking?
|
||||||
pan[0] = fPanRight;
|
if (!fIsPlaying)
|
||||||
pan[1] = fPanLeft;
|
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) {
|
FillBuffer(buffer, frames);
|
||||||
case gs_audio_format::B_GS_U8:
|
|
||||||
{
|
switch (fFormat.format) {
|
||||||
for (int64 i = 0; i < frames; i++) {
|
case gs_audio_format::B_GS_U8:
|
||||||
ApplyMod((uint8*)data, (uint8*)buffer, i, fGain, pan);
|
{
|
||||||
UpdateMods();
|
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:
|
break;
|
||||||
{
|
|
||||||
for (int64 i = 0; i < frames; i++) {
|
|
||||||
ApplyMod((int16*)data, (int16*)buffer, i, fGain, pan);
|
|
||||||
UpdateMods();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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:
|
break;
|
||||||
{
|
|
||||||
for (int64 i = 0; i < frames; i++) {
|
|
||||||
ApplyMod((int32*)data, (int32*)buffer, i, fGain, pan);
|
|
||||||
UpdateMods();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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:
|
break;
|
||||||
{
|
|
||||||
for (int64 i = 0; i < frames; i++) {
|
|
||||||
ApplyMod((float*)data, (float*)buffer, i, fGain, pan);
|
|
||||||
UpdateMods();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
GameSoundBuffer::Reset()
|
||||||
{
|
{
|
||||||
fGain = 1.0;
|
fGain = 1.0;
|
||||||
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user