diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5e47c7d15..8bb7f3e7f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -96,6 +96,7 @@ set(sdrbase_SOURCES
sdrbase/dsp/afsquelch.cpp
sdrbase/dsp/agc.cpp
sdrbase/dsp/downchannelizer.cpp
+ sdrbase/dsp/upchannelizer.cpp
sdrbase/dsp/channelmarker.cpp
sdrbase/dsp/ctcssdetector.cpp
sdrbase/dsp/dspcommands.cpp
@@ -124,6 +125,7 @@ set(sdrbase_SOURCES
sdrbase/dsp/scopevis.cpp
sdrbase/dsp/spectrumvis.cpp
sdrbase/dsp/threadedbasebandsamplesink.cpp
+ sdrbase/dsp/threadedbasebandsamplesource.cpp
sdrbase/gui/aboutdialog.cpp
sdrbase/gui/addpresetdialog.cpp
@@ -182,6 +184,7 @@ set(sdrbase_HEADERS
sdrbase/dsp/afsquelch.h
sdrbase/dsp/downchannelizer.h
+ sdrbase/dsp/upchannelizer.h
sdrbase/dsp/channelmarker.h
sdrbase/dsp/complex.h
sdrbase/dsp/decimators.h
@@ -218,6 +221,7 @@ set(sdrbase_HEADERS
sdrbase/dsp/scopevis.h
sdrbase/dsp/spectrumvis.h
sdrbase/dsp/threadedbasebandsamplesink.h
+ sdrbase/dsp/threadedbasebandsamplesource.h
sdrbase/gui/aboutdialog.h
sdrbase/gui/addpresetdialog.h
diff --git a/doc/model/SDRAngel.mdj b/doc/model/SDRAngel.mdj
index 180601b57..e90e4db7a 100644
--- a/doc/model/SDRAngel.mdj
+++ b/doc/model/SDRAngel.mdj
@@ -5119,8 +5119,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 184,
- "top": -232,
+ "left": 280,
+ "top": -296,
"width": 0,
"height": 13,
"autoResize": false,
@@ -5143,8 +5143,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 957,
- "top": 119,
+ "left": 1005,
+ "top": 87,
"width": 69,
"height": 13,
"autoResize": false,
@@ -5168,8 +5168,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 184,
- "top": -232,
+ "left": 280,
+ "top": -296,
"width": 79,
"height": 13,
"autoResize": false,
@@ -5193,8 +5193,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 184,
- "top": -232,
+ "left": 280,
+ "top": -296,
"width": 0,
"height": 13,
"autoResize": false,
@@ -5212,8 +5212,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 952,
- "top": 112,
+ "left": 1000,
+ "top": 80,
"width": 79,
"height": 25,
"autoResize": false,
@@ -5248,8 +5248,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 952,
- "top": 137,
+ "left": 1000,
+ "top": 105,
"width": 79,
"height": 10,
"autoResize": false
@@ -5272,8 +5272,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 952,
- "top": 147,
+ "left": 1000,
+ "top": 115,
"width": 79,
"height": 10,
"autoResize": false
@@ -5296,8 +5296,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 72,
- "top": -128,
+ "left": 120,
+ "top": -160,
"width": 10,
"height": 10,
"autoResize": false
@@ -5320,8 +5320,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 72,
- "top": -128,
+ "left": 120,
+ "top": -160,
"width": 10,
"height": 10,
"autoResize": false
@@ -5336,8 +5336,8 @@
"showShadow": true,
"containerChangeable": true,
"containerExtending": false,
- "left": 952,
- "top": 112,
+ "left": 1000,
+ "top": 80,
"width": 79,
"height": 45,
"autoResize": false,
@@ -9230,7 +9230,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 208,
+ "left": 496,
"top": 80,
"width": 0,
"height": 13,
@@ -9254,7 +9254,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 933,
+ "left": 1077,
"top": 207,
"width": 70,
"height": 13,
@@ -9279,7 +9279,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 208,
+ "left": 496,
"top": 80,
"width": 79,
"height": 13,
@@ -9304,7 +9304,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 208,
+ "left": 496,
"top": 80,
"width": 0,
"height": 13,
@@ -9323,7 +9323,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 928,
+ "left": 1072,
"top": 200,
"width": 80,
"height": 25,
@@ -9359,7 +9359,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 928,
+ "left": 1072,
"top": 225,
"width": 80,
"height": 10,
@@ -9383,7 +9383,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 928,
+ "left": 1072,
"top": 235,
"width": 80,
"height": 10,
@@ -9407,7 +9407,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 104,
+ "left": 248,
"top": 40,
"width": 10,
"height": 10,
@@ -9431,7 +9431,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 104,
+ "left": 248,
"top": 40,
"width": 10,
"height": 10,
@@ -9447,7 +9447,7 @@
"showShadow": true,
"containerChangeable": true,
"containerExtending": false,
- "left": 928,
+ "left": 1072,
"top": 200,
"width": 80,
"height": 45,
@@ -9507,8 +9507,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 829,
- "top": 186,
+ "left": 902,
+ "top": 184,
"width": 0,
"height": 13,
"autoResize": false,
@@ -9540,8 +9540,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 824,
- "top": 200,
+ "left": 899,
+ "top": 199,
"width": 0,
"height": 13,
"autoResize": false,
@@ -9573,8 +9573,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 838,
- "top": 157,
+ "left": 909,
+ "top": 155,
"width": 0,
"height": 13,
"autoResize": false,
@@ -9605,7 +9605,7 @@
"$ref": "AAAAAAFXjMDFwaB3R08="
},
"lineStyle": 1,
- "points": "927:209;742:148",
+ "points": "1071:213;742:140",
"stereotypeDisplay": "label",
"showVisibility": true,
"showProperty": true,
@@ -9654,8 +9654,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -112,
- "top": -32,
+ "left": 112,
+ "top": -16,
"width": 0,
"height": 13,
"autoResize": false,
@@ -9678,8 +9678,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 821,
- "top": 295,
+ "left": 933,
+ "top": 303,
"width": 88,
"height": 13,
"autoResize": false,
@@ -9703,8 +9703,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -112,
- "top": -32,
+ "left": 112,
+ "top": -16,
"width": 79,
"height": 13,
"autoResize": false,
@@ -9728,8 +9728,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -112,
- "top": -32,
+ "left": 112,
+ "top": -16,
"width": 0,
"height": 13,
"autoResize": false,
@@ -9747,8 +9747,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 816,
- "top": 288,
+ "left": 928,
+ "top": 296,
"width": 98,
"height": 25,
"autoResize": false,
@@ -9783,8 +9783,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 816,
- "top": 313,
+ "left": 928,
+ "top": 321,
"width": 98,
"height": 10,
"autoResize": false
@@ -9807,8 +9807,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 816,
- "top": 323,
+ "left": 928,
+ "top": 331,
"width": 98,
"height": 10,
"autoResize": false
@@ -9831,8 +9831,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -56,
- "top": -16,
+ "left": 56,
+ "top": -8,
"width": 10,
"height": 10,
"autoResize": false
@@ -9855,8 +9855,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -56,
- "top": -16,
+ "left": 56,
+ "top": -8,
"width": 10,
"height": 10,
"autoResize": false
@@ -9871,8 +9871,8 @@
"showShadow": true,
"containerChangeable": true,
"containerExtending": false,
- "left": 816,
- "top": 288,
+ "left": 928,
+ "top": 296,
"width": 98,
"height": 45,
"autoResize": false,
@@ -9931,8 +9931,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 790,
- "top": 336,
+ "left": 845,
+ "top": 357,
"width": 144,
"height": 13,
"autoResize": false,
@@ -9965,8 +9965,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 804,
- "top": 358,
+ "left": 855,
+ "top": 369,
"width": 0,
"height": 13,
"autoResize": false,
@@ -9998,8 +9998,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 787,
- "top": 317,
+ "left": 845,
+ "top": 325,
"width": 0,
"height": 13,
"autoResize": false,
@@ -10031,8 +10031,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 796,
- "top": 346,
+ "left": 904,
+ "top": 343,
"width": 0,
"height": 13,
"autoResize": false,
@@ -10064,8 +10064,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 798,
- "top": 359,
+ "left": 905,
+ "top": 356,
"width": 0,
"height": 13,
"autoResize": false,
@@ -10097,8 +10097,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 790,
- "top": 319,
+ "left": 903,
+ "top": 315,
"width": 0,
"height": 13,
"autoResize": false,
@@ -10130,8 +10130,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 800,
- "top": 344,
+ "left": 799,
+ "top": 366,
"width": 0,
"height": 13,
"autoResize": false,
@@ -10163,8 +10163,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 807,
- "top": 356,
+ "left": 804,
+ "top": 378,
"width": 0,
"height": 13,
"autoResize": false,
@@ -10196,8 +10196,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 783,
- "top": 320,
+ "left": 786,
+ "top": 340,
"width": 7,
"height": 13,
"autoResize": false,
@@ -10277,7 +10277,7 @@
"$ref": "AAAAAAFXjMG1TqVyU1Q="
},
"lineStyle": 1,
- "points": "815:329;771:346",
+ "points": "927:329;771:363",
"stereotypeDisplay": "label",
"showVisibility": true,
"showProperty": true,
@@ -10345,8 +10345,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 880,
- "top": 263,
+ "left": 1007,
+ "top": 268,
"width": 85,
"height": 13,
"autoResize": false,
@@ -10379,8 +10379,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 895,
- "top": 237,
+ "left": 1025,
+ "top": 239,
"width": 0,
"height": 13,
"autoResize": false,
@@ -10412,8 +10412,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 924,
- "top": 271,
+ "left": 1051,
+ "top": 276,
"width": 0,
"height": 13,
"autoResize": false,
@@ -10445,8 +10445,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 900,
- "top": 252,
+ "left": 1020,
+ "top": 261,
"width": 0,
"height": 13,
"autoResize": false,
@@ -10478,8 +10478,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 894,
- "top": 241,
+ "left": 1014,
+ "top": 249,
"width": 0,
"height": 13,
"autoResize": false,
@@ -10511,8 +10511,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 915,
- "top": 276,
+ "left": 1032,
+ "top": 286,
"width": 0,
"height": 13,
"autoResize": false,
@@ -10544,8 +10544,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 910,
- "top": 244,
+ "left": 1049,
+ "top": 241,
"width": 0,
"height": 13,
"autoResize": false,
@@ -10577,8 +10577,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 900,
- "top": 235,
+ "left": 1039,
+ "top": 232,
"width": 0,
"height": 13,
"autoResize": false,
@@ -10610,8 +10610,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 944,
- "top": 247,
+ "left": 1082,
+ "top": 248,
"width": 7,
"height": 13,
"autoResize": false,
@@ -10691,7 +10691,7 @@
"$ref": "AAAAAAFXjMG1TqVyU1Q="
},
"lineStyle": 1,
- "points": "891:287;940:245",
+ "points": "1008:295;1079:245",
"stereotypeDisplay": "label",
"showVisibility": true,
"showProperty": true,
@@ -11043,8 +11043,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 757,
- "top": 271,
+ "left": 818,
+ "top": 277,
"width": 92,
"height": 13,
"autoResize": false,
@@ -11077,8 +11077,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 793,
- "top": 282,
+ "left": 858,
+ "top": 291,
"width": 0,
"height": 13,
"autoResize": false,
@@ -11110,8 +11110,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 824,
- "top": 248,
+ "left": 877,
+ "top": 250,
"width": 0,
"height": 13,
"autoResize": false,
@@ -11143,8 +11143,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 808,
- "top": 274,
+ "left": 897,
+ "top": 292,
"width": 0,
"height": 13,
"autoResize": false,
@@ -11176,8 +11176,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 798,
- "top": 283,
+ "left": 889,
+ "top": 303,
"width": 0,
"height": 13,
"autoResize": false,
@@ -11209,8 +11209,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 830,
- "top": 257,
+ "left": 912,
+ "top": 269,
"width": 0,
"height": 13,
"autoResize": false,
@@ -11242,8 +11242,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 800,
- "top": 267,
+ "left": 833,
+ "top": 263,
"width": 0,
"height": 13,
"autoResize": false,
@@ -11275,8 +11275,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 793,
- "top": 278,
+ "left": 829,
+ "top": 276,
"width": 0,
"height": 13,
"autoResize": false,
@@ -11308,8 +11308,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 812,
- "top": 244,
+ "left": 837,
+ "top": 236,
"width": 7,
"height": 13,
"autoResize": false,
@@ -11389,7 +11389,7 @@
"$ref": "AAAAAAFXjMG1TqVyU1Q="
},
"lineStyle": 1,
- "points": "838:287;791:245",
+ "points": "927:296;816:245",
"stereotypeDisplay": "label",
"showVisibility": true,
"showProperty": true,
@@ -12010,8 +12010,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 845,
- "top": 137,
+ "left": 870,
+ "top": 119,
"width": 0,
"height": 13,
"autoResize": false,
@@ -12043,8 +12043,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 845,
- "top": 152,
+ "left": 871,
+ "top": 134,
"width": 0,
"height": 13,
"autoResize": false,
@@ -12076,8 +12076,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 846,
- "top": 108,
+ "left": 869,
+ "top": 90,
"width": 0,
"height": 13,
"autoResize": false,
@@ -12108,7 +12108,7 @@
"$ref": "AAAAAAFQaTmd98O2VPc="
},
"lineStyle": 1,
- "points": "951:133;742:126",
+ "points": "999:104;742:119",
"stereotypeDisplay": "label",
"showVisibility": true,
"showProperty": true,
@@ -12157,8 +12157,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -80,
- "top": 32,
+ "left": -144,
+ "top": 16,
"width": 0,
"height": 13,
"autoResize": false,
@@ -12181,8 +12181,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 917,
- "top": 47,
+ "left": 885,
+ "top": 39,
"width": 80,
"height": 13,
"autoResize": false,
@@ -12206,8 +12206,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -80,
- "top": 32,
+ "left": -144,
+ "top": 16,
"width": 79,
"height": 13,
"autoResize": false,
@@ -12231,8 +12231,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -80,
- "top": 32,
+ "left": -144,
+ "top": 16,
"width": 0,
"height": 13,
"autoResize": false,
@@ -12250,8 +12250,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 912,
- "top": 40,
+ "left": 880,
+ "top": 32,
"width": 90,
"height": 25,
"autoResize": false,
@@ -12286,8 +12286,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 912,
- "top": 65,
+ "left": 880,
+ "top": 57,
"width": 90,
"height": 10,
"autoResize": false
@@ -12310,8 +12310,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 912,
- "top": 75,
+ "left": 880,
+ "top": 67,
"width": 90,
"height": 10,
"autoResize": false
@@ -12334,8 +12334,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -40,
- "top": 16,
+ "left": -72,
+ "top": 8,
"width": 10,
"height": 10,
"autoResize": false
@@ -12358,8 +12358,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -40,
- "top": 16,
+ "left": -72,
+ "top": 8,
"width": 10,
"height": 10,
"autoResize": false
@@ -12374,8 +12374,8 @@
"showShadow": true,
"containerChangeable": true,
"containerExtending": false,
- "left": 912,
- "top": 40,
+ "left": 880,
+ "top": 32,
"width": 90,
"height": 45,
"autoResize": false,
@@ -12441,8 +12441,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 64,
- "top": -16,
+ "left": -32,
+ "top": -32,
"width": 0,
"height": 13,
"autoResize": false,
@@ -12465,8 +12465,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 821,
- "top": 23,
+ "left": 773,
+ "top": 15,
"width": 59,
"height": 13,
"autoResize": false,
@@ -12490,8 +12490,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 64,
- "top": -16,
+ "left": -32,
+ "top": -32,
"width": 79,
"height": 13,
"autoResize": false,
@@ -12515,8 +12515,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 64,
- "top": -16,
+ "left": -32,
+ "top": -32,
"width": 0,
"height": 13,
"autoResize": false,
@@ -12534,8 +12534,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 816,
- "top": 16,
+ "left": 768,
+ "top": 8,
"width": 69,
"height": 25,
"autoResize": false,
@@ -12570,8 +12570,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 816,
- "top": 41,
+ "left": 768,
+ "top": 33,
"width": 69,
"height": 10,
"autoResize": false
@@ -12594,8 +12594,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 816,
- "top": 51,
+ "left": 768,
+ "top": 43,
"width": 69,
"height": 10,
"autoResize": false
@@ -12618,8 +12618,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 32,
- "top": -8,
+ "left": -16,
+ "top": -16,
"width": 10,
"height": 10,
"autoResize": false
@@ -12642,8 +12642,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 32,
- "top": -8,
+ "left": -16,
+ "top": -16,
"width": 10,
"height": 10,
"autoResize": false
@@ -12658,8 +12658,8 @@
"showShadow": true,
"containerChangeable": true,
"containerExtending": false,
- "left": 816,
- "top": 16,
+ "left": 768,
+ "top": 8,
"width": 69,
"height": 45,
"autoResize": false,
@@ -12718,8 +12718,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 829,
- "top": 97,
+ "left": 814,
+ "top": 92,
"width": 0,
"height": 13,
"autoResize": false,
@@ -12751,8 +12751,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 832,
- "top": 112,
+ "left": 818,
+ "top": 106,
"width": 0,
"height": 13,
"autoResize": false,
@@ -12784,8 +12784,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 822,
- "top": 68,
+ "left": 805,
+ "top": 63,
"width": 0,
"height": 13,
"autoResize": false,
@@ -12816,7 +12816,7 @@
"$ref": "AAAAAAFXjOJ+JhMrZaY="
},
"lineStyle": 1,
- "points": "911:71;742:107",
+ "points": "879:66;742:103",
"stereotypeDisplay": "label",
"showVisibility": true,
"showProperty": true,
@@ -12858,8 +12858,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 784,
- "top": 78,
+ "left": 757,
+ "top": 72,
"width": 0,
"height": 13,
"autoResize": false,
@@ -12891,8 +12891,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 790,
- "top": 92,
+ "left": 765,
+ "top": 84,
"width": 0,
"height": 13,
"autoResize": false,
@@ -12924,8 +12924,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 771,
- "top": 51,
+ "left": 740,
+ "top": 47,
"width": 0,
"height": 13,
"autoResize": false,
@@ -12956,7 +12956,7 @@
"$ref": "AAAAAAFXjOMFpRnaNbk="
},
"lineStyle": 1,
- "points": "815:54;742:88",
+ "points": "768:53;730:79",
"stereotypeDisplay": "label",
"showVisibility": true,
"showProperty": true,
@@ -12998,7 +12998,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 830,
+ "left": 902,
"top": 201,
"width": 94,
"height": 13,
@@ -13032,7 +13032,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 877,
+ "left": 949,
"top": 186,
"width": 0,
"height": 13,
@@ -13065,7 +13065,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 877,
+ "left": 949,
"top": 231,
"width": 0,
"height": 13,
@@ -13197,7 +13197,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 901,
+ "left": 1045,
"top": 201,
"width": 0,
"height": 13,
@@ -13230,7 +13230,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 898,
+ "left": 1042,
"top": 187,
"width": 0,
"height": 13,
@@ -13263,7 +13263,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 902,
+ "left": 1046,
"top": 228,
"width": 7,
"height": 13,
@@ -13344,7 +13344,7 @@
"$ref": "AAAAAAFXjMSYm8O1IEo="
},
"lineStyle": 1,
- "points": "827:222;927:222",
+ "points": "827:222;1071:222",
"stereotypeDisplay": "label",
"showVisibility": true,
"showProperty": true,
@@ -13419,7 +13419,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -1178,
+ "left": -1194,
"top": 1546,
"width": 0,
"height": 13,
@@ -13443,7 +13443,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 309,
+ "left": 301,
"top": 1399,
"width": 86,
"height": 13,
@@ -13468,7 +13468,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -1178,
+ "left": -1194,
"top": 1546,
"width": 79,
"height": 13,
@@ -13493,7 +13493,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -1178,
+ "left": -1194,
"top": 1546,
"width": 0,
"height": 13,
@@ -13512,7 +13512,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 304,
+ "left": 296,
"top": 1392,
"width": 96,
"height": 25,
@@ -13548,7 +13548,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 304,
+ "left": 296,
"top": 1417,
"width": 96,
"height": 10,
@@ -13572,7 +13572,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 304,
+ "left": 296,
"top": 1427,
"width": 96,
"height": 10,
@@ -13596,7 +13596,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -589,
+ "left": -597,
"top": 773,
"width": 10,
"height": 10,
@@ -13620,7 +13620,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -589,
+ "left": -597,
"top": 773,
"width": 10,
"height": 10,
@@ -13636,7 +13636,7 @@
"showShadow": true,
"containerChangeable": true,
"containerExtending": false,
- "left": 304,
+ "left": 296,
"top": 1392,
"width": 96,
"height": 45,
@@ -13980,8 +13980,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 231,
- "top": 1447,
+ "left": 226,
+ "top": 1451,
"width": 110,
"height": 13,
"autoResize": false,
@@ -14014,8 +14014,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 375,
- "top": 1465,
+ "left": 371,
+ "top": 1463,
"width": 0,
"height": 13,
"autoResize": false,
@@ -14047,8 +14047,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 331,
- "top": 1463,
+ "left": 327,
+ "top": 1464,
"width": 0,
"height": 13,
"autoResize": false,
@@ -14080,8 +14080,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 361,
- "top": 1458,
+ "left": 357,
+ "top": 1457,
"width": 0,
"height": 13,
"autoResize": false,
@@ -14113,8 +14113,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 375,
- "top": 1461,
+ "left": 370,
+ "top": 1459,
"width": 0,
"height": 13,
"autoResize": false,
@@ -14146,8 +14146,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 334,
- "top": 1451,
+ "left": 330,
+ "top": 1452,
"width": 0,
"height": 13,
"autoResize": false,
@@ -14179,8 +14179,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 360,
- "top": 1472,
+ "left": 357,
+ "top": 1471,
"width": 0,
"height": 13,
"autoResize": false,
@@ -14212,8 +14212,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 374,
- "top": 1470,
+ "left": 370,
+ "top": 1469,
"width": 0,
"height": 13,
"autoResize": false,
@@ -14245,8 +14245,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 330,
- "top": 1474,
+ "left": 326,
+ "top": 1475,
"width": 7,
"height": 13,
"autoResize": false,
@@ -14326,7 +14326,7 @@
"$ref": "AAAAAAFXw/4ZwJHrscU="
},
"lineStyle": 1,
- "points": "349:1437;344:1503",
+ "points": "343:1437;342:1503",
"stereotypeDisplay": "label",
"showVisibility": true,
"showProperty": true,
@@ -15580,8 +15580,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -144,
- "top": 368,
+ "left": -160,
+ "top": 352,
"width": 0,
"height": 13,
"autoResize": false,
@@ -15604,8 +15604,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 293,
- "top": 1295,
+ "left": 285,
+ "top": 1287,
"width": 120,
"height": 13,
"autoResize": false,
@@ -15629,8 +15629,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -144,
- "top": 368,
+ "left": -160,
+ "top": 352,
"width": 79,
"height": 13,
"autoResize": false,
@@ -15654,8 +15654,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -144,
- "top": 368,
+ "left": -160,
+ "top": 352,
"width": 0,
"height": 13,
"autoResize": false,
@@ -15673,8 +15673,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 288,
- "top": 1288,
+ "left": 280,
+ "top": 1280,
"width": 130,
"height": 25,
"autoResize": false,
@@ -15709,8 +15709,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 288,
- "top": 1313,
+ "left": 280,
+ "top": 1305,
"width": 130,
"height": 10,
"autoResize": false
@@ -15733,8 +15733,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 288,
- "top": 1323,
+ "left": 280,
+ "top": 1315,
"width": 130,
"height": 10,
"autoResize": false
@@ -15757,8 +15757,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -72,
- "top": 184,
+ "left": -80,
+ "top": 176,
"width": 10,
"height": 10,
"autoResize": false
@@ -15781,8 +15781,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": -72,
- "top": 184,
+ "left": -80,
+ "top": 176,
"width": 10,
"height": 10,
"autoResize": false
@@ -15797,8 +15797,8 @@
"showShadow": true,
"containerChangeable": true,
"containerExtending": false,
- "left": 288,
- "top": 1288,
+ "left": 280,
+ "top": 1280,
"width": 130,
"height": 45,
"autoResize": false,
@@ -15857,8 +15857,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 336,
- "top": 1355,
+ "left": 328,
+ "top": 1351,
"width": 0,
"height": 13,
"autoResize": false,
@@ -15890,8 +15890,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 321,
- "top": 1354,
+ "left": 313,
+ "top": 1351,
"width": 0,
"height": 13,
"autoResize": false,
@@ -15923,8 +15923,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 365,
- "top": 1356,
+ "left": 357,
+ "top": 1352,
"width": 0,
"height": 13,
"autoResize": false,
@@ -15955,7 +15955,7 @@
"$ref": "AAAAAAFXw/4ZwJHrscU="
},
"lineStyle": 1,
- "points": "351:1391;352:1333",
+ "points": "343:1391;344:1325",
"stereotypeDisplay": "label",
"showVisibility": true,
"showProperty": true,
@@ -15997,8 +15997,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 429,
- "top": 1367,
+ "left": 425,
+ "top": 1363,
"width": 89,
"height": 13,
"autoResize": false,
@@ -16031,8 +16031,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 481,
- "top": 1355,
+ "left": 477,
+ "top": 1351,
"width": 0,
"height": 13,
"autoResize": false,
@@ -16064,8 +16064,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 456,
- "top": 1392,
+ "left": 452,
+ "top": 1388,
"width": 0,
"height": 13,
"autoResize": false,
@@ -16097,8 +16097,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 415,
- "top": 1329,
+ "left": 407,
+ "top": 1321,
"width": 0,
"height": 13,
"autoResize": false,
@@ -16130,8 +16130,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 425,
- "top": 1319,
+ "left": 417,
+ "top": 1311,
"width": 0,
"height": 13,
"autoResize": false,
@@ -16163,8 +16163,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 397,
- "top": 1349,
+ "left": 388,
+ "top": 1341,
"width": 0,
"height": 13,
"autoResize": false,
@@ -16196,8 +16196,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 530,
- "top": 1406,
+ "left": 531,
+ "top": 1405,
"width": 0,
"height": 13,
"autoResize": false,
@@ -16229,7 +16229,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 536,
+ "left": 537,
"top": 1393,
"width": 0,
"height": 13,
@@ -16262,7 +16262,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 516,
+ "left": 517,
"top": 1431,
"width": 7,
"height": 13,
@@ -16343,7 +16343,7 @@
"$ref": "AAAAAAFXxAPmj8P8CCk="
},
"lineStyle": 1,
- "points": "386:1333;544:1439",
+ "points": "378:1325;545:1439",
"stereotypeDisplay": "label",
"showVisibility": true,
"showProperty": true,
@@ -16695,8 +16695,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 363,
- "top": 1211,
+ "left": 359,
+ "top": 1208,
"width": 0,
"height": 13,
"autoResize": false,
@@ -16728,8 +16728,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 378,
- "top": 1211,
+ "left": 374,
+ "top": 1208,
"width": 0,
"height": 13,
"autoResize": false,
@@ -16761,8 +16761,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 334,
- "top": 1212,
+ "left": 330,
+ "top": 1207,
"width": 0,
"height": 13,
"autoResize": false,
@@ -16794,8 +16794,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 363,
- "top": 1168,
+ "left": 361,
+ "top": 1169,
"width": 0,
"height": 13,
"autoResize": false,
@@ -16827,8 +16827,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 376,
- "top": 1170,
+ "left": 374,
+ "top": 1171,
"width": 0,
"height": 13,
"autoResize": false,
@@ -16860,7 +16860,7 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 335,
+ "left": 334,
"top": 1164,
"width": 0,
"height": 13,
@@ -16893,8 +16893,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 365,
- "top": 1254,
+ "left": 359,
+ "top": 1247,
"width": 0,
"height": 13,
"autoResize": false,
@@ -16926,8 +16926,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 378,
- "top": 1252,
+ "left": 372,
+ "top": 1245,
"width": 0,
"height": 13,
"autoResize": false,
@@ -16959,8 +16959,8 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 335,
- "top": 1259,
+ "left": 329,
+ "top": 1251,
"width": 7,
"height": 13,
"autoResize": false,
@@ -17040,7 +17040,7 @@
"$ref": "AAAAAAFXxAW+Ru8WA+c="
},
"lineStyle": 1,
- "points": "348:1149;351:1287",
+ "points": "347:1149;344:1279",
"stereotypeDisplay": "label",
"showVisibility": true,
"showProperty": true,
@@ -23564,13 +23564,13 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 815,
+ "left": 807,
"top": 1064,
"width": 92,
"height": 13,
"autoResize": false,
- "alpha": 1.4876554296766327,
- "distance": 33.94112549695428,
+ "alpha": 1.345758316739122,
+ "distance": 40,
"hostEdge": {
"$ref": "AAAAAAFXxBJxTW+wWD0="
},
@@ -23829,13 +23829,13 @@
"showShadow": true,
"containerChangeable": false,
"containerExtending": false,
- "left": 867,
- "top": 1011,
+ "left": 840,
+ "top": 1024,
"width": 7,
"height": 13,
"autoResize": false,
- "alpha": 0.5235987755982988,
- "distance": 25,
+ "alpha": -1.0432110870426592,
+ "distance": 17.26267650163207,
"hostEdge": {
"$ref": "AAAAAAFXxBJxTW+wWD0="
},
@@ -24810,6 +24810,98 @@
"autoResize": false,
"text": "For SpectrumVis",
"wordWrap": true
+ },
+ {
+ "_type": "UMLNoteView",
+ "_id": "AAAAAAFXx9ZWlTGaZu8=",
+ "_parent": {
+ "$ref": "AAAAAAFQXc4WXpjqsR0="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 168,
+ "top": 488,
+ "width": 153,
+ "height": 38,
+ "autoResize": false,
+ "text": "FileSource does not use this sample FIFO",
+ "wordWrap": true
+ },
+ {
+ "_type": "UMLNoteView",
+ "_id": "AAAAAAFXx9brl7q0gqY=",
+ "_parent": {
+ "$ref": "AAAAAAFQXc4WXpjqsR0="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 160,
+ "top": 1336,
+ "width": 153,
+ "height": 38,
+ "autoResize": false,
+ "text": "FileSink does not use this sample FIFO",
+ "wordWrap": true
+ },
+ {
+ "_type": "UMLNoteView",
+ "_id": "AAAAAAFXx9ppa4k9S9w=",
+ "_parent": {
+ "$ref": "AAAAAAFQXc4WXpjqsR0="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 296,
+ "top": 752,
+ "width": 153,
+ "height": 90,
+ "autoResize": false,
+ "text": "Does the downsampling from device FIFO to baseband FIFO. FileSource feeds baseband directly",
+ "wordWrap": true
+ },
+ {
+ "_type": "UMLNoteView",
+ "_id": "AAAAAAFXx9r9orq1yQI=",
+ "_parent": {
+ "$ref": "AAAAAAFQXc4WXpjqsR0="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 272,
+ "top": 1560,
+ "width": 153,
+ "height": 77,
+ "autoResize": false,
+ "text": "Does the upsampling from baseband FIFO to device FIFO. FileSink pulls from baseband FIFO directly",
+ "wordWrap": true
}
]
},
diff --git a/sdrbase/dsp/basebandsamplesource.h b/sdrbase/dsp/basebandsamplesource.h
index 67a2ada89..841697131 100644
--- a/sdrbase/dsp/basebandsamplesource.h
+++ b/sdrbase/dsp/basebandsamplesource.h
@@ -33,7 +33,7 @@ public:
virtual void start() = 0;
virtual void stop() = 0;
- virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly) = 0;
+ virtual void pull(Sample& sample) = 0;
virtual bool handleMessage(const Message& cmd) = 0; //!< Processing of a message. Returns true if message has actually been processed
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication
diff --git a/sdrbase/dsp/devicesamplesink.cpp b/sdrbase/dsp/devicesamplesink.cpp
index bce0e189c..b574c589d 100644
--- a/sdrbase/dsp/devicesamplesink.cpp
+++ b/sdrbase/dsp/devicesamplesink.cpp
@@ -18,7 +18,7 @@
#include "dsp/devicesamplesink.h"
DeviceSampleSink::DeviceSampleSink() :
- m_sampleSourceFifo(1<<19, 1<<16)
+ m_sampleSourceFifo(1<<19, 1<<17)
{
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
}
diff --git a/sdrbase/dsp/downchannelizer.cpp b/sdrbase/dsp/downchannelizer.cpp
index 83f30a90a..d2452c98f 100644
--- a/sdrbase/dsp/downchannelizer.cpp
+++ b/sdrbase/dsp/downchannelizer.cpp
@@ -1,3 +1,20 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 F4EXB //
+// written by Edouard Griffiths //
+// //
+// 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 . //
+///////////////////////////////////////////////////////////////////////////////////
+
#include
#include "dsp/inthalfbandfilter.h"
#include "dsp/dspcommands.h"
diff --git a/sdrbase/dsp/downchannelizer.h b/sdrbase/dsp/downchannelizer.h
index 9eb233078..3979a14b7 100644
--- a/sdrbase/dsp/downchannelizer.h
+++ b/sdrbase/dsp/downchannelizer.h
@@ -1,5 +1,22 @@
-#ifndef INCLUDE_CHANNELIZER_H
-#define INCLUDE_CHANNELIZER_H
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 F4EXB //
+// written by Edouard Griffiths //
+// //
+// 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 . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SDRBASE_DSP_DOWNCHANNELIZER_H
+#define SDRBASE_DSP_DOWNCHANNELIZER_H
#include
#include
@@ -64,7 +81,7 @@ protected:
};
typedef std::list FilterStages;
FilterStages m_filterStages;
- BasebandSampleSink* m_sampleSink;
+ BasebandSampleSink* m_sampleSink; //!< Demodulator
int m_inputSampleRate;
int m_requestedOutputSampleRate;
int m_requestedCenterFrequency;
@@ -82,4 +99,4 @@ signals:
void inputSampleRateChanged();
};
-#endif // INCLUDE_CHANNELIZER_H
+#endif // SDRBASE_DSP_DOWNCHANNELIZER_H
diff --git a/sdrbase/dsp/inthalfbandfilter.h b/sdrbase/dsp/inthalfbandfilter.h
index 25a9ff3b6..64ccd9bcc 100644
--- a/sdrbase/dsp/inthalfbandfilter.h
+++ b/sdrbase/dsp/inthalfbandfilter.h
@@ -51,6 +51,47 @@ public:
}
}
+ // upsample by 2, return center part of original spectrum
+ bool workInterpolateCenter(Sample* sampleIn, Sample *SampleOut)
+ {
+ switch(m_state)
+ {
+ case 0:
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = 0;
+ m_samples[m_ptr][1] = 0;
+
+ // save result
+ doFIR(SampleOut);
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER) % (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 1;
+
+ // tell caller we didn't consume the sample
+ return false;
+
+ default:
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = sampleIn->real();
+ m_samples[m_ptr][1] = sampleIn->imag();
+
+ // save result
+ doFIR(SampleOut);
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER) % (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 0;
+
+ // tell caller we consumed the sample
+ return true;
+ }
+ }
+
bool workDecimateCenter(qint32 *x, qint32 *y)
{
// insert sample into ring-buffer
@@ -84,43 +125,43 @@ public:
}
}
- // downsample by 2, return edges of spectrum rotated into center
- bool workDecimateFullRotate(Sample* sample)
- {
- switch(m_state)
- {
- case 0:
- // insert sample into ring-buffer
- m_samples[m_ptr][0] = sample->real();
- m_samples[m_ptr][1] = sample->imag();
-
- // advance write-pointer
- m_ptr = (m_ptr + HB_FILTERORDER) % (HB_FILTERORDER + 1);
-
- // next state
- m_state = 1;
-
- // tell caller we don't have a new sample
- return false;
-
- default:
- // insert sample into ring-buffer
- m_samples[m_ptr][0] = -sample->real();
- m_samples[m_ptr][1] = sample->imag();
-
- // save result
- doFIR(sample);
-
- // advance write-pointer
- m_ptr = (m_ptr + HB_FILTERORDER) % (HB_FILTERORDER + 1);
-
- // next state
- m_state = 0;
-
- // tell caller we have a new sample
- return true;
- }
- }
+ // downsample by 2, return edges of spectrum rotated into center - unused
+// bool workDecimateFullRotate(Sample* sample)
+// {
+// switch(m_state)
+// {
+// case 0:
+// // insert sample into ring-buffer
+// m_samples[m_ptr][0] = sample->real();
+// m_samples[m_ptr][1] = sample->imag();
+//
+// // advance write-pointer
+// m_ptr = (m_ptr + HB_FILTERORDER) % (HB_FILTERORDER + 1);
+//
+// // next state
+// m_state = 1;
+//
+// // tell caller we don't have a new sample
+// return false;
+//
+// default:
+// // insert sample into ring-buffer
+// m_samples[m_ptr][0] = -sample->real();
+// m_samples[m_ptr][1] = sample->imag();
+//
+// // save result
+// doFIR(sample);
+//
+// // advance write-pointer
+// m_ptr = (m_ptr + HB_FILTERORDER) % (HB_FILTERORDER + 1);
+//
+// // next state
+// m_state = 0;
+//
+// // tell caller we have a new sample
+// return true;
+// }
+// }
// downsample by 2, return lower half of original spectrum
bool workDecimateLowerHalf(Sample* sample)
@@ -191,6 +232,81 @@ public:
}
}
+ // upsample by 2, from lower half of original spectrum
+ bool workInterpolateLowerHalf(Sample* sampleIn, Sample *sampleOut)
+ {
+ switch(m_state)
+ {
+ case 0:
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = 0;
+ m_samples[m_ptr][1] = 0;
+
+ // save result
+ doFIR(sampleOut);
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER) % (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 1;
+
+ // tell caller we didn't consume the sample
+ return false;
+
+ case 1:
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = -sampleIn->real();
+ m_samples[m_ptr][1] = -sampleIn->imag();
+
+ // save result
+ doFIR(sampleOut);
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER) % (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 2;
+
+ // tell caller we consumed the sample
+ return true;
+
+ case 2:
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = 0;
+ m_samples[m_ptr][1] = 0;
+
+ // save result
+ doFIR(sampleOut);
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER) % (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 3;
+
+ // tell caller we didn't consume the sample
+ return false;
+
+ default:
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = sampleIn->real();
+ m_samples[m_ptr][1] = sampleIn->imag();
+
+ // save result
+ doFIR(sampleOut);
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER) % (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 0;
+
+ // tell caller we consumed the sample
+ return true;
+ }
+ }
+
// downsample by 2, return upper half of original spectrum
bool workDecimateUpperHalf(Sample* sample)
{
@@ -260,7 +376,82 @@ public:
}
}
- void myDecimate(const Sample* sample1, Sample* sample2)
+ // upsample by 2, from upper half of original spectrum
+ bool workInterpolateUpperHalf(Sample* sampleIn, Sample *sampleOut)
+ {
+ switch(m_state)
+ {
+ case 0:
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = 0;
+ m_samples[m_ptr][1] = 0;
+
+ // save result
+ doFIR(sampleOut);
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER) % (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 1;
+
+ // tell caller we didn't consume the sample
+ return false;
+
+ case 1:
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = -sampleIn->real();
+ m_samples[m_ptr][1] = -sampleIn->imag();
+
+ // save result
+ doFIR(sampleOut);
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER) % (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 2;
+
+ // tell caller we consumed the sample
+ return true;
+
+ case 2:
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = 0;
+ m_samples[m_ptr][1] = 0;
+
+ // save result
+ doFIR(sampleOut);
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER) % (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 3;
+
+ // tell caller we didn't consume the sample
+ return false;
+
+ default:
+ // insert sample into ring-buffer
+ m_samples[m_ptr][0] = sampleIn->real();
+ m_samples[m_ptr][1] = sampleIn->imag();
+
+ // save result
+ doFIR(sampleOut);
+
+ // advance write-pointer
+ m_ptr = (m_ptr + HB_FILTERORDER) % (HB_FILTERORDER + 1);
+
+ // next state
+ m_state = 0;
+
+ // tell caller we consumed the sample
+ return true;
+ }
+ }
+
+ void myDecimate(const Sample* sample1, Sample* sample2)
{
static const qint16 mod33[38] = { 31,32,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,
20,21,22,23,24,25,26,27,28,29,30,31,32,0,1,2};
diff --git a/sdrbase/dsp/threadedbasebandsamplesource.cpp b/sdrbase/dsp/threadedbasebandsamplesource.cpp
new file mode 100644
index 000000000..efdb1ab49
--- /dev/null
+++ b/sdrbase/dsp/threadedbasebandsamplesource.cpp
@@ -0,0 +1,101 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 F4EXB //
+// written by Edouard Griffiths //
+// //
+// 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 . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+
+#include "dsp/threadedbasebandsamplesource.h"
+
+ThreadedBasebandSampleSourceFifo::ThreadedBasebandSampleSourceFifo(BasebandSampleSource* sampleSource) :
+ m_sampleSource(sampleSource),
+ m_sampleSourceFifo(1<<19, 1<<17)
+{
+ m_samplesChunkSize = m_sampleSourceFifo.getChunkSize();
+ connect(&m_sampleSourceFifo, SIGNAL(dataWrite()), this, SLOT(handleFifoData()));
+}
+
+ThreadedBasebandSampleSourceFifo::~ThreadedBasebandSampleSourceFifo()
+{
+}
+
+void ThreadedBasebandSampleSourceFifo::readFromFifo(SampleVector::iterator& beginRead, unsigned int nbSamples)
+{
+ m_sampleSourceFifo.read(beginRead, nbSamples);
+}
+
+void ThreadedBasebandSampleSourceFifo::handleFifoData()
+{
+ for (int i = 0; i < m_samplesChunkSize; i++)
+ {
+ SampleVector::iterator sampleIt;
+ m_sampleSourceFifo.getWriteIterator(sampleIt);
+ m_sampleSource->pull(*sampleIt);
+ m_sampleSourceFifo.bumpIndex();
+ }
+}
+
+ThreadedBasebandSampleSource::ThreadedBasebandSampleSource(BasebandSampleSource* sampleSource, QObject *parent) :
+ m_basebandSampleSource(sampleSource)
+{
+ QString name = "ThreadedBasebandSampleSource(" + m_basebandSampleSource->objectName() + ")";
+ setObjectName(name);
+
+ qDebug() << "ThreadedBasebandSampleSource::ThreadedBasebandSampleSource: " << name;
+
+ m_thread = new QThread(parent);
+ m_threadedBasebandSampleSourceFifo = new ThreadedBasebandSampleSourceFifo(m_basebandSampleSource);
+ m_basebandSampleSource->moveToThread(m_thread);
+ m_threadedBasebandSampleSourceFifo->moveToThread(m_thread);
+
+ qDebug() << "ThreadedBasebandSampleSource::ThreadedBasebandSampleSource: thread: " << thread() << " m_thread: " << m_thread;
+}
+
+ThreadedBasebandSampleSource::~ThreadedBasebandSampleSource()
+{
+ delete m_threadedBasebandSampleSourceFifo;
+ delete m_thread;
+}
+
+void ThreadedBasebandSampleSource::start()
+{
+ qDebug() << "ThreadedBasebandSampleSource::start";
+ m_thread->start();
+ m_basebandSampleSource->start();
+}
+
+void ThreadedBasebandSampleSource::stop()
+{
+ qDebug() << "ThreadedBasebandSampleSource::stop";
+ m_basebandSampleSource->stop();
+ m_thread->exit();
+ m_thread->wait();
+}
+
+void ThreadedBasebandSampleSource::pull(SampleVector::iterator& beginRead, unsigned int nbSamples)
+{
+ m_threadedBasebandSampleSourceFifo->readFromFifo(beginRead, nbSamples);
+}
+
+bool ThreadedBasebandSampleSource::handleSourceMessage(const Message& cmd)
+{
+ return m_basebandSampleSource->handleMessage(cmd);
+}
+
+QString ThreadedBasebandSampleSource::getSampleSourceObjectName() const
+{
+ return m_basebandSampleSource->objectName();
+}
diff --git a/sdrbase/dsp/threadedbasebandsamplesource.h b/sdrbase/dsp/threadedbasebandsamplesource.h
index 1310f8f61..7a00aa676 100644
--- a/sdrbase/dsp/threadedbasebandsamplesource.h
+++ b/sdrbase/dsp/threadedbasebandsamplesource.h
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////
-// Copyright (C) 2015 F4EXB //
+// Copyright (C) 2016 F4EXB //
// written by Edouard Griffiths //
// //
// This program is free software; you can redistribute it and/or modify //
@@ -36,15 +36,18 @@ class ThreadedBasebandSampleSourceFifo : public QObject {
Q_OBJECT
public:
- ThreadedBasebandSampleSourceFifo(BasebandSampleSource* sampleSource, std::size_t size = 1<<18);
+ ThreadedBasebandSampleSourceFifo(BasebandSampleSource* sampleSource);
~ThreadedBasebandSampleSourceFifo();
- void writeToFifo(SampleVector::const_iterator& begin, SampleVector::const_iterator& end);
+ void readFromFifo(SampleVector::iterator& beginRead, unsigned int nbSamples);
BasebandSampleSource* m_sampleSource;
SampleSourceFifo m_sampleSourceFifo;
public slots:
void handleFifoData();
+
+private:
+ unsigned int m_samplesChunkSize;
};
/**
@@ -58,21 +61,20 @@ public:
~ThreadedBasebandSampleSource();
const BasebandSampleSource *getSource() const { return m_basebandSampleSource; }
- MessageQueue* getInputMessageQueue() { return m_basebandSampleSource->getInputMessageQueue(); } //!< Return pointer to sample source's input message queue
+ MessageQueue* getInputMessageQueue() { return m_basebandSampleSource->getInputMessageQueue(); } //!< Return pointer to sample source's input message queue
MessageQueue* getOutputMessageQueue() { return m_basebandSampleSource->getOutputMessageQueue(); } //!< Return pointer to sample source's output message queue
void start(); //!< this thread start()
void stop(); //!< this thread exit() and wait()
- bool handleSourceMessage(const Message& cmd); //!< Send message to source synchronously
- void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly); //!< Feed source with samples
+ bool handleSourceMessage(const Message& cmd); //!< Send message to source synchronously
+ void pull(SampleVector::iterator& beginRead, unsigned int nbSamples); //!< Pull samples from source
QString getSampleSourceObjectName() const;
protected:
-
QThread *m_thread; //!< The thead object
- ThreadedBasebandSampleSinkFifo *m_threadedBasebandSampleSourceFifo;
+ ThreadedBasebandSampleSourceFifo *m_threadedBasebandSampleSourceFifo;
BasebandSampleSource* m_basebandSampleSource;
};
diff --git a/sdrbase/dsp/upchannelizer.cpp b/sdrbase/dsp/upchannelizer.cpp
new file mode 100644
index 000000000..c56056e24
--- /dev/null
+++ b/sdrbase/dsp/upchannelizer.cpp
@@ -0,0 +1,259 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 F4EXB //
+// written by Edouard Griffiths //
+// //
+// 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 . //
+///////////////////////////////////////////////////////////////////////////////////
+
+
+#include
+#include "dsp/inthalfbandfilter.h"
+#include "dsp/dspcommands.h"
+
+#include
+#include
+
+MESSAGE_CLASS_DEFINITION(UpChannelizer::MsgChannelizerNotification, Message)
+
+UpChannelizer::UpChannelizer(BasebandSampleSource* sampleSource) :
+ m_sampleSource(sampleSource),
+ m_outputSampleRate(0),
+ m_requestedInputSampleRate(0),
+ m_requestedCenterFrequency(0),
+ m_currentInputSampleRate(0),
+ m_currentCenterFrequency(0)
+{
+ QString name = "UpChannelizer(" + m_sampleSource->objectName() + ")";
+ setObjectName(name);
+}
+
+UpChannelizer::~UpChannelizer()
+{
+ freeFilterChain();
+}
+
+void UpChannelizer::configure(MessageQueue* messageQueue, int sampleRate, int centerFrequency)
+{
+ Message* cmd = new DSPConfigureChannelizer(sampleRate, centerFrequency);
+ messageQueue->push(cmd);
+}
+
+void UpChannelizer::pull(Sample& sample)
+{
+ if(m_sampleSource == 0) {
+ m_sampleBuffer.clear();
+ return;
+ }
+
+ if (m_filterStages.size() == 0) // optimization when no downsampling is done anyway
+ {
+ m_sampleSource->pull(sample);
+ }
+ else
+ {
+ m_mutex.lock();
+
+ // TODO: handle multiple stages
+
+ FilterStages::iterator stage = m_filterStages.begin();
+
+ if ((*stage)->work(&m_sampleIn, &sample))
+ {
+ m_sampleSource->pull(m_sampleIn);
+ }
+
+ m_mutex.unlock();
+ }
+}
+
+void UpChannelizer::start()
+{
+ if (m_sampleSource != 0)
+ {
+ qDebug() << "UpChannelizer::start: thread: " << thread()
+ << " m_outputSampleRate: " << m_outputSampleRate
+ << " m_requestedInputSampleRate: " << m_requestedInputSampleRate
+ << " m_requestedCenterFrequency: " << m_requestedCenterFrequency;
+ m_sampleSource->start();
+ }
+}
+
+void UpChannelizer::stop()
+{
+ if(m_sampleSource != 0)
+ m_sampleSource->stop();
+}
+
+bool UpChannelizer::handleMessage(const Message& cmd)
+{
+ qDebug() << "UpChannelizer::handleMessage: " << cmd.getIdentifier();
+
+ // TODO: apply changes only if input sample rate or requested output sample rate change. Change of center frequency has no impact.
+
+ if (DSPSignalNotification::match(cmd))
+ {
+ DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
+ m_outputSampleRate = notif.getSampleRate();
+ qDebug() << "UpChannelizer::handleMessage: DSPSignalNotification: m_outputSampleRate: " << m_outputSampleRate;
+ applyConfiguration();
+
+ if (m_sampleSource != 0)
+ {
+ m_sampleSource->handleMessage(notif);
+ }
+
+ emit outputSampleRateChanged();
+ return true;
+ }
+ else if (DSPConfigureChannelizer::match(cmd))
+ {
+ DSPConfigureChannelizer& chan = (DSPConfigureChannelizer&) cmd;
+ m_requestedInputSampleRate = chan.getSampleRate();
+ m_requestedCenterFrequency = chan.getCenterFrequency();
+
+ qDebug() << "UpChannelizer::handleMessage: DSPConfigureChannelizer:"
+ << " m_requestedInputSampleRate: " << m_requestedInputSampleRate
+ << " m_requestedCenterFrequency: " << m_requestedCenterFrequency;
+
+ applyConfiguration();
+
+ return true;
+ }
+ else
+ {
+ if (m_sampleSource != 0)
+ {
+ return m_sampleSource->handleMessage(cmd);
+ }
+ else
+ {
+ return false;
+ }
+ }
+}
+
+void UpChannelizer::applyConfiguration()
+{
+ if (m_outputSampleRate == 0)
+ {
+ qDebug() << "UpChannelizer::applyConfiguration: m_outputSampleRate=0 aborting";
+ return;
+ }
+
+ m_mutex.lock();
+
+ freeFilterChain();
+
+ m_currentCenterFrequency = createFilterChain(
+ m_outputSampleRate / -2, m_outputSampleRate / 2,
+ m_requestedCenterFrequency - m_requestedInputSampleRate / 2, m_requestedCenterFrequency + m_requestedInputSampleRate / 2);
+
+ m_mutex.unlock();
+
+ m_currentInputSampleRate = m_outputSampleRate / (1 << m_filterStages.size());
+
+ qDebug() << "UpChannelizer::applyConfiguration in=" << m_outputSampleRate
+ << ", req=" << m_requestedInputSampleRate
+ << ", out=" << m_requestedInputSampleRate
+ << ", fc=" << m_currentCenterFrequency;
+
+ if (m_sampleSource != 0)
+ {
+ MsgChannelizerNotification notif(m_currentInputSampleRate, m_currentCenterFrequency);
+ m_sampleSource->handleMessage(notif);
+ }
+}
+
+UpChannelizer::FilterStage::FilterStage(Mode mode) :
+ m_filter(new IntHalfbandFilter),
+ m_workFunction(0)
+{
+ switch(mode) {
+ case ModeCenter:
+ m_workFunction = &IntHalfbandFilter::workInterpolateCenter;
+ break;
+
+ case ModeLowerHalf:
+ m_workFunction = &IntHalfbandFilter::workInterpolateLowerHalf;
+ break;
+
+ case ModeUpperHalf:
+ m_workFunction = &IntHalfbandFilter::workInterpolateUpperHalf;
+ break;
+ }
+}
+
+UpChannelizer::FilterStage::~FilterStage()
+{
+ delete m_filter;
+}
+
+bool UpChannelizer::signalContainsChannel(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) const
+{
+ //qDebug(" testing signal [%f, %f], channel [%f, %f]", sigStart, sigEnd, chanStart, chanEnd);
+ if(sigEnd <= sigStart)
+ return false;
+ if(chanEnd <= chanStart)
+ return false;
+ return (sigStart <= chanStart) && (sigEnd >= chanEnd);
+}
+
+Real UpChannelizer::createFilterChain(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd)
+{
+ Real sigBw = sigEnd - sigStart;
+ Real safetyMargin = sigBw / 20;
+ Real rot = sigBw / 4;
+
+ safetyMargin = 0;
+
+ //fprintf(stderr, "Channelizer::createFilterChain: ");
+ //fprintf(stderr, "Signal [%.1f, %.1f] (BW %.1f), Channel [%.1f, %.1f], Rot %.1f, Safety %.1f\n", sigStart, sigEnd, sigBw, chanStart, chanEnd, rot, safetyMargin);
+#if 1
+ // check if it fits into the left half
+ if(signalContainsChannel(sigStart + safetyMargin, sigStart + sigBw / 2.0 - safetyMargin, chanStart, chanEnd)) {
+ //fprintf(stderr, "-> take left half (rotate by +1/4 and decimate by 2)\n");
+ m_filterStages.push_back(new FilterStage(FilterStage::ModeLowerHalf));
+ return createFilterChain(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd);
+ }
+
+ // check if it fits into the right half
+ if(signalContainsChannel(sigEnd - sigBw / 2.0f + safetyMargin, sigEnd - safetyMargin, chanStart, chanEnd)) {
+ //fprintf(stderr, "-> take right half (rotate by -1/4 and decimate by 2)\n");
+ m_filterStages.push_back(new FilterStage(FilterStage::ModeUpperHalf));
+ return createFilterChain(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd);
+ }
+
+ // check if it fits into the center
+ // Was: if(signalContainsChannel(sigStart + rot + safetyMargin, sigStart + rot + sigBw / 2.0f - safetyMargin, chanStart, chanEnd)) {
+ if(signalContainsChannel(sigStart + rot + safetyMargin, sigEnd - rot - safetyMargin, chanStart, chanEnd)) {
+ //fprintf(stderr, "-> take center half (decimate by 2)\n");
+ m_filterStages.push_back(new FilterStage(FilterStage::ModeCenter));
+ // Was: return createFilterChain(sigStart + rot, sigStart + sigBw / 2.0f + rot, chanStart, chanEnd);
+ return createFilterChain(sigStart + rot, sigEnd - rot, chanStart, chanEnd);
+ }
+#endif
+ Real ofs = ((chanEnd - chanStart) / 2.0 + chanStart) - ((sigEnd - sigStart) / 2.0 + sigStart);
+ //fprintf(stderr, "-> complete (final BW %.1f, frequency offset %.1f)\n", sigBw, ofs);
+ return ofs;
+}
+
+void UpChannelizer::freeFilterChain()
+{
+ for(FilterStages::iterator it = m_filterStages.begin(); it != m_filterStages.end(); ++it)
+ delete *it;
+ m_filterStages.clear();
+}
+
+
+
+
diff --git a/sdrbase/dsp/upchannelizer.h b/sdrbase/dsp/upchannelizer.h
new file mode 100644
index 000000000..140f944fc
--- /dev/null
+++ b/sdrbase/dsp/upchannelizer.h
@@ -0,0 +1,103 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 F4EXB //
+// written by Edouard Griffiths //
+// //
+// 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 . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SDRBASE_DSP_UPCHANNELIZER_H_
+#define SDRBASE_DSP_UPCHANNELIZER_H_
+
+#include
+#include
+#include
+#include "util/export.h"
+#include "util/message.h"
+
+class MessageQueue;
+class IntHalfbandFilter;
+
+class SDRANGEL_API UpChannelizer : public BasebandSampleSource {
+ Q_OBJECT
+public:
+ class SDRANGEL_API MsgChannelizerNotification : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ MsgChannelizerNotification(int samplerate, qint64 frequencyOffset) :
+ Message(),
+ m_sampleRate(samplerate),
+ m_frequencyOffset(frequencyOffset)
+ { }
+
+ int getSampleRate() const { return m_sampleRate; }
+ qint64 getFrequencyOffset() const { return m_frequencyOffset; }
+
+ private:
+ int m_sampleRate;
+ qint64 m_frequencyOffset;
+ };
+
+ UpChannelizer(BasebandSampleSource* sampleSink);
+ virtual ~UpChannelizer();
+
+ void configure(MessageQueue* messageQueue, int sampleRate, int centerFrequency);
+ int getOutputSampleRate() const { return m_outputSampleRate; }
+
+ virtual void start();
+ virtual void stop();
+ virtual void pull(Sample& sample);
+ virtual bool handleMessage(const Message& cmd);
+
+protected:
+ struct FilterStage {
+ enum Mode {
+ ModeCenter,
+ ModeLowerHalf,
+ ModeUpperHalf
+ };
+
+ typedef bool (IntHalfbandFilter::*WorkFunction)(Sample* sIn, Sample *sOut);
+ IntHalfbandFilter* m_filter;
+ WorkFunction m_workFunction;
+
+ FilterStage(Mode mode);
+ ~FilterStage();
+
+ bool work(Sample* sampleIn, Sample *sampleOut)
+ {
+ return (m_filter->*m_workFunction)(sampleIn, sampleOut);
+ }
+ };
+ typedef std::list FilterStages;
+ FilterStages m_filterStages;
+ BasebandSampleSource* m_sampleSource; //!< Modulator
+ int m_outputSampleRate;
+ int m_requestedInputSampleRate;
+ int m_requestedCenterFrequency;
+ int m_currentInputSampleRate;
+ int m_currentCenterFrequency;
+ SampleVector m_sampleBuffer;
+ Sample m_sampleIn;
+ QMutex m_mutex;
+
+ void applyConfiguration();
+ bool signalContainsChannel(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) const;
+ Real createFilterChain(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd);
+ void freeFilterChain();
+
+signals:
+ void outputSampleRateChanged();
+};
+
+#endif /* SDRBASE_DSP_UPCHANNELIZER_H_ */
diff --git a/sdrbase/sdrbase.pro b/sdrbase/sdrbase.pro
index 503209fe9..941ce133b 100644
--- a/sdrbase/sdrbase.pro
+++ b/sdrbase/sdrbase.pro
@@ -34,6 +34,7 @@ SOURCES += mainwindow.cpp\
dsp/afsquelch.cpp\
dsp/agc.cpp\
dsp/downchannelizer.cpp\
+ dsp/upchannelizer.cpp\
dsp/channelmarker.cpp\
dsp/ctcssdetector.cpp\
dsp/dspcommands.cpp\
@@ -65,6 +66,7 @@ SOURCES += mainwindow.cpp\
dsp/scopevis.cpp\
dsp/spectrumvis.cpp\
dsp/threadedbasebandsamplesink.cpp\
+ dsp/threadedbasebandsamplesource.cpp\
gui/aboutdialog.cpp\
gui/addpresetdialog.cpp\
gui/basicchannelsettingswidget.cpp\
@@ -111,6 +113,7 @@ HEADERS += mainwindow.h\
device/devicesourceapi.h\
dsp/afsquelch.h\
dsp/downchannelizer.h\
+ dsp/upchannelizer.h\
dsp/channelmarker.h\
dsp/complex.h\
dsp/decimators.h\
@@ -149,6 +152,7 @@ HEADERS += mainwindow.h\
dsp/scopevis.h\
dsp/spectrumvis.h\
dsp/threadedbasebandsamplesink.h\
+ dsp/threadedbasebandsamplesource.h\
gui/aboutdialog.h\
gui/addpresetdialog.h\
gui/audiodialog.h\