multi_audio: Add multiple Audio In Feature, implement listed TODO
Signed-off-by: Jérôme Duval <[email protected]>
This commit is contained in:
committed by
Jérôme Duval
parent
e766693eb0
commit
ea81d6eaf0
@@ -13,6 +13,7 @@ Addon hmulti_audio.media_addon :
|
|||||||
MultiAudioDevice.cpp
|
MultiAudioDevice.cpp
|
||||||
MultiAudioNode.cpp
|
MultiAudioNode.cpp
|
||||||
MultiAudioUtility.cpp
|
MultiAudioUtility.cpp
|
||||||
|
Resampler.cpp
|
||||||
TimeComputer.cpp
|
TimeComputer.cpp
|
||||||
: be media $(TARGET_LIBSUPC++)
|
: be media $(TARGET_LIBSUPC++)
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -24,12 +24,14 @@
|
|||||||
# define PRINTING
|
# define PRINTING
|
||||||
#endif
|
#endif
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "Resampler.h"
|
||||||
|
|
||||||
|
|
||||||
#define PARAMETER_ID_INPUT_FREQUENCY 1
|
#define PARAMETER_ID_INPUT_FREQUENCY 1
|
||||||
#define PARAMETER_ID_OUTPUT_FREQUENCY 2
|
#define PARAMETER_ID_OUTPUT_FREQUENCY 2
|
||||||
|
|
||||||
|
|
||||||
|
//This represent an hardware output
|
||||||
class node_input {
|
class node_input {
|
||||||
public:
|
public:
|
||||||
node_input(media_input& input, media_format format);
|
node_input(media_input& input, media_format format);
|
||||||
@@ -39,12 +41,14 @@ public:
|
|||||||
media_input fInput;
|
media_input fInput;
|
||||||
media_format fPreferredFormat;
|
media_format fPreferredFormat;
|
||||||
media_format fFormat;
|
media_format fFormat;
|
||||||
uint32 fBufferCycle;
|
volatile uint32 fBufferCycle;
|
||||||
multi_buffer_info fOldBufferInfo;
|
multi_buffer_info fOldBufferInfo;
|
||||||
BBuffer* fBuffer;
|
BBuffer* fBuffer;
|
||||||
|
Resampler *fResampler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//This represent an hardware input
|
||||||
class node_output {
|
class node_output {
|
||||||
public:
|
public:
|
||||||
node_output(media_output& output, media_format format);
|
node_output(media_output& output, media_format format);
|
||||||
@@ -60,6 +64,7 @@ public:
|
|||||||
uint64 fSamplesSent;
|
uint64 fSamplesSent;
|
||||||
volatile uint32 fBufferCycle;
|
volatile uint32 fBufferCycle;
|
||||||
multi_buffer_info fOldBufferInfo;
|
multi_buffer_info fOldBufferInfo;
|
||||||
|
Resampler *fResampler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -115,6 +120,7 @@ node_input::node_input(media_input& input, media_format format)
|
|||||||
fPreferredFormat = format;
|
fPreferredFormat = format;
|
||||||
fBufferCycle = 1;
|
fBufferCycle = 1;
|
||||||
fBuffer = NULL;
|
fBuffer = NULL;
|
||||||
|
fResampler = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -136,6 +142,7 @@ node_output::node_output(media_output& output, media_format format)
|
|||||||
fOutput = output;
|
fOutput = output;
|
||||||
fPreferredFormat = format;
|
fPreferredFormat = format;
|
||||||
fBufferCycle = 1;
|
fBufferCycle = 1;
|
||||||
|
fResampler = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -351,6 +358,10 @@ MultiAudioNode::NodeRegistered()
|
|||||||
currentInput = new node_input(*input, fOutputPreferredFormat);
|
currentInput = new node_input(*input, fOutputPreferredFormat);
|
||||||
currentInput->fPreferredFormat.u.raw_audio.channel_count = 1;
|
currentInput->fPreferredFormat.u.raw_audio.channel_count = 1;
|
||||||
currentInput->fInput.format = currentInput->fPreferredFormat;
|
currentInput->fInput.format = currentInput->fPreferredFormat;
|
||||||
|
delete currentInput->fResampler;
|
||||||
|
currentInput->fResampler = new
|
||||||
|
Resampler(currentInput->fPreferredFormat.AudioFormat(),
|
||||||
|
fOutputPreferredFormat.AudioFormat());
|
||||||
|
|
||||||
currentInput->fChannelId = fDevice->Description().channels[i].channel_id;
|
currentInput->fChannelId = fDevice->Description().channels[i].channel_id;
|
||||||
fInputs.AddItem(currentInput);
|
fInputs.AddItem(currentInput);
|
||||||
@@ -397,6 +408,11 @@ MultiAudioNode::NodeRegistered()
|
|||||||
currentOutput = new node_output(*output, fInputPreferredFormat);
|
currentOutput = new node_output(*output, fInputPreferredFormat);
|
||||||
currentOutput->fPreferredFormat.u.raw_audio.channel_count = 1;
|
currentOutput->fPreferredFormat.u.raw_audio.channel_count = 1;
|
||||||
currentOutput->fOutput.format = currentOutput->fPreferredFormat;
|
currentOutput->fOutput.format = currentOutput->fPreferredFormat;
|
||||||
|
delete currentOutput->fResampler;
|
||||||
|
currentOutput->fResampler = new
|
||||||
|
Resampler(fInputPreferredFormat.AudioFormat(),
|
||||||
|
currentOutput->fPreferredFormat.AudioFormat());
|
||||||
|
|
||||||
currentOutput->fChannelId = fDevice->Description().channels[i].channel_id;
|
currentOutput->fChannelId = fDevice->Description().channels[i].channel_id;
|
||||||
fOutputs.AddItem(currentOutput);
|
fOutputs.AddItem(currentOutput);
|
||||||
|
|
||||||
@@ -1725,8 +1741,6 @@ MultiAudioNode::_OutputThread()
|
|||||||
CALLED();
|
CALLED();
|
||||||
multi_buffer_info bufferInfo;
|
multi_buffer_info bufferInfo;
|
||||||
bufferInfo.info_size = sizeof(multi_buffer_info);
|
bufferInfo.info_size = sizeof(multi_buffer_info);
|
||||||
bufferInfo._reserved_0 = 0;
|
|
||||||
bufferInfo._reserved_1 = 2;
|
|
||||||
bufferInfo.playback_buffer_cycle = 0;
|
bufferInfo.playback_buffer_cycle = 0;
|
||||||
bufferInfo.record_buffer_cycle = 0;
|
bufferInfo.record_buffer_cycle = 0;
|
||||||
|
|
||||||
@@ -1758,8 +1772,7 @@ MultiAudioNode::_OutputThread()
|
|||||||
for (int32 i = 0; i < fInputs.CountItems(); i++) {
|
for (int32 i = 0; i < fInputs.CountItems(); i++) {
|
||||||
node_input* input = (node_input*)fInputs.ItemAt(i);
|
node_input* input = (node_input*)fInputs.ItemAt(i);
|
||||||
|
|
||||||
if (bufferInfo._reserved_0 == input->fChannelId
|
if (bufferInfo.playback_buffer_cycle >= 0
|
||||||
&& bufferInfo.playback_buffer_cycle >= 0
|
|
||||||
&& bufferInfo.playback_buffer_cycle
|
&& bufferInfo.playback_buffer_cycle
|
||||||
< fDevice->BufferList().return_playback_buffers
|
< fDevice->BufferList().return_playback_buffers
|
||||||
&& (input->fOldBufferInfo.playback_buffer_cycle
|
&& (input->fOldBufferInfo.playback_buffer_cycle
|
||||||
@@ -1814,8 +1827,7 @@ MultiAudioNode::_OutputThread()
|
|||||||
// buffer
|
// buffer
|
||||||
if (RunState() == BMediaEventLooper::B_STARTED
|
if (RunState() == BMediaEventLooper::B_STARTED
|
||||||
&& output->fOutput.destination != media_destination::null) {
|
&& output->fOutput.destination != media_destination::null) {
|
||||||
if (bufferInfo._reserved_1 == output->fChannelId
|
if (bufferInfo.record_buffer_cycle >= 0
|
||||||
&& bufferInfo.record_buffer_cycle >= 0
|
|
||||||
&& bufferInfo.record_buffer_cycle
|
&& bufferInfo.record_buffer_cycle
|
||||||
< fDevice->BufferList().return_record_buffers
|
< fDevice->BufferList().return_record_buffers
|
||||||
&& (output->fOldBufferInfo.record_buffer_cycle
|
&& (output->fOldBufferInfo.record_buffer_cycle
|
||||||
@@ -1823,6 +1835,8 @@ MultiAudioNode::_OutputThread()
|
|||||||
|| fDevice->BufferList().return_record_buffers == 1)) {
|
|| fDevice->BufferList().return_record_buffers == 1)) {
|
||||||
//PRINT(("record_buffer_cycle ok\n"));
|
//PRINT(("record_buffer_cycle ok\n"));
|
||||||
|
|
||||||
|
output->fBufferCycle = bufferInfo.record_buffer_cycle;
|
||||||
|
|
||||||
// Get the next buffer of data
|
// Get the next buffer of data
|
||||||
BBuffer* buffer = _FillNextBuffer(bufferInfo, *output);
|
BBuffer* buffer = _FillNextBuffer(bufferInfo, *output);
|
||||||
if (buffer != NULL) {
|
if (buffer != NULL) {
|
||||||
@@ -1889,6 +1903,17 @@ MultiAudioNode::_WriteZeros(node_input& input, uint32 bufferCycle)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case media_raw_audio_format::B_AUDIO_DOUBLE:
|
||||||
|
for (uint32 channel = 0; channel < channelCount; channel++) {
|
||||||
|
char* dest = _PlaybackBuffer(bufferCycle,
|
||||||
|
input.fChannelId + channel);
|
||||||
|
for (uint32 i = bufferSize; i > 0; i--) {
|
||||||
|
*(double*)dest = 0;
|
||||||
|
dest += stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case media_raw_audio_format::B_AUDIO_INT:
|
case media_raw_audio_format::B_AUDIO_INT:
|
||||||
for (uint32 channel = 0; channel < channelCount; channel++) {
|
for (uint32 channel = 0; channel < channelCount; channel++) {
|
||||||
char* dest = _PlaybackBuffer(bufferCycle,
|
char* dest = _PlaybackBuffer(bufferCycle,
|
||||||
@@ -1911,6 +1936,28 @@ MultiAudioNode::_WriteZeros(node_input& input, uint32 bufferCycle)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case media_raw_audio_format::B_AUDIO_UCHAR:
|
||||||
|
for (uint32 channel = 0; channel < channelCount; channel++) {
|
||||||
|
char* dest = _PlaybackBuffer(bufferCycle,
|
||||||
|
input.fChannelId + channel);
|
||||||
|
for (uint32 i = bufferSize; i > 0; i--) {
|
||||||
|
*(uint8*)dest = 128;
|
||||||
|
dest += stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case media_raw_audio_format::B_AUDIO_CHAR:
|
||||||
|
for (uint32 channel = 0; channel < channelCount; channel++) {
|
||||||
|
char* dest = _PlaybackBuffer(bufferCycle,
|
||||||
|
input.fChannelId + channel);
|
||||||
|
for (uint32 i = bufferSize; i > 0; i--) {
|
||||||
|
*(int8*)dest = 0;
|
||||||
|
dest += stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "ERROR in WriteZeros format not handled\n");
|
fprintf(stderr, "ERROR in WriteZeros format not handled\n");
|
||||||
}
|
}
|
||||||
@@ -1929,219 +1976,36 @@ MultiAudioNode::_FillWithZeros(node_input& input)
|
|||||||
void
|
void
|
||||||
MultiAudioNode::_FillNextBuffer(node_input& input, BBuffer* buffer)
|
MultiAudioNode::_FillNextBuffer(node_input& input, BBuffer* buffer)
|
||||||
{
|
{
|
||||||
// TODO: simplify this, or put it into a static function to remove
|
uint32 channelCount = input.fInput.format.u.raw_audio.channel_count;
|
||||||
// the need for checking all over again
|
size_t inputSampleSize = input.fInput.format.u.raw_audio.format
|
||||||
|
& media_raw_audio_format::B_AUDIO_SIZE_MASK;
|
||||||
|
|
||||||
uint32 bufferSize = fDevice->BufferList().return_playback_buffer_size;
|
uint32 bufferSize = fDevice->BufferList().return_playback_buffer_size;
|
||||||
|
|
||||||
if (buffer->SizeUsed()
|
if (buffer->SizeUsed() / inputSampleSize / channelCount != bufferSize) {
|
||||||
/ (input.fInput.format.u.raw_audio.format
|
|
||||||
& media_raw_audio_format::B_AUDIO_SIZE_MASK)
|
|
||||||
/ input.fInput.format.u.raw_audio.channel_count != bufferSize) {
|
|
||||||
_WriteZeros(input, input.fBufferCycle);
|
_WriteZeros(input, input.fBufferCycle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (input.fInput.format.u.raw_audio.format) {
|
if (channelCount != input.fFormat.u.raw_audio.channel_count) {
|
||||||
case media_raw_audio_format::B_AUDIO_FLOAT:
|
PRINT(("Channel count is different"));
|
||||||
switch (input.fFormat.u.raw_audio.format) {
|
return;
|
||||||
case media_raw_audio_format::B_AUDIO_FLOAT:
|
}
|
||||||
{
|
|
||||||
size_t frameSize = input.fInput.format.u.raw_audio
|
if (input.fResampler != NULL) {
|
||||||
.channel_count * sizeof(float);
|
size_t srcStride = channelCount * inputSampleSize;
|
||||||
size_t stride = _PlaybackStride(input.fBufferCycle,
|
|
||||||
input.fChannelId);
|
for (uint32 channel = 0; channel < channelCount; channel++) {
|
||||||
//PRINT(("stride : %i, frame_size : %i, return_playback_buffer_size : %i\n", stride, frame_size, fDevice->BufferList().return_playback_buffer_size));
|
char* src = (char*)buffer->Data() + channel * inputSampleSize;
|
||||||
for (uint32 channel = 0; channel
|
char* dst = _PlaybackBuffer(input.fBufferCycle,
|
||||||
< input.fInput.format.u.raw_audio.channel_count;
|
|
||||||
channel++) {
|
|
||||||
char* dest = _PlaybackBuffer(input.fBufferCycle,
|
|
||||||
input.fChannelId + channel);
|
input.fChannelId + channel);
|
||||||
char* src = (char*)buffer->Data()
|
size_t dstStride = _PlaybackStride(input.fBufferCycle,
|
||||||
+ channel * sizeof(float);
|
|
||||||
|
|
||||||
for (uint32 i = bufferSize; i > 0; i--) {
|
|
||||||
*(float *)dest = *(float *)src;
|
|
||||||
dest += stride;
|
|
||||||
src += frameSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case media_raw_audio_format::B_AUDIO_SHORT:
|
|
||||||
if (input.fInput.format.u.raw_audio.channel_count == 2) {
|
|
||||||
int16* dest1 = (int16*)_PlaybackBuffer(
|
|
||||||
input.fBufferCycle, input.fChannelId);
|
|
||||||
int16* dest2 = (int16*)_PlaybackBuffer(
|
|
||||||
input.fBufferCycle, input.fChannelId + 1);
|
|
||||||
float* src = (float*)buffer->Data();
|
|
||||||
if (_PlaybackStride(input.fBufferCycle,
|
|
||||||
input.fChannelId) == sizeof(int16)
|
|
||||||
&& _PlaybackStride(input.fBufferCycle,
|
|
||||||
input.fChannelId + 1) == sizeof(int16)) {
|
|
||||||
//PRINT(("FillNextBuffer : 2 channels strides 2\n"));
|
|
||||||
for (uint32 i = bufferSize; i > 0; i--) {
|
|
||||||
*dest1++ = int16(32767 * *src++);
|
|
||||||
*dest2++ = int16(32767 * *src++);
|
|
||||||
}
|
|
||||||
} else if (_PlaybackStride(input.fBufferCycle,
|
|
||||||
input.fChannelId) == 2 * sizeof(int16)
|
|
||||||
&& _PlaybackStride(input.fBufferCycle,
|
|
||||||
input.fChannelId + 1) == 2 * sizeof(int16)
|
|
||||||
&& dest1 + 1 == dest2) {
|
|
||||||
//PRINT(("FillNextBuffer : 2 channels strides 4\n"));
|
|
||||||
for (uint32 i = 2 * bufferSize; i > 0; i--)
|
|
||||||
*dest1++ = int16(32767 * *src++);
|
|
||||||
} else {
|
|
||||||
//PRINT(("FillNextBuffer : 2 channels strides != 2\n"));
|
|
||||||
size_t stride1 = _PlaybackStride(input.fBufferCycle,
|
|
||||||
input.fChannelId) / sizeof(int16);
|
|
||||||
size_t stride2 = _PlaybackStride(input.fBufferCycle,
|
|
||||||
input.fChannelId + 1) / sizeof(int16);
|
|
||||||
for (uint32 i = bufferSize; i > 0; i--) {
|
|
||||||
*dest1 = int16(32767 * *src++);
|
|
||||||
*dest2 = int16(32767 * *src++);
|
|
||||||
dest1 += stride1;
|
|
||||||
dest2 += stride2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
size_t frameSize = input.fInput.format.u
|
|
||||||
.raw_audio.channel_count * sizeof(int16);
|
|
||||||
size_t stride = _PlaybackStride(input.fBufferCycle,
|
|
||||||
input.fChannelId);
|
|
||||||
//PRINT(("stride : %i, frame_size : %i, return_playback_buffer_size : %i\n", stride, frame_size, fDevice->BufferList().return_playback_buffer_size));
|
|
||||||
for (uint32 channel = 0; channel <
|
|
||||||
input.fInput.format.u.raw_audio.channel_count;
|
|
||||||
channel++) {
|
|
||||||
char* dest = _PlaybackBuffer(input.fBufferCycle,
|
|
||||||
input.fChannelId + channel);
|
input.fChannelId + channel);
|
||||||
char* src = (char*)buffer->Data()
|
|
||||||
+ channel * sizeof(int16);
|
|
||||||
|
|
||||||
for (uint32 i = bufferSize; i > 0; i--) {
|
input.fResampler->Resample(src, srcStride,
|
||||||
*(int16*)dest = int16(32767 * *(float*)src);
|
dst, dstStride, bufferSize);
|
||||||
dest += stride;
|
|
||||||
src += frameSize;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case media_raw_audio_format::B_AUDIO_INT:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case media_raw_audio_format::B_AUDIO_INT:
|
|
||||||
switch (input.fFormat.u.raw_audio.format) {
|
|
||||||
case media_raw_audio_format::B_AUDIO_INT:
|
|
||||||
{
|
|
||||||
size_t frameSize = input.fInput.format.u.raw_audio
|
|
||||||
.channel_count * sizeof(int32);
|
|
||||||
size_t stride = _PlaybackStride(input.fBufferCycle,
|
|
||||||
input.fChannelId);
|
|
||||||
//PRINT(("stride : %i, frame_size : %i, return_playback_buffer_size : %i\n", stride, frame_size, fDevice->BufferList().return_playback_buffer_size));
|
|
||||||
for (uint32 channel = 0; channel
|
|
||||||
< input.fInput.format.u.raw_audio.channel_count;
|
|
||||||
channel++) {
|
|
||||||
char* dest = _PlaybackBuffer(input.fBufferCycle,
|
|
||||||
input.fChannelId + channel);
|
|
||||||
char* src = (char*)buffer->Data()
|
|
||||||
+ channel * sizeof(int32);
|
|
||||||
|
|
||||||
for (uint32 i = bufferSize; i > 0; i--) {
|
|
||||||
*(int32 *)dest = *(int32 *)src;
|
|
||||||
dest += stride;
|
|
||||||
src += frameSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case media_raw_audio_format::B_AUDIO_SHORT:
|
|
||||||
case media_raw_audio_format::B_AUDIO_FLOAT:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case media_raw_audio_format::B_AUDIO_SHORT:
|
|
||||||
switch (input.fFormat.u.raw_audio.format) {
|
|
||||||
case media_raw_audio_format::B_AUDIO_SHORT:
|
|
||||||
if (input.fInput.format.u.raw_audio.channel_count == 2) {
|
|
||||||
int16* dest1 = (int16*)_PlaybackBuffer(
|
|
||||||
input.fBufferCycle, input.fChannelId);
|
|
||||||
int16* dest2 = (int16*)_PlaybackBuffer(
|
|
||||||
input.fBufferCycle, input.fChannelId + 1);
|
|
||||||
int16* src = (int16*)buffer->Data();
|
|
||||||
if (_PlaybackStride(input.fBufferCycle,
|
|
||||||
input.fChannelId) == sizeof(int16)
|
|
||||||
&& _PlaybackStride(input.fBufferCycle,
|
|
||||||
input.fChannelId + 1) == sizeof(int16)) {
|
|
||||||
//PRINT(("FillNextBuffer : 2 channels strides 2\n"));
|
|
||||||
for (uint32 i = bufferSize; i > 0; i--) {
|
|
||||||
*dest1++ = *src++;
|
|
||||||
*dest2++ = *src++;
|
|
||||||
}
|
|
||||||
} else if (_PlaybackStride(input.fBufferCycle,
|
|
||||||
input.fChannelId) == 2 * sizeof(int16)
|
|
||||||
&& _PlaybackStride(input.fBufferCycle,
|
|
||||||
input.fChannelId + 1) == 2 * sizeof(int16)
|
|
||||||
&& dest1 + 1 == dest2) {
|
|
||||||
//PRINT(("FillNextBuffer : 2 channels strides 4\n"));
|
|
||||||
memcpy(dest1, src,
|
|
||||||
bufferSize * 2 * sizeof(int16));
|
|
||||||
} else {
|
|
||||||
//PRINT(("FillNextBuffer : 2 channels strides != 2\n"));
|
|
||||||
size_t stride1 = _PlaybackStride(
|
|
||||||
input.fBufferCycle, input.fChannelId) / 2;
|
|
||||||
size_t stride2 = _PlaybackStride(
|
|
||||||
input.fBufferCycle, input.fChannelId + 1)
|
|
||||||
/ 2;
|
|
||||||
|
|
||||||
for (uint32 i = bufferSize; i > 0; i--) {
|
|
||||||
*dest1 = *src++;
|
|
||||||
*dest2 = *src++;
|
|
||||||
dest1 += stride1;
|
|
||||||
dest2 += stride2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
size_t frameSize = input.fInput.format.u
|
|
||||||
.raw_audio.channel_count * sizeof(int16);
|
|
||||||
size_t stride = _PlaybackStride(input.fBufferCycle,
|
|
||||||
input.fChannelId);
|
|
||||||
//PRINT(("stride : %i, frame_size : %i, return_playback_buffer_size : %i\n", stride, frame_size, fDevice->BufferList().return_playback_buffer_size));
|
|
||||||
for (uint32 channel = 0; channel
|
|
||||||
< input.fInput.format.u.raw_audio.channel_count;
|
|
||||||
channel++) {
|
|
||||||
char* dest = _PlaybackBuffer(input.fBufferCycle,
|
|
||||||
input.fChannelId + channel);
|
|
||||||
char* src = (char*)buffer->Data()
|
|
||||||
+ channel * sizeof(int16);
|
|
||||||
|
|
||||||
for (uint32 i = bufferSize; i > 0; i--) {
|
|
||||||
*(int16*)dest = *(int16*)src;
|
|
||||||
dest += stride;
|
|
||||||
src += frameSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case media_raw_audio_format::B_AUDIO_FLOAT:
|
|
||||||
case media_raw_audio_format::B_AUDIO_INT:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case media_raw_audio_format::B_AUDIO_UCHAR:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2219,7 +2083,7 @@ MultiAudioNode::_UpdateTimeSource(multi_buffer_info& info,
|
|||||||
|
|
||||||
|
|
||||||
BBuffer*
|
BBuffer*
|
||||||
MultiAudioNode::_FillNextBuffer(multi_buffer_info &info, node_output &channel)
|
MultiAudioNode::_FillNextBuffer(multi_buffer_info &info, node_output &output)
|
||||||
{
|
{
|
||||||
//CALLED();
|
//CALLED();
|
||||||
// get a buffer from our buffer group
|
// get a buffer from our buffer group
|
||||||
@@ -2227,15 +2091,16 @@ MultiAudioNode::_FillNextBuffer(multi_buffer_info &info, node_output &channel)
|
|||||||
//PRINT(("MBI.record_buffer_cycle : %i\n", MBI.record_buffer_cycle));
|
//PRINT(("MBI.record_buffer_cycle : %i\n", MBI.record_buffer_cycle));
|
||||||
//PRINT(("MBI.recorded_real_time : %i\n", MBI.recorded_real_time));
|
//PRINT(("MBI.recorded_real_time : %i\n", MBI.recorded_real_time));
|
||||||
//PRINT(("MBI.recorded_frames_count : %i\n", MBI.recorded_frames_count));
|
//PRINT(("MBI.recorded_frames_count : %i\n", MBI.recorded_frames_count));
|
||||||
if (!channel.fBufferGroup)
|
if (!output.fBufferGroup)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
BBuffer* buffer = channel.fBufferGroup->RequestBuffer(
|
BBuffer* buffer = output.fBufferGroup->RequestBuffer(
|
||||||
channel.fOutput.format.u.raw_audio.buffer_size, BufferDuration());
|
output.fOutput.format.u.raw_audio.buffer_size, BufferDuration());
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
// If we fail to get a buffer (for example, if the request times out),
|
// If we fail to get a buffer (for example, if the request times out),
|
||||||
// we skip this buffer and go on to the next, to avoid locking up the
|
// we skip this buffer and go on to the next, to avoid locking up the
|
||||||
// control thread.
|
// control thread.
|
||||||
|
fprintf(stderr, "Buffer is null");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2246,17 +2111,34 @@ MultiAudioNode::_FillNextBuffer(multi_buffer_info &info, node_output &channel)
|
|||||||
if (TimeSource() == NULL)
|
if (TimeSource() == NULL)
|
||||||
fprintf(stderr, "TimeSource() NULL\n");
|
fprintf(stderr, "TimeSource() NULL\n");
|
||||||
|
|
||||||
// now fill it with data, continuing where the last buffer left off
|
uint32 channelCount = output.fOutput.format.u.raw_audio.channel_count;
|
||||||
memcpy(buffer->Data(),
|
size_t outputSampleSize = output.fOutput.format.u.raw_audio.format
|
||||||
fDevice->BufferList().record_buffers[info.record_buffer_cycle]
|
& media_raw_audio_format::B_AUDIO_SIZE_MASK;
|
||||||
[channel.fChannelId
|
|
||||||
- fDevice->Description().output_channel_count].base,
|
uint32 bufferSize = fDevice->BufferList().return_record_buffer_size;
|
||||||
channel.fOutput.format.u.raw_audio.buffer_size);
|
|
||||||
|
if (output.fResampler != NULL) {
|
||||||
|
size_t dstStride = channelCount * outputSampleSize;
|
||||||
|
|
||||||
|
uint32 channelId = output.fChannelId
|
||||||
|
- fDevice->Description().output_channel_count;
|
||||||
|
|
||||||
|
for (uint32 channel = 0; channel < channelCount; channel++) {
|
||||||
|
char* src = _RecordBuffer(output.fBufferCycle,
|
||||||
|
channelId + channel);
|
||||||
|
size_t srcStride = _RecordStride(output.fBufferCycle,
|
||||||
|
channelId + channel);
|
||||||
|
char* dst = (char*)buffer->Data() + channel * outputSampleSize;
|
||||||
|
|
||||||
|
output.fResampler->Resample(src, srcStride, dst, dstStride,
|
||||||
|
bufferSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// fill in the buffer header
|
// fill in the buffer header
|
||||||
media_header* header = buffer->Header();
|
media_header* header = buffer->Header();
|
||||||
header->type = B_MEDIA_RAW_AUDIO;
|
header->type = B_MEDIA_RAW_AUDIO;
|
||||||
header->size_used = channel.fOutput.format.u.raw_audio.buffer_size;
|
header->size_used = output.fOutput.format.u.raw_audio.buffer_size;
|
||||||
header->time_source = TimeSource()->ID();
|
header->time_source = TimeSource()->ID();
|
||||||
header->start_time = PerformanceTimeFor(info.recorded_real_time);
|
header->start_time = PerformanceTimeFor(info.recorded_real_time);
|
||||||
|
|
||||||
|
|||||||
@@ -166,6 +166,13 @@ private:
|
|||||||
{ return fDevice->BufferList().playback_buffers
|
{ return fDevice->BufferList().playback_buffers
|
||||||
[cycle][channel].stride; }
|
[cycle][channel].stride; }
|
||||||
|
|
||||||
|
char* _RecordBuffer(int32 cycle, int32 channel)
|
||||||
|
{ return fDevice->BufferList().record_buffers
|
||||||
|
[cycle][channel].base; }
|
||||||
|
uint32 _RecordStride(int32 cycle, int32 channel)
|
||||||
|
{ return fDevice->BufferList().record_buffers
|
||||||
|
[cycle][channel].stride; }
|
||||||
|
|
||||||
void _WriteZeros(node_input& input, uint32 bufferCycle);
|
void _WriteZeros(node_input& input, uint32 bufferCycle);
|
||||||
void _FillWithZeros(node_input& input);
|
void _FillWithZeros(node_input& input);
|
||||||
void _FillNextBuffer(node_input& channel,
|
void _FillNextBuffer(node_input& channel,
|
||||||
@@ -178,7 +185,7 @@ private:
|
|||||||
|
|
||||||
void _AllocateBuffers(node_output& channel);
|
void _AllocateBuffers(node_output& channel);
|
||||||
BBuffer* _FillNextBuffer(multi_buffer_info& info,
|
BBuffer* _FillNextBuffer(multi_buffer_info& info,
|
||||||
node_output& channel);
|
node_output& output);
|
||||||
void _UpdateTimeSource(multi_buffer_info& info,
|
void _UpdateTimeSource(multi_buffer_info& info,
|
||||||
multi_buffer_info& oldInfo, node_input& input);
|
multi_buffer_info& oldInfo, node_input& input);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,645 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jérôme Leveque
|
||||||
|
* Copyright 2012 Jérôme Duval
|
||||||
|
* Copyright 2003 Marcus Overhagen
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "Resampler.h"
|
||||||
|
#include "MultiAudioUtility.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*! A simple resampling class for the multi_audio add-ons.
|
||||||
|
You pick the conversion function on object creation,
|
||||||
|
and then call the Resample() function, specifying data pointer,
|
||||||
|
offset (in bytes) to the next sample, and count of samples.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
Resampler::Resampler(uint32 sourceFormat, uint32 destFormat)
|
||||||
|
:
|
||||||
|
fFunc(NULL)
|
||||||
|
{
|
||||||
|
PRINT(("Resampler() in 0x%x, out 0x%x\n", (unsigned int)sourceFormat,
|
||||||
|
(unsigned int)destFormat));
|
||||||
|
|
||||||
|
switch (sourceFormat) {
|
||||||
|
case media_raw_audio_format::B_AUDIO_FLOAT:
|
||||||
|
switch (destFormat) {
|
||||||
|
case media_raw_audio_format::B_AUDIO_FLOAT:
|
||||||
|
fFunc = &Resampler::_CopyType2Type<float>;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_DOUBLE:
|
||||||
|
fFunc = &Resampler::_CopyFloat2Double;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_INT:
|
||||||
|
fFunc = &Resampler::_CopyFloat2Int;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_SHORT:
|
||||||
|
fFunc = &Resampler::_CopyFloat2Short;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_UCHAR:
|
||||||
|
fFunc = &Resampler::_CopyFloat2UChar;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_CHAR:
|
||||||
|
fFunc = &Resampler::_CopyFloat2Char;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case media_raw_audio_format::B_AUDIO_DOUBLE:
|
||||||
|
switch (destFormat) {
|
||||||
|
case media_raw_audio_format::B_AUDIO_FLOAT:
|
||||||
|
fFunc = &Resampler::_CopyDouble2Float;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_DOUBLE:
|
||||||
|
fFunc = &Resampler::_CopyType2Type<double>;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_INT:
|
||||||
|
fFunc = &Resampler::_CopyDouble2Int;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_SHORT:
|
||||||
|
fFunc = &Resampler::_CopyDouble2Short;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_UCHAR:
|
||||||
|
fFunc = &Resampler::_CopyDouble2UChar;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_CHAR:
|
||||||
|
fFunc = &Resampler::_CopyDouble2Char;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case media_raw_audio_format::B_AUDIO_INT:
|
||||||
|
switch (destFormat) {
|
||||||
|
case media_raw_audio_format::B_AUDIO_FLOAT:
|
||||||
|
fFunc = &Resampler::_CopyInt2Float;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_DOUBLE:
|
||||||
|
fFunc = &Resampler::_CopyInt2Double;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_INT:
|
||||||
|
fFunc = &Resampler::_CopyType2Type<int32>;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_SHORT:
|
||||||
|
fFunc = &Resampler::_CopyInt2Short;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_UCHAR:
|
||||||
|
fFunc = &Resampler::_CopyInt2UChar;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_CHAR:
|
||||||
|
fFunc = &Resampler::_CopyInt2Char;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case media_raw_audio_format::B_AUDIO_SHORT:
|
||||||
|
switch (destFormat) {
|
||||||
|
case media_raw_audio_format::B_AUDIO_FLOAT:
|
||||||
|
fFunc = &Resampler::_CopyShort2Float;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_DOUBLE:
|
||||||
|
fFunc = &Resampler::_CopyShort2Double;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_INT:
|
||||||
|
fFunc = &Resampler::_CopyShort2Int;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_SHORT:
|
||||||
|
fFunc = &Resampler::_CopyType2Type<int16>;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_UCHAR:
|
||||||
|
fFunc = &Resampler::_CopyShort2UChar;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_CHAR:
|
||||||
|
fFunc = &Resampler::_CopyShort2Char;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case media_raw_audio_format::B_AUDIO_UCHAR:
|
||||||
|
switch (destFormat) {
|
||||||
|
case media_raw_audio_format::B_AUDIO_FLOAT:
|
||||||
|
fFunc = &Resampler::_CopyUChar2Float;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_DOUBLE:
|
||||||
|
fFunc = &Resampler::_CopyUChar2Double;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_INT:
|
||||||
|
fFunc = &Resampler::_CopyUChar2Int;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_SHORT:
|
||||||
|
fFunc = &Resampler::_CopyUChar2Short;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_UCHAR:
|
||||||
|
fFunc = &Resampler::_CopyType2Type<uint8>;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_CHAR:
|
||||||
|
fFunc = &Resampler::_CopyUChar2Char;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case media_raw_audio_format::B_AUDIO_CHAR:
|
||||||
|
switch (destFormat) {
|
||||||
|
case media_raw_audio_format::B_AUDIO_FLOAT:
|
||||||
|
fFunc = &Resampler::_CopyChar2Float;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_DOUBLE:
|
||||||
|
fFunc = &Resampler::_CopyChar2Double;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_INT:
|
||||||
|
fFunc = &Resampler::_CopyChar2Int;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_SHORT:
|
||||||
|
fFunc = &Resampler::_CopyChar2Short;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_UCHAR:
|
||||||
|
fFunc = &Resampler::_CopyChar2UChar;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_CHAR:
|
||||||
|
fFunc = &Resampler::_CopyType2Type<int8>;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Resampler::~Resampler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Resampler::InitCheck() const
|
||||||
|
{
|
||||||
|
return fFunc != NULL ? B_OK : B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void
|
||||||
|
Resampler::_CopyType2Type(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(T*)outputData = *(const T*)inputData;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyFloat2Double(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(double*)outputData = *(const float*)inputData;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyFloat2Int(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(int32*)outputData = (int32)(*(const float*)inputData * 2147483647.0f);
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyFloat2Short(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(int16*)outputData = (int16)(*(const float*)inputData * 32767.0f);
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyFloat2UChar(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(uint8*)outputData = (uint8)(128.0f + *(const float*)inputData * 127.0f);
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyFloat2Char(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(int8*)outputData = (int8)(*(const float*)inputData * 127.0f);
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyDouble2Float(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(float*)outputData = *(const double*)inputData;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyDouble2Int(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(int32*)outputData = (int32)(*(const double*)inputData * 2147483647.0f);
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyDouble2Short(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(int16*)outputData = (int16)(*(const double*)inputData * 32767.0f);
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyDouble2UChar(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(uint8*)outputData = (uint8)(128.0f + *(const double*)inputData * 127.0f);
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyDouble2Char(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(int8*)outputData = (int8)(*(const double*)inputData * 127.0f);
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyShort2Float(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(float*)outputData = *(const int16*)inputData / 32767.0f;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyShort2Double(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(double*)outputData = *(const int16*)inputData / 32767.0;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyShort2Int(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(int32*)outputData = (int32)*(const int16*)inputData << 16;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyShort2UChar(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(uint8*)outputData = 128 + (*(const int16*)inputData >> 8);
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyShort2Char(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(int8*)outputData = *(const int16*)inputData >> 8;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyInt2Float(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(float*)outputData = *(const int32*)inputData / 2147483647.0f;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyInt2Double(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(double*)outputData = *(const int32*)inputData / 2147483647.0;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyInt2Short(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(int16*)outputData = *(const int32*)inputData >> 16;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyInt2UChar(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(uint8*)outputData = 128 + (*(const int32*)inputData >> 24);
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyInt2Char(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(uint8*)outputData = *(const int32*)inputData >> 24;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyUChar2Float(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(float*)outputData = (*(const uint8*)inputData - 128) / 127.0f;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyUChar2Double(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(double*)outputData = (*(const uint8*)inputData - 128) / 127.0;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyUChar2Short(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(int16*)outputData = (int16)(*(const uint8*)inputData - 128) << 8;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyUChar2Int(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(int32*)outputData = (int32)(*(const uint8*)inputData - 128) << 24;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyUChar2Char(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(int8*)outputData = *(const uint8*)inputData - 128;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyChar2Float(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(float*)outputData = *(const int8*)inputData / 127.0f;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyChar2Double(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(double*)outputData = *(const int8*)inputData / 127.0;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyChar2Short(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(int16*)outputData = ((int16)*(const int8*)inputData) << 8;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyChar2Int(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(int32*)outputData = ((int16)*(const int8*)inputData) << 24;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Resampler::_CopyChar2UChar(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
while (sampleCount > 0) {
|
||||||
|
*(uint8*)outputData = *(const int8*)inputData + 128;
|
||||||
|
|
||||||
|
outputData = (void*)((uint8*)outputData + outputStride);
|
||||||
|
inputData = (void*)((uint8*)inputData + inputStride);
|
||||||
|
|
||||||
|
sampleCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jérôme Leveque
|
||||||
|
* Copyright 2003 Marcus Overhagen
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef _MULTI_AUDIO_RESAMPLER_H
|
||||||
|
#define _MULTI_AUDIO_RESAMPLER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <MediaDefs.h>
|
||||||
|
|
||||||
|
|
||||||
|
class Resampler {
|
||||||
|
public:
|
||||||
|
Resampler(uint32 sourceFormat,
|
||||||
|
uint32 destFormat);
|
||||||
|
|
||||||
|
virtual ~Resampler();
|
||||||
|
|
||||||
|
status_t InitCheck() const;
|
||||||
|
|
||||||
|
void Resample(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//static functions for converting datas
|
||||||
|
template<typename T> void _CopyType2Type(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyFloat2Double(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyFloat2Short(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyFloat2Int(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyFloat2UChar(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyFloat2Char(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
|
||||||
|
virtual void _CopyDouble2Float(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyDouble2Short(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyDouble2Int(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyDouble2UChar(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyDouble2Char(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
|
||||||
|
virtual void _CopyInt2Float(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyInt2Double(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyInt2Short(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyInt2UChar(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyInt2Char(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
|
||||||
|
virtual void _CopyShort2Float(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyShort2Double(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyShort2Int(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyShort2UChar(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyShort2Char(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
|
||||||
|
virtual void _CopyUChar2Float(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyUChar2Double(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyUChar2Short(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyUChar2Int(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyUChar2Char(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
|
||||||
|
virtual void _CopyChar2Float(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyChar2Double(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyChar2Short(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyChar2Int(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
virtual void _CopyChar2UChar(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void (Resampler::*fFunc)(const void *inputData,
|
||||||
|
uint32 inputStride, void *outputData,
|
||||||
|
uint32 outputStride, uint32 sampleCount);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline void
|
||||||
|
Resampler::Resample(const void *inputData, uint32 inputStride,
|
||||||
|
void *outputData, uint32 outputStride, uint32 sampleCount)
|
||||||
|
{
|
||||||
|
if (this->InitCheck() != B_OK)
|
||||||
|
return;
|
||||||
|
(this->*fFunc)(inputData, inputStride, outputData, outputStride,
|
||||||
|
sampleCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _MULTI_AUDIO_RESAMPLER_H
|
||||||
Reference in New Issue
Block a user