1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-09-18 19:06:34 -04:00
sdrangel/dsdplus/dsd_mbe.cpp
2016-04-10 18:58:40 +02:00

291 lines
9.8 KiB
C++

///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB. //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <string.h>
#include <math.h>
#include <mbelib.h>
#include "dsd_mbe.h"
#include "dsd_decoder.h"
namespace DSDplus
{
DSDMBEDecoder::DSDMBEDecoder(DSDDecoder *dsdDecoder) :
m_dsdDecoder(dsdDecoder)
{
}
DSDMBEDecoder::~DSDMBEDecoder()
{
}
void DSDMBEDecoder::processFrame(char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24])
{
// for (int i = 0; i < 88; i++)
// {
// imbe_d[i] = 0;
// }
memset((void *) imbe_d, 0, 88);
if ((m_dsdDecoder->m_state.synctype == 0) || (m_dsdDecoder->m_state.synctype == 1))
{
mbe_processImbe7200x4400Framef(m_dsdDecoder->m_state.audio_out_temp_buf, &m_dsdDecoder->m_state.errs,
&m_dsdDecoder->m_state.errs2, m_dsdDecoder->m_state.err_str, imbe_fr, imbe_d, m_dsdDecoder->m_state.cur_mp,
m_dsdDecoder->m_state.prev_mp, m_dsdDecoder->m_state.prev_mp_enhanced, m_dsdDecoder->m_opts.uvquality);
}
else if ((m_dsdDecoder->m_state.synctype == 14) || (m_dsdDecoder->m_state.synctype == 15))
{
mbe_processImbe7100x4400Framef(m_dsdDecoder->m_state.audio_out_temp_buf, &m_dsdDecoder->m_state.errs,
&m_dsdDecoder->m_state.errs2, m_dsdDecoder->m_state.err_str, imbe7100_fr, imbe_d,
m_dsdDecoder->m_state.cur_mp, m_dsdDecoder->m_state.prev_mp, m_dsdDecoder->m_state.prev_mp_enhanced,
m_dsdDecoder->m_opts.uvquality);
}
else if ((m_dsdDecoder->m_state.synctype == 6) || (m_dsdDecoder->m_state.synctype == 7))
{
mbe_processAmbe3600x2400Framef(m_dsdDecoder->m_state.audio_out_temp_buf, &m_dsdDecoder->m_state.errs,
&m_dsdDecoder->m_state.errs2, m_dsdDecoder->m_state.err_str, ambe_fr, ambe_d, m_dsdDecoder->m_state.cur_mp,
m_dsdDecoder->m_state.prev_mp, m_dsdDecoder->m_state.prev_mp_enhanced, m_dsdDecoder->m_opts.uvquality);
}
else
{
mbe_processAmbe3600x2450Framef(m_dsdDecoder->m_state.audio_out_temp_buf, &m_dsdDecoder->m_state.errs,
&m_dsdDecoder->m_state.errs2, m_dsdDecoder->m_state.err_str, ambe_fr, ambe_d, m_dsdDecoder->m_state.cur_mp,
m_dsdDecoder->m_state.prev_mp, m_dsdDecoder->m_state.prev_mp_enhanced, m_dsdDecoder->m_opts.uvquality);
}
if (m_dsdDecoder->m_opts.errorbars == 1)
{
fprintf(m_dsdDecoder->m_state.logfile, "%s", m_dsdDecoder->m_state.err_str);
}
processAudio();
// if (m_dsdDecoder->m_opts.wav_out_f != NULL)
// {
// writeSynthesizedVoice(opts, state);
// }
//
// if (m_dsdDecoder->m_opts.audio_out == 1)
// {
// playSynthesizedVoice(opts, state);
// }
}
void DSDMBEDecoder::processAudio()
{
int i, n;
float aout_abs, max, gainfactor, gaindelta, maxbuf;
if (m_dsdDecoder->m_opts.audio_gain == (float) 0)
{
// detect max level
max = 0;
m_dsdDecoder->m_state.audio_out_temp_buf_p = m_dsdDecoder->m_state.audio_out_temp_buf;
for (n = 0; n < 160; n++)
{
aout_abs = fabsf(*m_dsdDecoder->m_state.audio_out_temp_buf_p);
if (aout_abs > max)
{
max = aout_abs;
}
m_dsdDecoder->m_state.audio_out_temp_buf_p++;
}
*m_dsdDecoder->m_state.aout_max_buf_p = max;
m_dsdDecoder->m_state.aout_max_buf_p++;
m_dsdDecoder->m_state.aout_max_buf_idx++;
if (m_dsdDecoder->m_state.aout_max_buf_idx > 24)
{
m_dsdDecoder->m_state.aout_max_buf_idx = 0;
m_dsdDecoder->m_state.aout_max_buf_p = m_dsdDecoder->m_state.aout_max_buf;
}
// lookup max history
for (i = 0; i < 25; i++)
{
maxbuf = m_dsdDecoder->m_state.aout_max_buf[i];
if (maxbuf > max)
{
max = maxbuf;
}
}
// determine optimal gain level
if (max > (float) 0)
{
gainfactor = ((float) 30000 / max);
}
else
{
gainfactor = (float) 50;
}
if (gainfactor < m_dsdDecoder->m_state.aout_gain)
{
m_dsdDecoder->m_state.aout_gain = gainfactor;
gaindelta = (float) 0;
}
else
{
if (gainfactor > (float) 50)
{
gainfactor = (float) 50;
}
gaindelta = gainfactor - m_dsdDecoder->m_state.aout_gain;
if (gaindelta > ((float) 0.05 * m_dsdDecoder->m_state.aout_gain))
{
gaindelta = ((float) 0.05 * m_dsdDecoder->m_state.aout_gain);
}
}
gaindelta /= (float) 160;
}
else
{
gaindelta = (float) 0;
}
if (m_dsdDecoder->m_opts.audio_gain >= 0)
{
// adjust output gain
m_dsdDecoder->m_state.audio_out_temp_buf_p = m_dsdDecoder->m_state.audio_out_temp_buf;
for (n = 0; n < 160; n++)
{
*m_dsdDecoder->m_state.audio_out_temp_buf_p = (m_dsdDecoder->m_state.aout_gain
+ ((float) n * gaindelta)) * (*m_dsdDecoder->m_state.audio_out_temp_buf_p);
m_dsdDecoder->m_state.audio_out_temp_buf_p++;
}
m_dsdDecoder->m_state.aout_gain += ((float) 160 * gaindelta);
}
// copy audio datat to output buffer and upsample if necessary
m_dsdDecoder->m_state.audio_out_temp_buf_p = m_dsdDecoder->m_state.audio_out_temp_buf;
if (m_dsdDecoder->m_opts.split == 0)
{
for (n = 0; n < 160; n++)
{
upsample(*m_dsdDecoder->m_state.audio_out_temp_buf_p);
m_dsdDecoder->m_state.audio_out_temp_buf_p++;
m_dsdDecoder->m_state.audio_out_float_buf_p += 6;
m_dsdDecoder->m_state.audio_out_idx += 6;
m_dsdDecoder->m_state.audio_out_idx2 += 6;
}
m_dsdDecoder->m_state.audio_out_float_buf_p -= (960 + m_dsdDecoder->m_opts.playoffset);
// copy to output (short) buffer
for (n = 0; n < 960; n++)
{
if (*m_dsdDecoder->m_state.audio_out_float_buf_p > (float) 32760)
{
*m_dsdDecoder->m_state.audio_out_float_buf_p = (float) 32760;
}
else if (*m_dsdDecoder->m_state.audio_out_float_buf_p < (float) -32760)
{
*m_dsdDecoder->m_state.audio_out_float_buf_p = (float) -32760;
}
*m_dsdDecoder->m_state.audio_out_buf_p = (short) *m_dsdDecoder->m_state.audio_out_float_buf_p;
m_dsdDecoder->m_state.audio_out_buf_p++;
m_dsdDecoder->m_state.audio_out_float_buf_p++;
}
m_dsdDecoder->m_state.audio_out_float_buf_p += m_dsdDecoder->m_opts.playoffset;
}
else
{
for (n = 0; n < 160; n++)
{
if (*m_dsdDecoder->m_state.audio_out_temp_buf_p > (float) 32760)
{
*m_dsdDecoder->m_state.audio_out_temp_buf_p = (float) 32760;
}
else if (*m_dsdDecoder->m_state.audio_out_temp_buf_p < (float) -32760)
{
*m_dsdDecoder->m_state.audio_out_temp_buf_p = (float) -32760;
}
*m_dsdDecoder->m_state.audio_out_buf_p = (short) *m_dsdDecoder->m_state.audio_out_temp_buf_p;
m_dsdDecoder->m_state.audio_out_buf_p++;
m_dsdDecoder->m_state.audio_out_temp_buf_p++;
m_dsdDecoder->m_state.audio_out_idx++;
m_dsdDecoder->m_state.audio_out_idx2++;
}
}
// TODO: flag audio is uvailable
}
void DSDMBEDecoder::upsample(float invalue)
{
int i, j, sum;
float *outbuf1, c, d;
outbuf1 = m_dsdDecoder->m_state.audio_out_float_buf_p;
outbuf1--;
c = *outbuf1;
d = invalue;
// basic triangle interpolation
outbuf1++;
*outbuf1 = ((invalue * (float) 0.166) + (c * (float) 0.834));
outbuf1++;
*outbuf1 = ((invalue * (float) 0.332) + (c * (float) 0.668));
outbuf1++;
*outbuf1 = ((invalue * (float) 0.5) + (c * (float) 0.5));
outbuf1++;
*outbuf1 = ((invalue * (float) 0.668) + (c * (float) 0.332));
outbuf1++;
*outbuf1 = ((invalue * (float) 0.834) + (c * (float) 0.166));
outbuf1++;
*outbuf1 = d;
outbuf1++;
if (m_dsdDecoder->m_state.audio_out_idx2 > 24)
{
// smoothing
outbuf1 -= 16;
for (j = 0; j < 4; j++)
{
for (i = 0; i < 6; i++)
{
sum = 0;
outbuf1 -= 2;
sum += *outbuf1;
outbuf1 += 2;
sum += *outbuf1;
outbuf1 += 2;
sum += *outbuf1;
outbuf1 -= 2;
*outbuf1 = (sum / (float) 3);
outbuf1++;
}
outbuf1 -= 8;
}
}
}
}