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\