Index: xbmc/cores/paplayer/AACcodec.h =================================================================== --- xbmc/cores/paplayer/AACcodec.h (revision 23261) +++ xbmc/cores/paplayer/AACcodec.h (working copy) @@ -35,6 +35,7 @@ virtual __int64 Seek(__int64 iSeekTime); virtual int ReadPCM(BYTE *pBuffer, int size, int *actualsize); virtual bool CanInit(); + virtual unsigned char* GetChannelMap(); private: static unsigned __int32 AACOpenCallback(const char *pName, const char *mode, void *userData); static void AACCloseCallback(void *userData); Index: xbmc/cores/paplayer/ICodec.h =================================================================== --- xbmc/cores/paplayer/ICodec.h (revision 23261) +++ xbmc/cores/paplayer/ICodec.h (working copy) @@ -29,6 +29,27 @@ #define READ_SUCCESS 0 #define READ_ERROR 1 +// This is the standard ALSA channel order +#define CODEC_MAP_FL 0 // Front Left +#define CODEC_MAP_FR 1 // Front Right +#define CODEC_MAP_RL 2 // Rear Left +#define CODEC_MAP_RR 3 // Rear Right +#define CODEC_MAP_FC 4 // Front Center +#define CODEC_MAP_LFE 5 // Low Frequency +#define CODEC_MAP_FLC 6 // Front Left of Center +#define CODEC_MAP_FRC 7 // Front Right of Center +#define CODEC_MAP_RC 8 // Rear Center +#define CODEC_MAP_SL 9 // Side Left +#define CODEC_MAP_SR 10 // Side Right +#define CODEC_MAP_TC 11 // Top Center +#define CODEC_MAP_TFL 12 // Top Front Left +#define CODEC_MAP_TFC 13 // Top Front Center +#define CODEC_MAP_TFR 14 // Top Front Right +#define CODEC_MAP_TRL 15 // Top Rear Left +#define CODEC_MAP_TRC 16 // Top Rear Center +#define CODEC_MAP_TRR 17 // Top Rear Right +#define CODEC_MAP_COUNT 18 // The total number of possible channels + class ICodec { public: @@ -97,6 +118,9 @@ // true if we can retrieve normalized float data immediately virtual bool HasFloatData() const { return false; } + // returns the channel mapping, or null if no re-mapping is required + virtual unsigned char * GetChannelMap() const { return NULL; } + __int64 m_TotalTime; // time in ms int m_SampleRate; int m_BitsPerSample; Index: xbmc/cores/paplayer/AudioDecoder.h =================================================================== --- xbmc/cores/paplayer/AudioDecoder.h (revision 23261) +++ xbmc/cores/paplayer/AudioDecoder.h (working copy) @@ -76,16 +76,18 @@ ICodec *GetCodec() const { return m_codec; } private: - void ProcessAudio(float *data, int numsamples); + void ProcessAudio(float *data, int *numsamples); // ReadPCMSamples() - helper to convert PCM (short/byte) to float int ReadPCMSamples(float *buffer, int numsamples, int *actualsamples); float GetReplayGain(); - // block size (number of bytes per sample * number of channels) - int m_blockSize; // pcm buffer CRingBuffer m_pcmBuffer; + // channel information + int m_NeededChannels; + unsigned char* m_ChannelMap; + // output buffer (for transferring data from the Pcm Buffer to the rest of the audio chain) float m_outputBuffer[OUTPUT_SAMPLES]; Index: xbmc/cores/paplayer/WAVcodec.h =================================================================== --- xbmc/cores/paplayer/WAVcodec.h (revision 23261) +++ xbmc/cores/paplayer/WAVcodec.h (working copy) @@ -36,10 +36,12 @@ virtual __int64 Seek(__int64 iSeekTime); virtual int ReadPCM(BYTE *pBuffer, int size, int *actualsize); virtual bool CanInit(); + virtual unsigned char* GetChannelMap(); private: long m_iDataStart; long m_iDataLen; DWORD m_ChannelMask; + unsigned char m_ChannelMap[CODEC_MAP_COUNT]; }; Index: xbmc/cores/paplayer/AudioDecoder.cpp =================================================================== --- xbmc/cores/paplayer/AudioDecoder.cpp (revision 23261) +++ xbmc/cores/paplayer/AudioDecoder.cpp (working copy) @@ -37,7 +37,6 @@ m_canPlay = false; m_gaplessBufferSize = 0; - m_blockSize = 4; } CAudioDecoder::~CAudioDecoder() @@ -90,8 +89,18 @@ Destroy(); return false; } - m_blockSize = m_codec->m_Channels * m_codec->m_BitsPerSample / 8; + m_NeededChannels = m_codec->m_Channels; + m_ChannelMap = m_codec->GetChannelMap(); + if (m_ChannelMap) + { + // if we have a channel map, we may need to open more channels + // so that we can output to the correct ones + for(int i = 0; i < m_codec->m_Channels; ++i) + if (m_ChannelMap[i] > m_NeededChannels) + m_NeededChannels = m_ChannelMap[i] + 1; + } + if (seekOffset) m_codec->Seek(seekOffset); @@ -105,8 +114,8 @@ if (!m_codec) return; - if (channels) *channels = m_codec->m_Channels; - if (samplerate) *samplerate = m_codec->m_SampleRate; + if (channels ) *channels = m_NeededChannels; + if (samplerate ) *samplerate = m_codec->m_SampleRate; if (bitspersample) *bitspersample = m_codec->m_BitsPerSample; } @@ -213,7 +222,7 @@ if ( result != READ_ERROR && actualsamples ) { // do any post processing of the audio (eg replaygain etc.) - ProcessAudio(m_inputBuffer, actualsamples); + ProcessAudio(m_inputBuffer, &actualsamples); // move it into our buffer m_pcmBuffer.WriteBinary((char *)m_inputBuffer, actualsamples * sizeof(float)); @@ -252,12 +261,15 @@ return RET_SLEEP; // nothing to do } -void CAudioDecoder::ProcessAudio(float *data, int numsamples) +void CAudioDecoder::ProcessAudio(float *data, int *numsamples) { + int c, i; + float *pos; + if (g_guiSettings.m_replayGain.iType != REPLAY_GAIN_NONE) { float gainFactor = GetReplayGain(); - for (int i = 0; i < numsamples; i++) + for (i = 0; i < *numsamples; i++) { data[i] *= gainFactor; // check the range (is this needed here?) @@ -265,6 +277,29 @@ if (data[i] < -1.0f) data[i] = -1.0f; } } + + //do we need to remap the channels? + if (m_ChannelMap) + { + // convert the samples to frames + int frames = *numsamples / m_codec->m_Channels; + float tmp[*numsamples]; + + // take a copy of all the data and zero the output + memcpy(tmp, data, *numsamples * sizeof(float)); + memset(data, 0, frames * m_NeededChannels * sizeof(float)); + + //remap the channels + pos = data; + for(i = 0; i < frames; i += m_codec->m_Channels) { + for(c = 0; c < m_codec->m_Channels; ++c) + pos[m_ChannelMap[c]] = tmp[i+c]; + pos += m_NeededChannels; + } + + // update the number of samples + *numsamples = frames * m_NeededChannels; + } } float CAudioDecoder::GetReplayGain() Index: xbmc/cores/paplayer/WAVcodec.cpp =================================================================== --- xbmc/cores/paplayer/WAVcodec.cpp (revision 23261) +++ xbmc/cores/paplayer/WAVcodec.cpp (working copy) @@ -102,6 +102,28 @@ { m_file.Read(&wfx + sizeof(WAVEFORMATEX), sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)); m_ChannelMask = Endian_SwapLE32(wfx.dwChannelMask); + + // Setup the channel mapping information + int c = 0; + if (m_ChannelMask & SPEAKER_FRONT_LEFT ) m_ChannelMap[c++] = CODEC_MAP_FL; + if (m_ChannelMask & SPEAKER_FRONT_RIGHT ) m_ChannelMap[c++] = CODEC_MAP_FR; + if (m_ChannelMask & SPEAKER_FRONT_CENTER ) m_ChannelMap[c++] = CODEC_MAP_FC; + if (m_ChannelMask & SPEAKER_LOW_FREQUENCY ) m_ChannelMap[c++] = CODEC_MAP_LFE; + if (m_ChannelMask & SPEAKER_BACK_LEFT ) m_ChannelMap[c++] = CODEC_MAP_RL; + if (m_ChannelMask & SPEAKER_BACK_RIGHT ) m_ChannelMap[c++] = CODEC_MAP_RR; + if (m_ChannelMask & SPEAKER_FRONT_LEFT_OF_CENTER ) m_ChannelMap[c++] = CODEC_MAP_FLC; + if (m_ChannelMask & SPEAKER_FRONT_RIGHT_OF_CENTER) m_ChannelMap[c++] = CODEC_MAP_FRC; + if (m_ChannelMask & SPEAKER_BACK_CENTER ) m_ChannelMap[c++] = CODEC_MAP_RC; + if (m_ChannelMask & SPEAKER_SIDE_LEFT ) m_ChannelMap[c++] = CODEC_MAP_SL; + if (m_ChannelMask & SPEAKER_SIDE_RIGHT ) m_ChannelMap[c++] = CODEC_MAP_SR; + if (m_ChannelMask & SPEAKER_TOP_CENTER ) m_ChannelMap[c++] = CODEC_MAP_TC; + if (m_ChannelMask & SPEAKER_TOP_FRONT_LEFT ) m_ChannelMap[c++] = CODEC_MAP_TFL; + if (m_ChannelMask & SPEAKER_TOP_FRONT_CENTER ) m_ChannelMap[c++] = CODEC_MAP_TFC; + if (m_ChannelMask & SPEAKER_TOP_FRONT_RIGHT ) m_ChannelMap[c++] = CODEC_MAP_TFR; + if (m_ChannelMask & SPEAKER_TOP_BACK_LEFT ) m_ChannelMap[c++] = CODEC_MAP_TRL; + if (m_ChannelMask & SPEAKER_TOP_BACK_CENTER ) m_ChannelMap[c++] = CODEC_MAP_TRC; + if (m_ChannelMask & SPEAKER_TOP_BACK_RIGHT ) m_ChannelMap[c++] = CODEC_MAP_TRR; + } else { m_ChannelMask = 0; } @@ -177,3 +199,9 @@ { return true; } + +unsigned char * WAVCodec::GetChannelMap() +{ + return (m_ChannelMask == 0) ? NULL : m_ChannelMap; +} + Index: xbmc/cores/paplayer/AACCodec/AACCodec.c =================================================================== --- xbmc/cores/paplayer/AACCodec/AACCodec.c (revision 23261) +++ xbmc/cores/paplayer/AACCodec/AACCodec.c (working copy) @@ -281,83 +281,6 @@ return tagsize; } -// AAC order : C, L, R, L", R", LFE -// XBOX order : L, R, L", R", C, LFE -static void remap_channels(unsigned char *data, unsigned int samples, unsigned int bps) -{ - unsigned int i; - - switch (bps) - { - case 8: - { - unsigned char r1, r2, r3, r4, r5, r6; - for (i = 0; i < samples; i += 6) - { - r1 = data[i]; // C - r2 = data[i+1]; // L - r3 = data[i+2]; // R - r4 = data[i+3]; // L" - r5 = data[i+4]; // R" - r6 = data[i+5]; // LFE - data[i] = r2; - data[i+1] = r3; - data[i+2] = r4; - data[i+3] = r5; - data[i+4] = r1; - data[i+5] = r6; - } - } - break; - - case 16: - default: - { - unsigned short r1, r2, r3, r4, r5, r6; - unsigned short *sample_buffer = (unsigned short *)data; - for (i = 0; i < samples; i += 6) - { - r1 = sample_buffer[i]; - r2 = sample_buffer[i+1]; - r3 = sample_buffer[i+2]; - r4 = sample_buffer[i+3]; - r5 = sample_buffer[i+4]; - r6 = sample_buffer[i+5]; - sample_buffer[i] = r2; - sample_buffer[i+1] = r3; - sample_buffer[i+2] = r4; - sample_buffer[i+3] = r5; - sample_buffer[i+4] = r1; - sample_buffer[i+5] = r6; - } - } - break; - - case 24: - case 32: - { - unsigned int r1, r2, r3, r4, r5, r6; - unsigned int *sample_buffer = (unsigned int *)data; - for (i = 0; i < samples; i += 6) - { - r1 = sample_buffer[i]; - r2 = sample_buffer[i+1]; - r3 = sample_buffer[i+2]; - r4 = sample_buffer[i+3]; - r5 = sample_buffer[i+4]; - r6 = sample_buffer[i+5]; - sample_buffer[i] = r2; - sample_buffer[i+1] = r3; - sample_buffer[i+2] = r4; - sample_buffer[i+3] = r5; - sample_buffer[i+4] = r1; - sample_buffer[i+5] = r6; - } - } - break; - } -} - int ReadMP4AAC(AACHandle handle, BYTE* pBuffer, int iSize) { int l=0; @@ -453,9 +376,6 @@ buf += delay * 8; } - if (frameInfo.channels == 6 && frameInfo.num_lfe_channels) - remap_channels(buf, sample_count, res_table[m_resolution]); - if (res_table[m_resolution] == 24) { /* convert libfaad output (3 bytes packed in 4) */ @@ -654,9 +574,6 @@ if ((frameInfo.samples > 0)) { - if (frameInfo.channels == 6 && frameInfo.num_lfe_channels) - remap_channels(sample_buffer, frameInfo.samples, res_table[m_resolution]); - if (res_table[m_resolution] == 24) { /* convert libfaad output (3 bytes packed in 4 bytes) */ Index: xbmc/cores/paplayer/AACcodec.cpp =================================================================== --- xbmc/cores/paplayer/AACcodec.cpp (revision 23261) +++ xbmc/cores/paplayer/AACcodec.cpp (working copy) @@ -257,3 +257,19 @@ return codec->m_file.GetLength(); } + +static unsigned char AACChannelMap[8][8] = { + {CODEC_MAP_FC }, // 1.0 + {CODEC_MAP_FL, CODEC_MAP_FR }, // 2.0 + {CODEC_MAP_FC, CODEC_MAP_FL , CODEC_MAP_FR }, // 3.0 + {CODEC_MAP_FC, CODEC_MAP_FL , CODEC_MAP_FR , CODEC_MAP_RC }, // 4.0 + {CODEC_MAP_FC, CODEC_MAP_FL , CODEC_MAP_FR , CODEC_MAP_RL, CODEC_MAP_RR }, // 5.0 + {CODEC_MAP_FC, CODEC_MAP_FL , CODEC_MAP_FR , CODEC_MAP_RL, CODEC_MAP_RR, CODEC_MAP_LFE }, // 5.1 + {}, //Invalid + {CODEC_MAP_FC, CODEC_MAP_FLC, CODEC_MAP_FRC, CODEC_MAP_FL, CODEC_MAP_FR, CODEC_MAP_RL, CODEC_MAP_RR, CODEC_MAP_LFE} // 7.1 +}; + +unsigned char* AACCodec::GetChannelMap() +{ + return ((m_Channels != 7) && (m_Channels < 9)) ? AACChannelMap[m_Channels-1] : NULL; +}