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:
Máximo Castañeda
2020-12-08 12:33:22 +00:00
committed by Jérôme Duval
parent 6cd9975b85
commit cfe72209cf
5 changed files with 76 additions and 50 deletions
@@ -19,8 +19,8 @@
*/ */
template<typename inType, typename outType, int gnum, int gden, int offset, template<typename inType, typename outType, int gnum, int gden,
int32 min, int32 max> static void int inMiddle, int outMiddle, int32 min, int32 max> static void
kernel(Resampler* object, const void *_src, int32 srcSampleOffset, kernel(Resampler* object, const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset, int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain) int32 destSampleCount, float _gain)
@@ -33,7 +33,7 @@ kernel(Resampler* object, const void *_src, int32 srcSampleOffset,
if (srcSampleCount == destSampleCount) { if (srcSampleCount == destSampleCount) {
// optimized case for no resampling // optimized case for no resampling
while (count--) { while (count--) {
float tmp = *(const inType*)src * gain + offset; float tmp = ((*(const inType*)src) - inMiddle) * gain + outMiddle;
if (tmp < min) tmp = min; if (tmp < min) tmp = min;
if (tmp > max) tmp = max; if (tmp > max) tmp = max;
*(outType *)dest = (outType)tmp; *(outType *)dest = (outType)tmp;
@@ -50,7 +50,8 @@ kernel(Resampler* object, const void *_src, int32 srcSampleOffset,
#define SRC *(const inType*)(src) #define SRC *(const inType*)(src)
while (count--) { 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 < min) tmp = min;
if (tmp > max) tmp = max; if (tmp > max) tmp = max;
*(outType *)dest = (outType)tmp; *(outType *)dest = (outType)tmp;
@@ -74,22 +75,25 @@ Interpolate::Interpolate(uint32 src_format, uint32 dst_format)
Resampler(), Resampler(),
fOldSample(0) fOldSample(0)
{ {
if (src_format == media_raw_audio_format::B_AUDIO_UCHAR)
fOldSample = 128;
if (dst_format == media_raw_audio_format::B_AUDIO_FLOAT) { if (dst_format == media_raw_audio_format::B_AUDIO_FLOAT) {
switch (src_format) { switch (src_format) {
case media_raw_audio_format::B_AUDIO_FLOAT: 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; return;
case media_raw_audio_format::B_AUDIO_INT: 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; return;
case media_raw_audio_format::B_AUDIO_SHORT: 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; return;
case media_raw_audio_format::B_AUDIO_CHAR: 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; return;
case media_raw_audio_format::B_AUDIO_UCHAR: 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; return;
default: default:
ERROR("Resampler::Resampler: unknown source format 0x%x\n", ERROR("Resampler::Resampler: unknown source format 0x%x\n",
@@ -102,19 +106,19 @@ Interpolate::Interpolate(uint32 src_format, uint32 dst_format)
switch (dst_format) { switch (dst_format) {
// float=>float already handled above // float=>float already handled above
case media_raw_audio_format::B_AUDIO_INT: 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>; INT32_MIN, INT32_MAX>;
return; return;
case media_raw_audio_format::B_AUDIO_SHORT: 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>; INT16_MIN, INT16_MAX>;
return; return;
case media_raw_audio_format::B_AUDIO_CHAR: 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>; INT8_MIN, INT8_MAX>;
return; return;
case media_raw_audio_format::B_AUDIO_UCHAR: 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>; 0, UINT8_MAX>;
return; return;
default: default:
@@ -557,7 +557,11 @@ MixerCore::_MixThread()
BBuffer* buffer = fBufferGroup->RequestBuffer(size, BBuffer* buffer = fBufferGroup->RequestBuffer(size,
bufferRequestTimeout); bufferRequestTimeout);
if (buffer != NULL) { 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 // fill in the buffer header
media_header* hdr = buffer->Header(); media_header* hdr = buffer->Header();
hdr->type = B_MEDIA_RAW_AUDIO; hdr->type = B_MEDIA_RAW_AUDIO;
@@ -19,8 +19,8 @@
*/ */
template<typename inType, typename outType, int gnum, int gden, int offset, template<typename inType, typename outType, int gnum, int gden,
int32 min, int32 max> static void int inMiddle, int outMiddle, int32 min, int32 max> static void
kernel(Resampler* object, const void *_src, int32 srcSampleOffset, kernel(Resampler* object, const void *_src, int32 srcSampleOffset,
int32 srcSampleCount, void *_dest, int32 destSampleOffset, int32 srcSampleCount, void *_dest, int32 destSampleOffset,
int32 destSampleCount, float _gain) int32 destSampleCount, float _gain)
@@ -33,7 +33,7 @@ kernel(Resampler* object, const void *_src, int32 srcSampleOffset,
if (srcSampleCount == destSampleCount) { if (srcSampleCount == destSampleCount) {
// optimized case for no resampling // optimized case for no resampling
while (count--) { while (count--) {
float tmp = *(const inType*)src * gain + offset; float tmp = ((*(const inType*)src) - inMiddle) * gain + outMiddle;
if (tmp < min) tmp = min; if (tmp < min) tmp = min;
if (tmp > max) tmp = max; if (tmp > max) tmp = max;
*(outType *)dest = (outType)tmp; *(outType *)dest = (outType)tmp;
@@ -48,7 +48,7 @@ kernel(Resampler* object, const void *_src, int32 srcSampleOffset,
// downsample // downsample
while (count--) { while (count--) {
float tmp = *(const inType*)src * gain + offset; float tmp = ((*(const inType*)src) - inMiddle) * gain + outMiddle;
if (tmp < min) tmp = min; if (tmp < min) tmp = min;
if (tmp > max) tmp = max; if (tmp > max) tmp = max;
*(outType *)dest = (outType)tmp; *(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) { if (dst_format == media_raw_audio_format::B_AUDIO_FLOAT) {
switch (src_format) { switch (src_format) {
case media_raw_audio_format::B_AUDIO_FLOAT: 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; return;
case media_raw_audio_format::B_AUDIO_INT: 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; return;
case media_raw_audio_format::B_AUDIO_SHORT: 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; return;
case media_raw_audio_format::B_AUDIO_CHAR: 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; return;
case media_raw_audio_format::B_AUDIO_UCHAR: 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; return;
default: default:
ERROR("Resampler::Resampler: unknown source format 0x%x\n", ERROR("Resampler::Resampler: unknown source format 0x%x\n",
@@ -94,19 +94,19 @@ Resampler::Resampler(uint32 src_format, uint32 dst_format)
switch (dst_format) { switch (dst_format) {
// float=>float already handled above // float=>float already handled above
case media_raw_audio_format::B_AUDIO_INT: 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>; INT32_MIN, INT32_MAX>;
return; return;
case media_raw_audio_format::B_AUDIO_SHORT: 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>; INT16_MIN, INT16_MAX>;
return; return;
case media_raw_audio_format::B_AUDIO_CHAR: 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>; INT8_MIN, INT8_MAX>;
return; return;
case media_raw_audio_format::B_AUDIO_UCHAR: 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>; 0, UINT8_MAX>;
return; return;
default: default:
+13 -6
View File
@@ -32,7 +32,7 @@ struct _gs_media_tracker {
// Local utility functions ----------------------------------------------- // Local utility functions -----------------------------------------------
template<typename T> template<typename T, int middle = 0>
bool bool
FillBuffer(_gs_ramp* ramp, T* dest, const T* src, size_t* bytes) 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++) { for (size_t sample = 0; sample < samples; sample++) {
float gain = *ramp->value; float gain = *ramp->value;
dest[sample] = T(float(src[sample]) * gain); dest[sample] = T(float(src[sample] - middle) * gain + middle);
if (ChangeRamp(ramp)) { if (ChangeRamp(ramp)) {
*bytes = sample * sizeof(T); *bytes = sample * sizeof(T);
@@ -206,7 +206,7 @@ BFileGameSound::FillBuffer(void* inBuffer, size_t inByteCount)
switch(Format().format) { switch(Format().format) {
case gs_audio_format::B_GS_U8: case gs_audio_format::B_GS_U8:
rampDone = ::FillBuffer<uint8>(fPausing, rampDone = ::FillBuffer<uint8, 128>(fPausing,
(uint8*)&buffer[out_offset], (uint8*)&buffer[out_offset],
(uint8*)&fBuffer[fPlayPosition], &bytes); (uint8*)&fBuffer[fPlayPosition], &bytes);
break; break;
@@ -245,8 +245,12 @@ BFileGameSound::FillBuffer(void* inBuffer, size_t inByteCount)
} }
// Fill the rest with silence // Fill the rest with silence
if (inByteCount > 0) if (inByteCount > 0) {
memset(&buffer[out_offset], 0, inByteCount); 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; fBufferSize = dformat.buffer_size;
// create the buffer // create the buffer
int middle = 0;
if (gsformat.format == gs_audio_format::B_GS_U8)
middle = 128;
fBuffer = new char[fBufferSize * 2]; fBuffer = new char[fBufferSize * 2];
memset(fBuffer, 0, fBufferSize * 2); memset(fBuffer, middle, fBufferSize * 2);
fFrameSize = gsformat.channel_count * get_sample_size(gsformat.format); fFrameSize = gsformat.channel_count * get_sample_size(gsformat.format);
fAudioStream->frames = fAudioStream->stream->CountFrames(); fAudioStream->frames = fAudioStream->stream->CountFrames();
+28 -17
View File
@@ -42,14 +42,14 @@
#include "StreamingGameSound.h" #include "StreamingGameSound.h"
#include "GSUtility.h" #include "GSUtility.h"
// Sound Buffer Utility functions ---------------------------------------- // Sound Buffer Utility functions ----------------------------------------
template<typename T> template<typename T, int middle = 0>
static inline void static inline void
ApplyMod(T* data, T* buffer, int64 index, float * pan) ApplyMod(T* data, T* buffer, int64 index, float * pan)
{ {
data[index * 2] += T(float(buffer[index * 2]) * pan[0]); data[index * 2] += T(float(buffer[index * 2] - middle) * pan[0] + middle);
data[index * 2 + 1] += T(float(buffer[index * 2 + 1]) * pan[1]); 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: 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, pan); ApplyMod<uint8, 128>((uint8*)data, (uint8*)buffer, i, pan);
UpdateMods(); UpdateMods();
} }
@@ -274,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, pan); ApplyMod<int16>((int16*)data, (int16*)buffer, i, pan);
UpdateMods(); UpdateMods();
} }
@@ -284,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, pan); ApplyMod<int32>((int32*)data, (int32*)buffer, i, pan);
UpdateMods(); UpdateMods();
} }
@@ -294,7 +294,7 @@ 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, pan); ApplyMod<float>((float*)data, (float*)buffer, i, pan);
UpdateMods(); UpdateMods();
} }
@@ -512,15 +512,26 @@ SimpleSoundBuffer::FillBuffer(void * data, int64 frames)
size_t remainder = fBufferSize - fPosition; size_t remainder = fBufferSize - fPosition;
memcpy(buffer, &fBuffer[fPosition], remainder); memcpy(buffer, &fBuffer[fPosition], remainder);
if (fLooping) { bytes -= remainder;
// restart the sound from the begging buffer += remainder;
memcpy(&buffer[remainder], fBuffer, bytes - remainder); }
fPosition = bytes - remainder;
} else if (fLooping) {
fPosition = fBufferSize; // restart the sound from the beginning
} else memcpy(buffer, fBuffer, bytes);
memset(data, 0, bytes); fPosition = bytes;
// there is nothing left to play 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 { } else {
memcpy(buffer, &fBuffer[fPosition], bytes); memcpy(buffer, &fBuffer[fPosition], bytes);
fPosition += bytes; fPosition += bytes;