1 /* -*- c++ -*- */
2 /*
3  * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt
4  *           https://gqrx.dk/
5  *
6  * Copyright 2012 Alexandru Csete OZ9AEC.
7  * FM stereo implementation by Alex Grinkov a.grinkov(at)gmail.com.
8  *
9  * Gqrx is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3, or (at your option)
12  * any later version.
13  *
14  * Gqrx is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Gqrx; see the file COPYING.  If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street,
22  * Boston, MA 02110-1301, USA.
23  */
24 #include <gnuradio/io_signature.h>
25 #include <math.h>
26 #include <iostream>
27 #include <dsp/stereo_demod.h>
28 
29 
30 /* Create a new instance of stereo_demod and return a boost shared_ptr. */
make_stereo_demod(float quad_rate,float audio_rate,bool stereo,bool oirt)31 stereo_demod_sptr make_stereo_demod(float quad_rate, float audio_rate,
32                                     bool stereo, bool oirt)
33 {
34     return gnuradio::get_initial_sptr(new stereo_demod(quad_rate,
35                                                        audio_rate, stereo, oirt));
36 }
37 
38 
39 static const int MIN_IN  = 1; /* Minimum number of input streams. */
40 static const int MAX_IN  = 1; /* Maximum number of input streams. */
41 static const int MIN_OUT = 2; /* Minimum number of output streams. */
42 static const int MAX_OUT = 2; /* Maximum number of output streams. */
43 
44 /*! \brief Create stereo demodulator object.
45  *
46  * Use make_stereo_demod() instead.
47  */
stereo_demod(float input_rate,float audio_rate,bool stereo,bool oirt)48 stereo_demod::stereo_demod(float input_rate, float audio_rate, bool stereo, bool oirt)
49     : gr::hier_block2("stereo_demod",
50                      gr::io_signature::make (MIN_IN,  MAX_IN,  sizeof (float)),
51                      gr::io_signature::make (MIN_OUT, MAX_OUT, sizeof (float))),
52     d_input_rate(input_rate),
53     d_audio_rate(audio_rate),
54     d_stereo(stereo),
55     d_oirt(oirt)
56 {
57   double cutof_freq = d_oirt ? 15e3 : 17e3;
58   lpf0 = make_lpf_ff(d_input_rate, cutof_freq, 2e3); // FIXME
59   audio_rr0 = make_resampler_ff(d_audio_rate/d_input_rate);
60   deemph0 = make_fm_deemph(d_audio_rate, 50.0e-6);
61 
62   if (d_stereo)
63   {
64     lpf1 = make_lpf_ff(d_input_rate, cutof_freq, 2e3, -2.1); // FIXME
65     audio_rr1 = make_resampler_ff(d_audio_rate/d_input_rate);
66     deemph1 = make_fm_deemph(d_audio_rate, 50.0e-6);
67 
68     if (!d_oirt)
69     {
70         d_tone_taps = gr::filter::firdes::complex_band_pass(
71                                        20.0,         // gain,
72 		                                   d_input_rate, // sampling_freq
73                                        18980.,       // low_cutoff_freq
74                                        19020.,       // high_cutoff_freq
75                                        1000.);       // transition_width
76         pll = gr::analog::pll_refout_cc::make(0.001,    // loop_bw FIXME
77                                 2*M_PI * 19020 / input_rate,  // max_freq
78                                 2*M_PI * 18980 / input_rate); // min_freq
79         subtone = gr::blocks::multiply_cc::make();
80     } else {
81         d_tone_taps = gr::filter::firdes::complex_band_pass(
82                                        1.0,          // gain,
83                                        d_input_rate, // sampling_freq
84                                        31200.,       // low_cutoff_freq
85                                        31300.,       // high_cutoff_freq
86                                        100.);        // transition_width
87         pll = gr::analog::pll_refout_cc::make(0.001,    // loop_bw FIXME
88                                 2*M_PI * 31200 / input_rate,  // max_freq
89                                 2*M_PI * 31300 / input_rate); // min_freq
90     }
91 
92     tone = gr::filter::fir_filter_fcc::make(1, d_tone_taps);
93     delay = gr::blocks::delay::make(sizeof(float), (d_tone_taps.size() - 1) / 2);
94 
95     lo = gr::blocks::complex_to_imag::make();
96 
97     mixer = gr::blocks::multiply_ff::make();
98 
99     add = gr::blocks::add_ff::make();
100     sub = gr::blocks::sub_ff::make();
101 
102     /* connect block */
103     if (!d_oirt) {
104         connect(self(), 0, tone, 0);
105         connect(self(), 0, delay, 0);
106         connect(tone, 0, pll, 0);
107         connect(pll, 0, subtone, 0);
108         connect(pll, 0, subtone, 1);
109         connect(subtone, 0, lo, 0);
110 
111         connect(lo, 0, mixer, 0);
112     } else {
113         connect(self(), 0, tone, 0);
114         connect(self(), 0, delay, 0);
115         connect(tone, 0, pll, 0);
116         connect(pll, 0, lo, 0);
117         connect(lo, 0, mixer, 0);
118     }
119 
120     connect(delay, 0, mixer, 1);
121 
122     connect(delay, 0, lpf0, 0);
123     connect(mixer, 0, lpf1, 0);
124 
125     connect(lpf0, 0, audio_rr0, 0); // sum
126     connect(lpf1, 0, audio_rr1, 0); // delta
127 
128     connect(audio_rr0, 0, add,   0);
129     connect(audio_rr1, 0, add,   1);
130     connect(add,       0, deemph0, 0);
131     connect(deemph0,   0, self(), 0); // left = sum + delta
132 
133     connect(audio_rr0, 0, sub,   0);
134     connect(audio_rr1, 0, sub,   1);
135     connect(sub,       0, deemph1, 0);
136     connect(deemph1,   0, self(), 1); // right = sum - delta
137   }
138   else // if (!d_stereo)
139   {
140     /* connect block */
141     connect(self(), 0, lpf0, 0);
142     connect(lpf0,   0, audio_rr0, 0);
143     connect(audio_rr0, 0, deemph0, 0);
144     connect(deemph0, 0, self(), 0);
145     connect(deemph0, 0, self(), 1);
146   }
147 }
148 
149 
~stereo_demod()150 stereo_demod::~stereo_demod()
151 {
152 
153 }
154