Permalink
Browse files

[AE] added: perform byteswap in raw mode if sink requires it

The sink may need raw audio data either in S16_LE or S16_BE format.

Currently the code assumes that the sink takes S16_NE. However, this may
not be the case, and especially on big-endian systems the sink may need
S16_LE instead (if the audio hardware takes that instead of S16_BE).

Therefore, perform a late byteswap if needed.

It would be preferred to take this into account in the IEC-61937 packer
already, so that we wouldn't consume CPU power byteswapping padding
(which there can be a lot of) or byteswap twice. However, the IEC-61937
packer can't currently get that information from the engine/sink.
  • Loading branch information...
anssih committed May 17, 2012
1 parent a60574b commit 9df032aca44899f8700929aeed91fbe86711b983
@@ -27,6 +27,7 @@
#include "utils/log.h"
#include "utils/TimeUtils.h"
#include "utils/MathUtils.h"
+#include "utils/EndianSwap.h"
#include "threads/SingleLock.h"
#include "settings/GUISettings.h"
#include "settings/Settings.h"
@@ -883,6 +884,16 @@ void CSoftAE::Run()
}
}
+void CSoftAE::AllocateConvIfNeeded(size_t convertedSize)
+{
+ if (m_convertedSize < convertedSize)
+ {
+ _aligned_free(m_converted);
+ m_converted = (uint8_t *)_aligned_malloc(convertedSize, 16);
+ m_convertedSize = convertedSize;
+ }
+}
+
void CSoftAE::MixSounds(float *buffer, unsigned int samples)
{
SoundStateList::iterator itt;
@@ -981,12 +992,7 @@ void CSoftAE::RunOutputStage()
if (m_convertFn)
{
const unsigned int convertedBytes = m_sinkFormat.m_frames * m_sinkFormat.m_frameSize;
- if (m_convertedSize < convertedBytes)
- {
- _aligned_free(m_converted);
- m_converted = (uint8_t *)_aligned_malloc(convertedBytes, 16);
- m_convertedSize = convertedBytes;
- }
+ AllocateConvIfNeeded(convertedBytes);
m_convertFn((float*)data, needSamples, m_converted);
data = m_converted;
}
@@ -1000,7 +1006,26 @@ void CSoftAE::RunRawOutputStage()
if(m_buffer.Used() < m_sinkBlockSize)
return;
- int wroteFrames = m_sink->AddPackets((uint8_t*)m_buffer.Raw(m_sinkBlockSize), m_sinkFormat.m_frames);
+ void *data = m_buffer.Raw(m_sinkBlockSize);
+
+ if (CAEUtil::S16NeedsByteSwap(AE_FMT_S16NE, m_sinkFormat.m_dataFormat))
+ {
+ /*
+ * It would really be preferable to handle this at packing stage, so that
+ * it could byteswap the data efficiently without wasting CPU time on
+ * swapping the huge IEC 61937 zero padding between frames (or not
+ * byteswap at all, if there are two byteswaps).
+ *
+ * Unfortunately packing is done on a higher level and we can't easily
+ * tell it the needed format from here, so do it here for now (better than
+ * nothing)...
+ */
+ AllocateConvIfNeeded(m_sinkBlockSize);
+ Endian_Swap16_buf((uint16_t *)m_converted, (uint16_t *)data, m_sinkBlockSize / 2);
+ data = m_converted;
+ }
+
+ int wroteFrames = m_sink->AddPackets((uint8_t *)data, m_sinkFormat.m_frames);
m_buffer.Shift(NULL, wroteFrames * m_sinkFormat.m_frameSize);
}
@@ -192,6 +192,8 @@ class CSoftAE : public IThreadedAE
uint8_t *m_converted;
size_t m_convertedSize;
+ void AllocateConvIfNeeded(size_t convertedSize);
+
/* thread run stages */
void MixSounds (float *buffer, unsigned int samples);
void FinalizeSamples (float *buffer, unsigned int samples);
@@ -455,3 +455,20 @@ void CAEUtil::FloatRand4(const float min, const float max, float result[4], __m1
result[3] = ((float)(m_seed = (214013 * m_seed + 2531011)) * factor) - delta;
#endif
}
+
+bool CAEUtil::S16NeedsByteSwap(AEDataFormat in, AEDataFormat out)
+{
+ const AEDataFormat nativeFormat =
+#ifdef WORDS_BIGENDIAN
+ AE_FMT_S16BE;
+#else
+ AE_FMT_S16LE;
+#endif
+
+ if (in == AE_FMT_S16NE || AE_IS_RAW(in))
+ in = nativeFormat;
+ if (out == AE_FMT_S16NE || AE_IS_RAW(out))
+ out = nativeFormat;
+
+ return in != out;
+}
@@ -74,4 +74,6 @@ class CAEUtil
*/
static float FloatRand1(const float min, const float max);
static void FloatRand4(const float min, const float max, float result[4], __m128 *sseresult = NULL);
+
+ static bool S16NeedsByteSwap(AEDataFormat in, AEDataFormat out);
};

0 comments on commit 9df032a

Please sign in to comment.