U8 sound format
U8 sound has a nonzero value as its zero amplitude, so it needs to be special-cased when mixing, applying gains and other transformations. Change-Id: I5ad96b5f39d454bffad2449ac9f27b2ae61e2ccd Reviewed-on: https://review.haiku-os.org/c/haiku/+/3470 Reviewed-by: Jérôme Duval <[email protected]>
This commit is contained in:
committed by
Jérôme Duval
parent
6cd9975b85
commit
cfe72209cf
@@ -19,8 +19,8 @@
|
||||
*/
|
||||
|
||||
|
||||
template<typename inType, typename outType, int gnum, int gden, int offset,
|
||||
int32 min, int32 max> static void
|
||||
template<typename inType, typename outType, int gnum, int gden,
|
||||
int inMiddle, int outMiddle, int32 min, int32 max> static void
|
||||
kernel(Resampler* object, const void *_src, int32 srcSampleOffset,
|
||||
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
|
||||
int32 destSampleCount, float _gain)
|
||||
@@ -33,7 +33,7 @@ kernel(Resampler* object, const void *_src, int32 srcSampleOffset,
|
||||
if (srcSampleCount == destSampleCount) {
|
||||
// optimized case for no resampling
|
||||
while (count--) {
|
||||
float tmp = *(const inType*)src * gain + offset;
|
||||
float tmp = ((*(const inType*)src) - inMiddle) * gain + outMiddle;
|
||||
if (tmp < min) tmp = min;
|
||||
if (tmp > max) tmp = max;
|
||||
*(outType *)dest = (outType)tmp;
|
||||
@@ -50,7 +50,8 @@ kernel(Resampler* object, const void *_src, int32 srcSampleOffset,
|
||||
#define SRC *(const inType*)(src)
|
||||
|
||||
while (count--) {
|
||||
float tmp = (gain * (oldSample + (SRC - oldSample) * current) + offset);
|
||||
float tmp = (gain * (oldSample + (SRC - oldSample) * current - inMiddle)
|
||||
+ outMiddle);
|
||||
if (tmp < min) tmp = min;
|
||||
if (tmp > max) tmp = max;
|
||||
*(outType *)dest = (outType)tmp;
|
||||
@@ -74,22 +75,25 @@ Interpolate::Interpolate(uint32 src_format, uint32 dst_format)
|
||||
Resampler(),
|
||||
fOldSample(0)
|
||||
{
|
||||
if (src_format == media_raw_audio_format::B_AUDIO_UCHAR)
|
||||
fOldSample = 128;
|
||||
|
||||
if (dst_format == media_raw_audio_format::B_AUDIO_FLOAT) {
|
||||
switch (src_format) {
|
||||
case media_raw_audio_format::B_AUDIO_FLOAT:
|
||||
fFunc = &kernel<float, float, 1, 1, 0, -1, 1>;
|
||||
fFunc = &kernel<float, float, 1, 1, 0, 0, -1, 1>;
|
||||
return;
|
||||
case media_raw_audio_format::B_AUDIO_INT:
|
||||
fFunc = &kernel<int32, float, 1, INT32_MAX, 0, -1, 1>;
|
||||
fFunc = &kernel<int32, float, 1, INT32_MAX, 0, 0, -1, 1>;
|
||||
return;
|
||||
case media_raw_audio_format::B_AUDIO_SHORT:
|
||||
fFunc = &kernel<int16, float, 1, INT16_MAX, 0, -1, 1>;
|
||||
fFunc = &kernel<int16, float, 1, INT16_MAX, 0, 0, -1, 1>;
|
||||
return;
|
||||
case media_raw_audio_format::B_AUDIO_CHAR:
|
||||
fFunc = &kernel<int8, float, 1, INT8_MAX, 0, -1, 1>;
|
||||
fFunc = &kernel<int8, float, 1, INT8_MAX, 0, 0, -1, 1>;
|
||||
return;
|
||||
case media_raw_audio_format::B_AUDIO_UCHAR:
|
||||
fFunc = &kernel<uint8, float, 2, UINT8_MAX, -128, -1, 1>;
|
||||
fFunc = &kernel<uint8, float, 2, UINT8_MAX, 128, 0, -1, 1>;
|
||||
return;
|
||||
default:
|
||||
ERROR("Resampler::Resampler: unknown source format 0x%x\n",
|
||||
@@ -102,19 +106,19 @@ Interpolate::Interpolate(uint32 src_format, uint32 dst_format)
|
||||
switch (dst_format) {
|
||||
// float=>float already handled above
|
||||
case media_raw_audio_format::B_AUDIO_INT:
|
||||
fFunc = &kernel<float, int32, INT32_MAX, 1, 0,
|
||||
fFunc = &kernel<float, int32, INT32_MAX, 1, 0, 0,
|
||||
INT32_MIN, INT32_MAX>;
|
||||
return;
|
||||
case media_raw_audio_format::B_AUDIO_SHORT:
|
||||
fFunc = &kernel<float, int16, INT16_MAX, 1, 0,
|
||||
fFunc = &kernel<float, int16, INT16_MAX, 1, 0, 0,
|
||||
INT16_MIN, INT16_MAX>;
|
||||
return;
|
||||
case media_raw_audio_format::B_AUDIO_CHAR:
|
||||
fFunc = &kernel<float, int8, INT8_MAX, 1, 0,
|
||||
fFunc = &kernel<float, int8, INT8_MAX, 1, 0, 0,
|
||||
INT8_MIN, INT8_MAX>;
|
||||
return;
|
||||
case media_raw_audio_format::B_AUDIO_UCHAR:
|
||||
fFunc = &kernel<float, uint8, UINT8_MAX, 2, 1,
|
||||
fFunc = &kernel<float, uint8, UINT8_MAX, 2, 0, 128,
|
||||
0, UINT8_MAX>;
|
||||
return;
|
||||
default:
|
||||
|
||||
@@ -557,7 +557,11 @@ MixerCore::_MixThread()
|
||||
BBuffer* buffer = fBufferGroup->RequestBuffer(size,
|
||||
bufferRequestTimeout);
|
||||
if (buffer != NULL) {
|
||||
memset(buffer->Data(), 0, size);
|
||||
int middle = 0;
|
||||
if (fOutput->MediaOutput().format.u.raw_audio.format
|
||||
== media_raw_audio_format::B_AUDIO_UCHAR)
|
||||
middle = 128;
|
||||
memset(buffer->Data(), middle, size);
|
||||
// fill in the buffer header
|
||||
media_header* hdr = buffer->Header();
|
||||
hdr->type = B_MEDIA_RAW_AUDIO;
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
*/
|
||||
|
||||
|
||||
template<typename inType, typename outType, int gnum, int gden, int offset,
|
||||
int32 min, int32 max> static void
|
||||
template<typename inType, typename outType, int gnum, int gden,
|
||||
int inMiddle, int outMiddle, int32 min, int32 max> static void
|
||||
kernel(Resampler* object, const void *_src, int32 srcSampleOffset,
|
||||
int32 srcSampleCount, void *_dest, int32 destSampleOffset,
|
||||
int32 destSampleCount, float _gain)
|
||||
@@ -33,7 +33,7 @@ kernel(Resampler* object, const void *_src, int32 srcSampleOffset,
|
||||
if (srcSampleCount == destSampleCount) {
|
||||
// optimized case for no resampling
|
||||
while (count--) {
|
||||
float tmp = *(const inType*)src * gain + offset;
|
||||
float tmp = ((*(const inType*)src) - inMiddle) * gain + outMiddle;
|
||||
if (tmp < min) tmp = min;
|
||||
if (tmp > max) tmp = max;
|
||||
*(outType *)dest = (outType)tmp;
|
||||
@@ -48,7 +48,7 @@ kernel(Resampler* object, const void *_src, int32 srcSampleOffset,
|
||||
|
||||
// downsample
|
||||
while (count--) {
|
||||
float tmp = *(const inType*)src * gain + offset;
|
||||
float tmp = ((*(const inType*)src) - inMiddle) * gain + outMiddle;
|
||||
if (tmp < min) tmp = min;
|
||||
if (tmp > max) tmp = max;
|
||||
*(outType *)dest = (outType)tmp;
|
||||
@@ -69,19 +69,19 @@ Resampler::Resampler(uint32 src_format, uint32 dst_format)
|
||||
if (dst_format == media_raw_audio_format::B_AUDIO_FLOAT) {
|
||||
switch (src_format) {
|
||||
case media_raw_audio_format::B_AUDIO_FLOAT:
|
||||
fFunc = &kernel<float, float, 1, 1, 0, -1, 1>;
|
||||
fFunc = &kernel<float, float, 1, 1, 0, 0, -1, 1>;
|
||||
return;
|
||||
case media_raw_audio_format::B_AUDIO_INT:
|
||||
fFunc = &kernel<int32, float, 1, INT32_MAX, 0, -1, 1>;
|
||||
fFunc = &kernel<int32, float, 1, INT32_MAX, 0, 0, -1, 1>;
|
||||
return;
|
||||
case media_raw_audio_format::B_AUDIO_SHORT:
|
||||
fFunc = &kernel<int16, float, 1, INT16_MAX, 0, -1, 1>;
|
||||
fFunc = &kernel<int16, float, 1, INT16_MAX, 0, 0, -1, 1>;
|
||||
return;
|
||||
case media_raw_audio_format::B_AUDIO_CHAR:
|
||||
fFunc = &kernel<int8, float, 1, INT8_MAX, 0, -1, 1>;
|
||||
fFunc = &kernel<int8, float, 1, INT8_MAX, 0, 0, -1, 1>;
|
||||
return;
|
||||
case media_raw_audio_format::B_AUDIO_UCHAR:
|
||||
fFunc = &kernel<uint8, float, 2, UINT8_MAX, -128, -1, 1>;
|
||||
fFunc = &kernel<uint8, float, 2, UINT8_MAX, 128, 0, -1, 1>;
|
||||
return;
|
||||
default:
|
||||
ERROR("Resampler::Resampler: unknown source format 0x%x\n",
|
||||
@@ -94,19 +94,19 @@ Resampler::Resampler(uint32 src_format, uint32 dst_format)
|
||||
switch (dst_format) {
|
||||
// float=>float already handled above
|
||||
case media_raw_audio_format::B_AUDIO_INT:
|
||||
fFunc = &kernel<float, int32, INT32_MAX, 1, 0,
|
||||
fFunc = &kernel<float, int32, INT32_MAX, 1, 0, 0,
|
||||
INT32_MIN, INT32_MAX>;
|
||||
return;
|
||||
case media_raw_audio_format::B_AUDIO_SHORT:
|
||||
fFunc = &kernel<float, int16, INT16_MAX, 1, 0,
|
||||
fFunc = &kernel<float, int16, INT16_MAX, 1, 0, 0,
|
||||
INT16_MIN, INT16_MAX>;
|
||||
return;
|
||||
case media_raw_audio_format::B_AUDIO_CHAR:
|
||||
fFunc = &kernel<float, int8, INT8_MAX, 1, 0,
|
||||
fFunc = &kernel<float, int8, INT8_MAX, 1, 0, 0,
|
||||
INT8_MIN, INT8_MAX>;
|
||||
return;
|
||||
case media_raw_audio_format::B_AUDIO_UCHAR:
|
||||
fFunc = &kernel<float, uint8, UINT8_MAX, 2, 1,
|
||||
fFunc = &kernel<float, uint8, UINT8_MAX, 2, 0, 128,
|
||||
0, UINT8_MAX>;
|
||||
return;
|
||||
default:
|
||||
|
||||
@@ -32,7 +32,7 @@ struct _gs_media_tracker {
|
||||
|
||||
|
||||
// Local utility functions -----------------------------------------------
|
||||
template<typename T>
|
||||
template<typename T, int middle = 0>
|
||||
bool
|
||||
FillBuffer(_gs_ramp* ramp, T* dest, const T* src, size_t* bytes)
|
||||
{
|
||||
@@ -40,7 +40,7 @@ FillBuffer(_gs_ramp* ramp, T* dest, const T* src, size_t* bytes)
|
||||
|
||||
for (size_t sample = 0; sample < samples; sample++) {
|
||||
float gain = *ramp->value;
|
||||
dest[sample] = T(float(src[sample]) * gain);
|
||||
dest[sample] = T(float(src[sample] - middle) * gain + middle);
|
||||
|
||||
if (ChangeRamp(ramp)) {
|
||||
*bytes = sample * sizeof(T);
|
||||
@@ -206,7 +206,7 @@ BFileGameSound::FillBuffer(void* inBuffer, size_t inByteCount)
|
||||
|
||||
switch(Format().format) {
|
||||
case gs_audio_format::B_GS_U8:
|
||||
rampDone = ::FillBuffer<uint8>(fPausing,
|
||||
rampDone = ::FillBuffer<uint8, 128>(fPausing,
|
||||
(uint8*)&buffer[out_offset],
|
||||
(uint8*)&fBuffer[fPlayPosition], &bytes);
|
||||
break;
|
||||
@@ -245,8 +245,12 @@ BFileGameSound::FillBuffer(void* inBuffer, size_t inByteCount)
|
||||
}
|
||||
|
||||
// Fill the rest with silence
|
||||
if (inByteCount > 0)
|
||||
memset(&buffer[out_offset], 0, inByteCount);
|
||||
if (inByteCount > 0) {
|
||||
int middle = 0;
|
||||
if (Format().format == gs_audio_format::B_GS_U8)
|
||||
middle = 128;
|
||||
memset(&buffer[out_offset], middle, inByteCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -362,8 +366,11 @@ BFileGameSound::Init(BDataIO* data)
|
||||
fBufferSize = dformat.buffer_size;
|
||||
|
||||
// create the buffer
|
||||
int middle = 0;
|
||||
if (gsformat.format == gs_audio_format::B_GS_U8)
|
||||
middle = 128;
|
||||
fBuffer = new char[fBufferSize * 2];
|
||||
memset(fBuffer, 0, fBufferSize * 2);
|
||||
memset(fBuffer, middle, fBufferSize * 2);
|
||||
|
||||
fFrameSize = gsformat.channel_count * get_sample_size(gsformat.format);
|
||||
fAudioStream->frames = fAudioStream->stream->CountFrames();
|
||||
|
||||
@@ -42,14 +42,14 @@
|
||||
#include "StreamingGameSound.h"
|
||||
#include "GSUtility.h"
|
||||
|
||||
|
||||
// Sound Buffer Utility functions ----------------------------------------
|
||||
template<typename T>
|
||||
template<typename T, int middle = 0>
|
||||
static inline void
|
||||
ApplyMod(T* data, T* buffer, int64 index, float * pan)
|
||||
{
|
||||
data[index * 2] += T(float(buffer[index * 2]) * pan[0]);
|
||||
data[index * 2 + 1] += T(float(buffer[index * 2 + 1]) * pan[1]);
|
||||
data[index * 2] += T(float(buffer[index * 2] - middle) * pan[0] + middle);
|
||||
data[index * 2 + 1] += T(float(buffer[index * 2 + 1] - middle) * pan[1]
|
||||
+ middle);
|
||||
}
|
||||
|
||||
|
||||
@@ -264,7 +264,7 @@ GameSoundBuffer::Play(void * data, int64 frames)
|
||||
case gs_audio_format::B_GS_U8:
|
||||
{
|
||||
for (int64 i = 0; i < frames; i++) {
|
||||
ApplyMod((uint8*)data, (uint8*)buffer, i, pan);
|
||||
ApplyMod<uint8, 128>((uint8*)data, (uint8*)buffer, i, pan);
|
||||
UpdateMods();
|
||||
}
|
||||
|
||||
@@ -274,7 +274,7 @@ GameSoundBuffer::Play(void * data, int64 frames)
|
||||
case gs_audio_format::B_GS_S16:
|
||||
{
|
||||
for (int64 i = 0; i < frames; i++) {
|
||||
ApplyMod((int16*)data, (int16*)buffer, i, pan);
|
||||
ApplyMod<int16>((int16*)data, (int16*)buffer, i, pan);
|
||||
UpdateMods();
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ GameSoundBuffer::Play(void * data, int64 frames)
|
||||
case gs_audio_format::B_GS_S32:
|
||||
{
|
||||
for (int64 i = 0; i < frames; i++) {
|
||||
ApplyMod((int32*)data, (int32*)buffer, i, pan);
|
||||
ApplyMod<int32>((int32*)data, (int32*)buffer, i, pan);
|
||||
UpdateMods();
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ GameSoundBuffer::Play(void * data, int64 frames)
|
||||
case gs_audio_format::B_GS_F:
|
||||
{
|
||||
for (int64 i = 0; i < frames; i++) {
|
||||
ApplyMod((float*)data, (float*)buffer, i, pan);
|
||||
ApplyMod<float>((float*)data, (float*)buffer, i, pan);
|
||||
UpdateMods();
|
||||
}
|
||||
|
||||
@@ -512,15 +512,26 @@ SimpleSoundBuffer::FillBuffer(void * data, int64 frames)
|
||||
size_t remainder = fBufferSize - fPosition;
|
||||
memcpy(buffer, &fBuffer[fPosition], remainder);
|
||||
|
||||
if (fLooping) {
|
||||
// restart the sound from the begging
|
||||
memcpy(&buffer[remainder], fBuffer, bytes - remainder);
|
||||
fPosition = bytes - remainder;
|
||||
} else
|
||||
fPosition = fBufferSize;
|
||||
} else
|
||||
memset(data, 0, bytes);
|
||||
// there is nothing left to play
|
||||
bytes -= remainder;
|
||||
buffer += remainder;
|
||||
}
|
||||
|
||||
if (fLooping) {
|
||||
// restart the sound from the beginning
|
||||
memcpy(buffer, fBuffer, bytes);
|
||||
fPosition = bytes;
|
||||
bytes = 0;
|
||||
} else {
|
||||
fPosition = fBufferSize;
|
||||
}
|
||||
|
||||
if (bytes > 0) {
|
||||
// Fill the rest with silence
|
||||
int middle = 0;
|
||||
if (fFormat.format == gs_audio_format::B_GS_U8)
|
||||
middle = 128;
|
||||
memset(buffer, middle, bytes);
|
||||
}
|
||||
} else {
|
||||
memcpy(buffer, &fBuffer[fPosition], bytes);
|
||||
fPosition += bytes;
|
||||
|
||||
Reference in New Issue
Block a user