Skip to content

Commit 065501e

Browse files
Improved IMBE decoder for p25p2 (#1044)
* Implement fixed-point IMBE decoder for p25p2 with "softVocoder" config option * Implement softVocoder option for DMR * Update docs to specify softVocoder applies to P25 and DMR * Software decoder outputs samples directly to PCM buffer
1 parent f40ab20 commit 065501e

19 files changed

+137
-121
lines changed

docs/CONFIGURE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ There is a list of available Plugins [here](./Plugins.md).
148148
| debugRecorderAddress | | "127.0.0.1" | string | The network address of the computer that will be monitoring the Debug Recorders. UDP packets will be sent from Trunk Recorder to this computer. The default is *"127.0.0.1"* which is the address used for monitoring on the same computer as Trunk Recorder. |
149149
| audioStreaming | | false | **true** / **false** | Whether or not to enable the audio streaming callbacks for plugins. |
150150
| newCallFromUpdate | | true | **true** / **false** | Allow for UPDATE trunking messages to start a new Call, in addition to GRANT messages. This may result in more Calls with no transmisions, and use more Recorders. The flipside is that it may catch parts of a Call that would have otherwise been missed. Turn this off if you are running out of Recorders. |
151-
| softVocoder | | false | **true** / **false** | Use the Software Decode vocoder from OP25 for Phase 1 audio. Give it a try if you are hearing weird tones in your audio. Whether it makes your audio sound better or worse is a matter of preference. |
151+
| softVocoder | | false | **true** / **false** | Use the Software Decode vocoder from OP25 for P25 and DMR. Give it a try if you are hearing weird tones in your audio. Whether it makes your audio sound better or worse is a matter of preference. |
152152
| recordUUVCalls | | true | **true** / **false** | *P25 only* Record Unit to Unit Voice calls. |
153153

154154

lib/op25_repeater/include/op25_repeater/frame_assembler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ namespace gr {
5050
* class. op25_repeater::frame_assembler::make is the public interface for
5151
* creating new instances.
5252
*/
53-
static sptr make(const char* options, int debug, int msgq_id, gr::msg_queue::sptr queue);
53+
static sptr make(const char* options, int debug, int msgq_id, gr::msg_queue::sptr queue, bool d_soft_vocoder);
5454
virtual void set_xormask(const char*p) {}
5555
virtual void set_nac(int nac) {}
5656
virtual void set_slotid(int slotid) {}

lib/op25_repeater/lib/frame_assembler_impl.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,10 @@ namespace gr {
8686
}
8787

8888
frame_assembler::sptr
89-
frame_assembler::make(const char* options, int debug, int msgq_id, gr::msg_queue::sptr queue)
89+
frame_assembler::make(const char* options, int debug, int msgq_id, gr::msg_queue::sptr queue, bool d_soft_vocoder)
9090
{
9191
return gnuradio::get_initial_sptr
92-
(new frame_assembler_impl(options, debug, msgq_id, queue));
92+
(new frame_assembler_impl(options, debug, msgq_id, queue, d_soft_vocoder));
9393
}
9494

9595
/*
@@ -107,7 +107,7 @@ namespace gr {
107107
/*
108108
* The private constructor
109109
*/
110-
frame_assembler_impl::frame_assembler_impl(const char* options, int debug, int msgq_id, gr::msg_queue::sptr queue)
110+
frame_assembler_impl::frame_assembler_impl(const char* options, int debug, int msgq_id, gr::msg_queue::sptr queue, bool d_soft_vocoder)
111111
: gr::block("frame_assembler",
112112
gr::io_signature::make (MIN_IN, MAX_IN, sizeof (char)),
113113
gr::io_signature::make ( 2, 2, sizeof(int16_t))),
@@ -122,7 +122,7 @@ namespace gr {
122122
else if (strcasecmp(options, "subchannel") == 0)
123123
d_sync = new rx_subchannel(options, logts, debug, msgq_id, queue);
124124
else
125-
d_sync = new rx_sync(options, logts, debug, msgq_id, queue, output_queue);
125+
d_sync = new rx_sync(options, logts, debug, msgq_id, queue, output_queue, d_soft_vocoder);
126126
}
127127

128128
int

lib/op25_repeater/lib/frame_assembler_impl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ namespace gr {
6363
log_ts logts;
6464

6565
public:
66-
frame_assembler_impl(const char* options, int debug, int msgq_id, gr::msg_queue::sptr queue);
66+
frame_assembler_impl(const char* options, int debug, int msgq_id, gr::msg_queue::sptr queue, bool d_soft_vocoder);
6767
~frame_assembler_impl();
6868

6969
// Where all the action really happens

lib/op25_repeater/lib/imbe_decoder.cc

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,7 @@ imbe_decoder::~imbe_decoder()
44
{
55
}
66

7-
imbe_decoder::imbe_decoder() :
8-
d_audio()
7+
imbe_decoder::imbe_decoder()
98
{
109
}
1110

12-
audio_samples*
13-
imbe_decoder::audio()
14-
{
15-
return &d_audio;
16-
}

lib/op25_repeater/lib/imbe_decoder.h

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,8 @@
2626

2727
#include <boost/noncopyable.hpp>
2828
#include <boost/shared_ptr.hpp>
29-
#include <deque>
3029
#include <vector>
3130

32-
typedef std::deque<float> audio_samples;
3331
typedef std::vector<bool> voice_codeword;
3432

3533

@@ -39,6 +37,7 @@ typedef std::vector<bool> voice_codeword;
3937
typedef std::shared_ptr<class imbe_decoder> imbe_decoder_sptr;
4038
#endif
4139

40+
#define IMBE_SAMPLES_PER_FRAME 160
4241
/**
4342
* imbe_decoder is the interface to the various mechanisms for
4443
* translating P25 voice codewords into audio samples.
@@ -64,15 +63,7 @@ class imbe_decoder : public boost::noncopyable {
6463
*
6564
* \param cw IMBE codeword (including parity check bits).
6665
*/
67-
virtual void decode(const voice_codeword& cw) = 0;
68-
69-
/**
70-
* Returns the audio_samples samples. These are mono samples at
71-
* 8KS/s represented as a float in the range -1.0 .. +1.0.
72-
*
73-
* \return A non-null pointer to a deque<float> of audio samples.
74-
*/
75-
audio_samples *audio();
66+
virtual void decode(int16_t samples[IMBE_SAMPLES_PER_FRAME], const voice_codeword& cw) = 0;
7667

7768
protected:
7869

@@ -81,15 +72,7 @@ class imbe_decoder : public boost::noncopyable {
8172
* because this is an abstract class and users should call
8273
* make_imbe_decoder to construct concrete instances.
8374
*/
84-
imbe_decoder();
85-
86-
private:
87-
88-
/**
89-
* The audio samples produced by the IMBE decoder.
90-
*/
91-
audio_samples d_audio;
92-
75+
imbe_decoder();
9376
};
9477

9578
#endif /* INCLUDED_IMBE_DECODER_H */

lib/op25_repeater/lib/imbe_vocoder/decode.cc

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@
3333
#include "dsp_sub.h"
3434
#include "imbe_vocoder.h"
3535

36+
3637
#include <string.h>
38+
#include <math.h>
3739

3840

3941

@@ -67,3 +69,61 @@ void imbe_vocoder::decode(IMBE_PARAM *imbe_param, Word16 *frame_vector, Word16 *
6769
for(j = 0; j < FRAME; j++)
6870
snd[j] = add(snd[j], snd_tmp[j]);
6971
}
72+
73+
74+
void imbe_vocoder::decode_tap(Word16 *snd, int L, float w0, const int *Vl, const float *Ml)
75+
{
76+
Word16 snd_v[FRAME];
77+
Word16 snd_uv[FRAME];
78+
int i;
79+
80+
//
81+
// Convert floating-point parameters into fixed-point IMBE_PARAM struct
82+
//
83+
84+
// Number of Harmonics (L) -> num_harms
85+
my_imbe_param.num_harms = L;
86+
87+
// Fundamental Frequency (w0) -> fund_freq
88+
// w0 is float angular frequency, convert to frequency
89+
float fund_freq_f = w0 / M_PI;
90+
// Convert fundamental frequency to fixed-point Q1.31 format
91+
my_imbe_param.fund_freq = (Word32)(fund_freq_f * (UWord32)(1LL << 31));
92+
93+
// Zero out harmonic vectors so only used harmonics have values
94+
memset(my_imbe_param.v_uv_dsn, 0, sizeof(my_imbe_param.v_uv_dsn));
95+
memset(my_imbe_param.sa, 0, sizeof(my_imbe_param.sa));
96+
97+
// Voicing Vector (Vl) -> v_uv_dsn
98+
for (i = 0; i < L; i++) {
99+
my_imbe_param.v_uv_dsn[i] = (Word16)Vl[i];
100+
}
101+
102+
// Spectral Amplitudes (Ml) -> sa
103+
for (int i = 0; i < L; i++) {
104+
my_imbe_param.sa[i] = (Word16)Ml[i];
105+
}
106+
107+
//
108+
// Pre-calculate values needed by synthesis that is typically done during sa decode
109+
//
110+
111+
my_imbe_param.div_one_by_num_harm_sh = norm_s(my_imbe_param.num_harms);
112+
my_imbe_param.div_one_by_num_harm = div_s(0x4000, my_imbe_param.num_harms << my_imbe_param.div_one_by_num_harm_sh);
113+
my_imbe_param.l_uv = 0;
114+
for (i = 0; i < my_imbe_param.num_harms; i++) {
115+
if (my_imbe_param.v_uv_dsn[i] == 0)
116+
my_imbe_param.l_uv++;
117+
}
118+
119+
//
120+
// Perform fixed-point synthesis
121+
//
122+
123+
sa_enh(&my_imbe_param);
124+
v_synt(&my_imbe_param, snd_v);
125+
uv_synt(&my_imbe_param, snd_uv);
126+
127+
for(i = 0; i < FRAME; i++)
128+
snd[i] = add(snd_v[i], snd_uv[i]);
129+
}

lib/op25_repeater/lib/imbe_vocoder/imbe_vocoder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ class imbe_vocoder
3636
// hack to enable ambe encoder read access to speech parameters
3737
const IMBE_PARAM* param(void) {return &my_imbe_param;}
3838
void set_gain_adjust(float gain_adjust) {d_gain_adjust = gain_adjust;}
39+
// decodes IMBE codec parameters in float format into 160 audio samples (snd)
40+
void decode_tap(Word16 *snd, int L, float w0, const int *Vl, const float *Ml);
3941
private:
4042
IMBE_PARAM my_imbe_param;
4143

lib/op25_repeater/lib/p25_frame_assembler_impl.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ static const int MAX_IN = 1; // maximum number of input streams
104104
p1fdma(op25audio, logts, debug, do_imbe, do_output, do_msgq, queue, output_queue, do_audio_output, soft_vocoder),
105105
d_do_audio_output(do_audio_output),
106106
d_do_phase2_tdma(do_phase2_tdma),
107-
p2tdma(op25audio, logts, 0, debug, do_msgq, queue, output_queue, do_audio_output),
107+
p2tdma(op25audio, logts, 0, debug, do_msgq, queue, output_queue, do_audio_output, soft_vocoder),
108108
d_do_msgq(do_msgq),
109109
d_msg_queue(queue),
110110
output_queue(),

lib/op25_repeater/lib/p25p1_fdma.cc

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -728,16 +728,7 @@ namespace gr {
728728

729729
if (d_soft_vocoder) {
730730
// This is vocoder that is for half-rate
731-
software_decoder.decode_fullrate(u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], E0, ET);
732-
audio_samples *samples = software_decoder.audio();
733-
for (int i=0; i < SND_FRAME; i++) {
734-
if (samples->size() > 0) {
735-
snd[i] = (int16_t)(samples->front());
736-
samples->pop_front();
737-
} else {
738-
snd[i] = 0;
739-
}
740-
}
731+
software_decoder.decode_fullrate(snd, u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], E0, ET);
741732
} else {
742733

743734
// This is the older, fullrate vocoder

0 commit comments

Comments
 (0)