311 changes: 172 additions & 139 deletions mythtv/libs/libmythfreesurround/freesurround.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
Copyright (C) 2007 Christian Kothe, Mark Spieth
Copyright (C) 2010-2011 Jean-Yves Avenard
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
Expand Down Expand Up @@ -40,6 +41,7 @@ using namespace std;
static const unsigned default_block_size = SURROUND_BUFSIZE;
// Gain of center and lfe channels in passive mode (sqrt 0.5)
static const float center_level = 0.707107;
static const float m3db = 0.7071067811865476f; // 3dB = SQRT(2)

unsigned int block_size = default_block_size;

Expand Down Expand Up @@ -101,18 +103,21 @@ class object_pool
struct buffers
{
buffers(unsigned int s):
l(s),r(s),c(s),ls(s),rs(s),lfe(s) { }
l(s),r(s),c(s),ls(s),rs(s),lfe(s), rls(s), rrs(s) { }
void resize(unsigned int s)
{
l.resize(s); r.resize(s); lfe.resize(s);
ls.resize(s); rs.resize(s); c.resize(s);
rls.resize(s); rrs.resize(s);
}
void clear()
{
l.clear(); r.clear(); lfe.clear();
ls.clear(); rs.clear(); c.clear();
rls.clear(); rrs.clear();
}
std::vector<float> l,r,c,ls,rs,lfe,cs,lcs,rcs; // for demultiplexing
std::vector<float> l,r,c,ls,rs,lfe,cs,lcs,rcs,
rls, rrs; // for demultiplexing
};

// construction methods
Expand Down Expand Up @@ -224,16 +229,39 @@ uint FreeSurround::putFrames(void* buffer, uint numFrames, uint numChannels)
bool process = true;
float *samples = (float *)buffer;
// demultiplex
switch (surround_mode)

float **inputs = decoder->getInputBuffers();
float *lt = &inputs[0][ic];
float *rt = &inputs[1][ic];

if ((surround_mode != SurroundModePassive) && (ic+numFrames > bs))
{
numFrames = bs - ic;
}

switch (numChannels)
{
case SurroundModePassive:
switch (numChannels)
case 1:
switch (surround_mode)
{
case 1:
case SurroundModePassive:
for (i = 0; i < numFrames && ic < bs; i++,ic++)
bufs->l[ic] = bufs->c[ic] = bufs->r[ic] = samples[i];
process = false;
break;
default:
for (i=0; i<numFrames; i++)
*lt++ = *rt++ = *samples++;
process = true;
break;
case 2:
}
channels = 6;
break;

case 2:
switch (surround_mode)
{
case SurroundModePassive:
for (i = 0; i < numFrames && ic < bs; i++,ic++)
{
float lt = *samples++;
Expand All @@ -243,98 +271,92 @@ uint FreeSurround::putFrames(void* buffer, uint numFrames, uint numChannels)
bufs->r[ic] = rt;
bufs->ls[ic] = bufs->rs[ic] = (lt-rt) * center_level;
}
process = false;
break;
case 5:
for (i = 0; i < numFrames && ic < bs; i++,ic++)
{
float lt = *samples++;
float rt = *samples++;
float c = *samples++;
float lfe = (lt+rt) * center_level;
float ls = *samples++;
float rs = *samples++;
bufs->l[ic] = lt;
bufs->lfe[ic] = lfe;
bufs->c[ic] = c;
bufs->r[ic] = rt;
bufs->ls[ic] = ls;
bufs->rs[ic] = rs;
}
break;
}
in_count = 0;
out_count = processed_size = ic;
processed = false;
latency_frames = 0;
break;

default:
float **inputs = decoder->getInputBuffers();
float *lt = &inputs[0][ic];
float *rt = &inputs[1][ic];
if ((ic+numFrames) > bs)
numFrames = bs - ic;
switch (numChannels)
{
case 1:
for (i=0; i<numFrames; i++)
*lt++ = *rt++ = *samples++;
break;
case 2:
default:
for (i=0; i<numFrames; i++)
{
*lt++ = *samples++;
*rt++ = *samples++;
}
break;
case 5:
// 5 ch is always passive mode,
for (i = 0; i < numFrames && ic < bs; i++,ic++)
{
float l = *samples++;
float r = *samples++;
float c = *samples++;
float lfe = (l+r) * center_level;
float ls = *samples++;
float rs = *samples++;
bufs->l[ic] = l;
bufs->lfe[ic] = lfe;
bufs->c[ic] = c;
bufs->r[ic] = r;
bufs->ls[ic] = ls;
bufs->rs[ic] = rs;
}
process = false;
process = true;
break;
}
if (process)
channels = 6;
break;

case 5:
for (i = 0; i < numFrames && ic < bs; i++,ic++)
{
ic += numFrames;
if (ic != bs)
{
// dont modify unless no processing is to be done
// for audiotime consistency
in_count = ic;
break;
}
processed = process;
// process_block takes some time so dont update in and out count
// before its finished so that Audiotime is correctly calculated
process_block();
in_count = 0;
out_count = bs;
processed_size = bs;
latency_frames = block_size/2;
float lt = *samples++;
float rt = *samples++;
float c = *samples++;
float ls = *samples++;
float rs = *samples++;
bufs->l[ic] = lt;
bufs->lfe[ic] = 0.0f;
bufs->c[ic] = c;
bufs->r[ic] = rt;
bufs->ls[ic] = ls;
bufs->rs[ic] = rs;
}
else
process = false;
channels = 6;
break;

case 7:
for (i = 0; i < numFrames && ic < bs; i++,ic++)
{
in_count = 0;
out_count = processed_size = ic;
processed = false;
latency_frames = 0;
// 3F3R-LFE L R C LFE BC LS RS
float lt = *samples++;
float rt = *samples++;
float c = *samples++;
float lfe = *samples++;
float cs = *samples++;
float ls = *samples++;
float rs = *samples++;
bufs->l[ic] = lt;
bufs->lfe[ic] = lfe;
bufs->c[ic] = c;
bufs->r[ic] = rt;
bufs->ls[ic] = ls;
bufs->rs[ic] = rs;
bufs->rls[ic] = bufs->rrs[ic] = cs * m3db;
}
process = false;
channels = 8;
break;
default:
break;
}
if (process)
{
ic += numFrames;
if (ic != bs)
{
// dont modify unless no processing is to be done
// for audiotime consistency
in_count = ic;
}
else
{
processed = process;
// process_block takes some time so dont update in and out count
// before its finished so that Audiotime is correctly calculated
process_block();
in_count = 0;
out_count = bs;
processed_size = bs;
latency_frames = block_size/2;
}
}
else
{
in_count = 0;
out_count = processed_size = ic;
processed = false;
latency_frames = 0;
}

LOG(VB_AUDIO | VB_TIMESTAMP, LOG_DEBUG,
QString("FreeSurround::putFrames %1 #ch %2 used %3 generated %4")
Expand All @@ -350,66 +372,77 @@ uint FreeSurround::receiveFrames(void *buffer, uint maxFrames)
if (maxFrames > oc) maxFrames = oc;
uint outindex = processed_size - oc;
float *output = (float *)buffer;

switch (surround_mode)
if (channels == 8)
{
float *l = &bufs->l[outindex];
float *c = &bufs->c[outindex];
float *r = &bufs->r[outindex];
float *ls = &bufs->ls[outindex];
float *rs = &bufs->rs[outindex];
float *lfe = &bufs->lfe[outindex];
float *rls = &bufs->rls[outindex];
float *rrs = &bufs->rrs[outindex];
for (i = 0; i < maxFrames; i++)
{
// printf("1:%f 2:%f 3:%f 4:%f 5:%f 6:%f 7:%f 8:%f\n",
// *l, *r, *c, *lfe, *rls, *rrs, *ls, *rs);

// 3F4-LFE L R C LFE Rls Rrs LS RS
*output++ = *l++;
*output++ = *r++;
*output++ = *c++;
*output++ = *lfe++;
*output++ = *rls++;
*output++ = *rrs++;
*output++ = *ls++;
*output++ = *rs++;
}
oc -= maxFrames;
outindex += maxFrames;
}
else // channels == 6
{
case SurroundModePassive:
if (processed)
{
float** outputs = decoder->getOutputBuffers();
float *l = &outputs[0][outindex];
float *c = &outputs[1][outindex];
float *r = &outputs[2][outindex];
float *ls = &outputs[3][outindex];
float *rs = &outputs[4][outindex];
float *lfe = &outputs[5][outindex];
for (i = 0; i < maxFrames; i++)
{
*output++ = bufs->l[outindex];
*output++ = bufs->r[outindex];
*output++ = bufs->c[outindex];
*output++ = bufs->lfe[outindex];
*output++ = bufs->ls[outindex];
*output++ = bufs->rs[outindex];
oc--;
outindex++;
}
break;

default:
if (processed)
{
float** outputs = decoder->getOutputBuffers();
float *l = &outputs[0][outindex];
float *c = &outputs[1][outindex];
float *r = &outputs[2][outindex];
float *ls = &outputs[3][outindex];
float *rs = &outputs[4][outindex];
float *lfe = &outputs[5][outindex];
for (i = 0; i < maxFrames; i++)
{
*output++ = *l++;
*output++ = *r++;
*output++ = *c++;
*output++ = *lfe++;
*output++ = *ls++;
*output++ = *rs++;
}
oc -= maxFrames;
outindex += maxFrames;
*output++ = *l++;
*output++ = *r++;
*output++ = *c++;
*output++ = *lfe++;
*output++ = *ls++;
*output++ = *rs++;
}
else
oc -= maxFrames;
outindex += maxFrames;
}
else
{
float *l = &bufs->l[outindex];
float *c = &bufs->c[outindex];
float *r = &bufs->r[outindex];
float *ls = &bufs->ls[outindex];
float *rs = &bufs->rs[outindex];
float *lfe = &bufs->lfe[outindex];
for (i = 0; i < maxFrames; i++)
{
float *l = &bufs->l[outindex];
float *c = &bufs->c[outindex];
float *r = &bufs->r[outindex];
float *ls = &bufs->ls[outindex];
float *rs = &bufs->rs[outindex];
float *lfe = &bufs->lfe[outindex];
for (i = 0; i < maxFrames; i++)
{
*output++ = *l++;
*output++ = *r++;
*output++ = *c++;
*output++ = *lfe++;
*output++ = *ls++;
*output++ = *rs++;
}
oc -= maxFrames;
outindex += maxFrames;
*output++ = *l++;
*output++ = *r++;
*output++ = *c++;
*output++ = *lfe++;
*output++ = *ls++;
*output++ = *rs++;
}
break;
oc -= maxFrames;
outindex += maxFrames;
}
}
out_count = oc;
LOG(VB_AUDIO | VB_TIMESTAMP, LOG_DEBUG,
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythfreesurround/freesurround.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class FreeSurround
int processed_size; // amount processed
SurroundMode surround_mode; // 1 of 3 surround modes supported
int latency_frames; // number of frames of incurred latency
int channels;
};

#endif

52 changes: 32 additions & 20 deletions mythtv/programs/mythfrontend/audiogeneralsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,10 +586,10 @@ void AudioTestThread::run()
{ 0, 1, 1 }, //stereo
{ }, //not used
{ }, //not used
{ }, //not used
{ 0, 2, 1, 4, 3 }, //5.0
{ 0, 2, 1, 5, 4, 3 }, //5.1
{ }, //not used
{ 0, 2, 1, 7, 5, 4, 6, 3 }, //7.1
{ 0, 2, 1, 6, 4, 5, 3 }, //6.1
{ 0, 2, 1, 7, 5, 4, 6, 3 }, //7.1
};

if (m_audioOutput)
Expand Down Expand Up @@ -633,17 +633,24 @@ void AudioTestThread::run()
case 4:
if (m_channels == 6)
channel = "surroundleft";
else if (m_channels == 7)
channel = "rearright";
else
channel = "rearleft";
break;
case 5:
if (m_channels == 6)
channel = "surroundright";
else if (m_channels == 7)
channel = "surroundleft";
else
channel = "rearright";
break;
case 6:
channel = "surroundleft";
if (m_channels == 7)
channel = "surroundright";
else
channel = "surroundleft";
break;
case 7:
channel = "surroundright";
Expand All @@ -668,8 +675,7 @@ void AudioTestThread::run()
LOG(VB_AUDIO, LOG_ERR, "AddData() Audio buffer "
"overflow, audio data lost!");
}
// a tad less than 1/48th of a second to avoid underruns
usleep((1000000 / m_samplerate) * 1000);
usleep(m_audioOutput->LengthLastData() * 1000);
}
m_audioOutput->Drain();
m_audioOutput->Pause(true);
Expand All @@ -689,17 +695,17 @@ void AudioTestThread::run()
AudioTest::AudioTest(QString main, QString passthrough,
int channels, AudioOutputSettings settings)
: VerticalConfigurationGroup(false, true, false, false),
m_channels(channels),
m_frontleft(NULL), m_frontright(NULL), m_center(NULL),
m_surroundleft(NULL), m_surroundright(NULL),
m_rearleft(NULL), m_rearright(NULL), m_lfe(NULL),
m_main(main), m_passthrough(passthrough), m_settings(settings),
m_quality(false)
{
m_channels = gCoreContext->GetNumSetting("TestingChannels", channels);
setLabel(QObject::tr("Audio Configuration Testing"));

m_at = new AudioTestThread(this, main, passthrough, channels,
settings, m_quality);
m_at = new AudioTestThread(this, m_main, m_passthrough, m_channels,
m_settings, m_quality);
if (!m_at->result().isEmpty())
{
QString msg = main + QObject::tr(" is invalid or not "
Expand Down Expand Up @@ -740,36 +746,42 @@ AudioTest::AudioTest(QString main, QString passthrough,
m_rearleft->setLabel(QObject::tr("Rear Left"));
connect(m_rearleft,
SIGNAL(pressed(QString)), this, SLOT(toggle(QString)));
reargroup->addChild(m_rearleft);

case 7:
m_rearright = new TransButtonSetting("4");
m_rearright->setLabel(QObject::tr("Rear Right"));
m_rearright->setLabel(QObject::tr(m_channels == 8 ?
"Rear Right" : "Rear Center"));
connect(m_rearright,
SIGNAL(pressed(QString)), this, SLOT(toggle(QString)));

reargroup->addChild(m_rearleft);
reargroup->addChild(m_rearright);

case 6:
m_surroundleft = new TransButtonSetting(m_channels == 6 ?
"4" : "6");
m_lfe = new TransButtonSetting(m_channels == 6 ? "5" :
m_channels == 7 ? "6" : "7");
m_lfe->setLabel(QObject::tr("LFE"));
connect(m_lfe,
SIGNAL(pressed(QString)), this, SLOT(toggle(QString)));

case 5:
m_surroundleft = new TransButtonSetting(m_channels == 6 ? "4" :
m_channels == 7 ? "5" : "6");
m_surroundleft->setLabel(QObject::tr("Surround Left"));
connect(m_surroundleft,
SIGNAL(pressed(QString)), this, SLOT(toggle(QString)));
m_surroundright = new TransButtonSetting("3");
m_surroundright->setLabel(QObject::tr("Surround Right"));
connect(m_surroundright,
SIGNAL(pressed(QString)), this, SLOT(toggle(QString)));
m_lfe = new TransButtonSetting(m_channels == 6 ? "5" : "7");
m_lfe->setLabel(QObject::tr("LFE"));
connect(m_lfe,
SIGNAL(pressed(QString)), this, SLOT(toggle(QString)));

m_center = new TransButtonSetting("1");
m_center->setLabel(QObject::tr("Center"));
connect(m_center,
SIGNAL(pressed(QString)), this, SLOT(toggle(QString)));
frontgroup->addChild(m_center);
middlegroup->addChild(m_surroundleft);
middlegroup->addChild(m_lfe);
if (m_lfe)
middlegroup->addChild(m_lfe);
middlegroup->addChild(m_surroundright);

case 2:
Expand Down