[hamradio-commits] [cubicsdr] 01/07: New upstream version 0.2.3+dfsg

Andreas E. Bombe aeb at moszumanska.debian.org
Thu Jan 25 01:57:48 UTC 2018


This is an automated email from the git hooks/post-receive script.

aeb pushed a commit to annotated tag debian/0.2.3+dfsg-1
in repository cubicsdr.

commit 5c6e0ed7f7b3b49af9d99b7cf0252ef6438ed789
Author: Andreas Bombe <aeb at debian.org>
Date:   Wed Jan 24 22:38:47 2018 +0100

    New upstream version 0.2.3+dfsg
---
 CMakeLists.txt                                   |  12 +-
 external/cubicvr2/math/mat3.h                    |  20 +-
 external/cubicvr2/math/mat4.h                    |  47 +-
 external/cubicvr2/math/transform.h               |  10 +-
 external/cubicvr2/math/vec2.h                    |  22 +-
 external/cubicvr2/math/vec3.h                    |  18 +-
 external/cubicvr2/math/vec4.h                    |  21 +-
 src/AppConfig.cpp                                |  93 ++++
 src/AppConfig.h                                  |  19 +
 src/AppFrame.cpp                                 | 623 +++++++++++++++++++----
 src/AppFrame.h                                   |  59 ++-
 src/BookmarkMgr.cpp                              | 119 +++--
 src/BookmarkMgr.h                                |  21 +-
 src/CubicSDR.cpp                                 | 180 ++++---
 src/CubicSDR.h                                   |  36 +-
 src/CubicSDRDefs.h                               |   4 +
 src/DemodLabelDialog.cpp                         |   2 +-
 src/DemodLabelDialog.h                           |   4 +-
 src/FrequencyDialog.cpp                          |   8 +-
 src/FrequencyDialog.h                            |   4 +-
 src/IOThread.cpp                                 |  18 +-
 src/IOThread.h                                   | 243 ++++-----
 src/ModemProperties.cpp                          |   2 +-
 src/ModemProperties.h                            |   5 +-
 src/audio/AudioFile.cpp                          |  50 ++
 src/audio/AudioFile.h                            |  25 +
 src/audio/AudioFileWAV.cpp                       | 219 ++++++++
 src/audio/AudioFileWAV.h                         |  42 ++
 src/audio/AudioSinkFileThread.cpp                | 140 +++++
 src/audio/AudioSinkFileThread.h                  |  50 ++
 src/audio/AudioSinkThread.cpp                    |  54 ++
 src/audio/AudioSinkThread.h                      |  25 +
 src/audio/AudioThread.cpp                        | 190 ++++---
 src/audio/AudioThread.h                          |  97 ++--
 src/demod/DemodDefs.h                            |  26 +-
 src/demod/DemodulatorInstance.cpp                | 211 ++++++--
 src/demod/DemodulatorInstance.h                  |  40 +-
 src/demod/DemodulatorMgr.cpp                     | 190 +++----
 src/demod/DemodulatorMgr.h                       |  54 +-
 src/demod/DemodulatorPreThread.cpp               |  60 +--
 src/demod/DemodulatorPreThread.h                 |  17 +-
 src/demod/DemodulatorThread.cpp                  | 159 +++---
 src/demod/DemodulatorThread.h                    |  32 +-
 src/demod/DemodulatorWorkerThread.cpp            |  23 +-
 src/demod/DemodulatorWorkerThread.h              |  17 +-
 src/forms/Bookmark/BookmarkPanel.cpp             | 226 ++++----
 src/forms/Bookmark/BookmarkPanel.h               |  96 ++--
 src/forms/Bookmark/BookmarkView.cpp              | 110 ++--
 src/forms/Bookmark/BookmarkView.h                |  12 +-
 src/forms/Dialog/AboutDialog.fbp                 | 415 +++++++++++++++
 src/forms/Dialog/AboutDialogBase.cpp             |  46 +-
 src/forms/Dialog/AboutDialogBase.h               |   9 +-
 src/forms/Dialog/ActionDialogBase.cpp            |  66 +--
 src/forms/Dialog/ActionDialogBase.h              |  40 +-
 src/forms/Dialog/PortSelectorDialogBase.cpp      | 112 ++--
 src/forms/Dialog/PortSelectorDialogBase.h        |  50 +-
 src/forms/DigitalConsole/DigitalConsoleFrame.cpp | 104 ++--
 src/forms/DigitalConsole/DigitalConsoleFrame.h   |  52 +-
 src/forms/SDRDevices/SDRDeviceAddForm.cpp        | 124 ++---
 src/forms/SDRDevices/SDRDeviceAddForm.h          |  48 +-
 src/forms/SDRDevices/SDRDevices.cpp              | 179 +++++--
 src/forms/SDRDevices/SDRDevicesForm.cpp          | 174 +++----
 src/forms/SDRDevices/SDRDevicesForm.h            |  76 +--
 src/modules/modem/Modem.h                        |   9 +-
 src/modules/modem/analog/ModemAM.cpp             |   4 +-
 src/modules/modem/analog/ModemDSB.cpp            |   2 +-
 src/modules/modem/analog/ModemFM.cpp             |   2 +-
 src/modules/modem/analog/ModemIQ.cpp             |   2 +-
 src/modules/modem/analog/ModemLSB.cpp            |   2 +-
 src/modules/modem/analog/ModemNBFM.cpp           |   2 +-
 src/modules/modem/analog/ModemUSB.cpp            |   2 +-
 src/panel/MeterPanel.cpp                         |   2 +-
 src/panel/MeterPanel.h                           |   4 +-
 src/panel/ScopePanel.cpp                         |  14 +-
 src/panel/SpectrumPanel.cpp                      |   4 +-
 src/panel/WaterfallPanel.cpp                     |   2 +-
 src/process/FFTDataDistributor.cpp               |  15 +-
 src/process/FFTVisualDataThread.cpp              |  22 +-
 src/process/FFTVisualDataThread.h                |   6 +-
 src/process/ScopeVisualProcessor.cpp             |  13 +-
 src/process/ScopeVisualProcessor.h               |  13 +-
 src/process/SpectrumVisualDataThread.cpp         |   4 +
 src/process/SpectrumVisualDataThread.h           |   2 +
 src/process/SpectrumVisualProcessor.cpp          | 192 ++++---
 src/process/SpectrumVisualProcessor.h            |  39 +-
 src/process/VisualProcessor.h                    | 167 +++---
 src/rig/RigThread.cpp                            |   4 +-
 src/sdr/SDRDeviceInfo.cpp                        |  94 +++-
 src/sdr/SDRDeviceInfo.h                          |   8 +
 src/sdr/SDREnumerator.cpp                        |  54 +-
 src/sdr/SDRPostThread.cpp                        | 219 ++++----
 src/sdr/SDRPostThread.h                          |  25 +-
 src/sdr/SoapySDRThread.cpp                       | 278 +++++++---
 src/sdr/SoapySDRThread.h                         |  32 +-
 src/ui/GLPanel.cpp                               |   4 +-
 src/ui/GLPanel.h                                 |   1 +
 src/util/GLFont.cpp                              |  16 +-
 src/util/ThreadBlockingQueue.h                   | 104 ++--
 src/util/ThreadQueue.cpp                         |   4 -
 src/util/ThreadQueue.h                           | 302 -----------
 src/util/Timer.cpp                               | 120 +++--
 src/util/Timer.h                                 |   4 +
 src/visual/GainCanvas.cpp                        | 112 +++-
 src/visual/GainCanvas.h                          |  10 +-
 src/visual/InteractiveCanvas.h                   |   2 +-
 src/visual/PrimaryGLContext.cpp                  |  61 ++-
 src/visual/PrimaryGLContext.h                    |   4 +-
 src/visual/ScopeCanvas.cpp                       |  19 +-
 src/visual/ScopeCanvas.h                         |   5 +-
 src/visual/SpectrumCanvas.cpp                    |  18 +-
 src/visual/SpectrumCanvas.h                      |   5 +-
 src/visual/TuningCanvas.cpp                      |  16 +-
 src/visual/WaterfallCanvas.cpp                   |  70 ++-
 src/visual/WaterfallCanvas.h                     |   7 +-
 114 files changed, 4828 insertions(+), 2544 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6a65c6b..d82e51a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,7 +6,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/")
 
 SET(CUBICSDR_VERSION_MAJOR "0")
 SET(CUBICSDR_VERSION_MINOR "2")
-SET(CUBICSDR_VERSION_PATCH "2")
+SET(CUBICSDR_VERSION_PATCH "3")
 SET(CUBICSDR_VERSION_SUFFIX "")
 SET(CUBICSDR_VERSION "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}${CUBICSDR_VERSION_SUFFIX}")
 
@@ -347,6 +347,10 @@ SET (cubicsdr_sources
     src/modules/modem/analog/ModemLSB.cpp
     src/modules/modem/analog/ModemUSB.cpp
     src/audio/AudioThread.cpp
+    src/audio/AudioSinkThread.cpp
+    src/audio/AudioSinkFileThread.cpp
+    src/audio/AudioFile.cpp
+    src/audio/AudioFileWAV.cpp
     src/util/Gradient.cpp
     src/util/Timer.cpp
     src/util/MouseTracker.cpp
@@ -451,6 +455,10 @@ SET (cubicsdr_headers
     src/modules/modem/analog/ModemLSB.h
     src/modules/modem/analog/ModemUSB.h
     src/audio/AudioThread.h
+    src/audio/AudioSinkThread.h
+    src/audio/AudioSinkFileThread.h
+    src/audio/AudioFile.h
+    src/audio/AudioFileWAV.h
     src/util/Gradient.h
     src/util/Timer.h
 	src/util/ThreadBlockingQueue.h
@@ -995,7 +1003,7 @@ IF (WIN32 AND BUILD_INSTALLER)
 
     IF (MSVC)
         install(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/external/msvc/${EX_PLATFORM_NAME}/vc_redist.${EX_PLATFORM_NAME}.exe DESTINATION vc_redist)
-        set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '\\\"$INSTDIR\\\\vc_redist\\\\vc_redist.${EX_PLATFORM_NAME}.exe\\\" /q:a'")
+        set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '\\\"$INSTDIR\\\\vc_redist\\\\vc_redist.${EX_PLATFORM_NAME}.exe\\\" /passive /norestart'")
     ENDIF (MSVC)
           
           
diff --git a/external/cubicvr2/math/mat3.h b/external/cubicvr2/math/mat3.h
index 8f5ab22..167d895 100644
--- a/external/cubicvr2/math/mat3.h
+++ b/external/cubicvr2/math/mat3.h
@@ -12,7 +12,7 @@
 #include <iostream>
 #include "vec3.h"
 #include <cstring>
-
+#include <stddef.h>
 namespace CubicVR {
 
     #define mat3SG(c,x,y) \
@@ -20,14 +20,20 @@ namespace CubicVR {
         c & COMBINE(set,x)(mat3 value) { y = value; return *this; }
 
     struct mat3 {
+       
         __float a,b,c,d,e,f,g,h,i;
-
-        //        __float  operator [] (unsigned i) const { return ((__float *)this)[i]; }
-#ifndef _WIN32
-        __float& operator [] (unsigned i)       { return ((__float *)this)[i]; }
-#endif
-        operator __float*() const { return (__float *)this; }
+      
+        //access as-array:
+        inline __float& operator [] (size_t i) {
+            __float* as_array = (__float*)this;
+            return (as_array[i]);
+        }
         
+        inline const __float& operator [] (size_t i) const { 
+            __float* as_array = (__float*)this;
+            return (as_array[i]);
+        }
+    
         mat3(__float ai,__float bi,__float ci,__float di,__float ei,__float fi,__float gi,__float hi,__float ii) {
             a = ai; b = bi; c = ci; d = di; e = ei; f = fi; g = gi; h = hi; i = ii;
         };
diff --git a/external/cubicvr2/math/mat4.h b/external/cubicvr2/math/mat4.h
index 2007535..75d1ec0 100644
--- a/external/cubicvr2/math/mat4.h
+++ b/external/cubicvr2/math/mat4.h
@@ -15,21 +15,35 @@
 #include "vec4.h"
 #include "mat3.h"
 #include <cmath>
+#include <stddef.h>
 
 namespace CubicVR {
     using namespace std;
     #define mat4SG(c,x,y) \
         mat4 COMBINE(get,x)() { return y; } \
         c & COMBINE(set,x)(mat4 value) { y = value; return *this; }
+
     struct mat4 {
-        __float a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p;
+      
+         //16 elements
+         __float a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p;
+      
+        //access as-array:
+        inline __float& operator [] (size_t i) {
+            __float* as_array = (__float*)this;
+            return (as_array[i]);
+        }
+
+        inline const __float& operator [] (size_t i) const {
+            __float* as_array = (__float*)this;
+            return (as_array[i]);
+        }
 
-        //        __float  operator [] (unsigned i) const { return ((__float *)this)[i]; }
-#ifndef _WIN32
-        __float& operator [] (unsigned i)       { return ((__float *)this)[i]; }
-#endif
+        //To be accessed by GL API directly, accessed by pointer.
+        //operator* overloading is way too dangerous, especially in ptr != NULL
+        //tests.
+       inline  __float* to_ptr() const { return (__float *)this; }
 
-        operator __float*() const { return (__float *)this; }
         mat4(__float ai,__float bi,__float ci,__float di,__float ei,__float fi,__float gi,__float hi,__float ii,__float ji,__float ki,__float li,__float mi,__float ni,__float oi,__float pi) {
             a = ai; b = bi; c = ci; d = di; e = ei; f = fi; g = gi; h = hi; i = ii; j = ji; k = ki; l = li; m = mi; n = ni; o = oi; p = pi;
         }
@@ -263,22 +277,19 @@ namespace CubicVR {
         static mat4 transform(vec3 position, vec3 rotation, vec3 scale) {
             mat4 m = mat4::identity();
             
-            if (position!=NULL) {
-                m *= mat4::translate(position[0],position[1],position[2]);
-            }
-            if (rotation!=NULL) {
-                if (!(rotation[0] == 0 && rotation[1] == 0 && rotation[2] == 0)) {
-                    m *= mat4::rotate(rotation[0],rotation[1],rotation[2]);
-                }
+            m *= mat4::translate(position[0],position[1],position[2]);
+          
+            if (!(rotation[0] == 0 && rotation[1] == 0 && rotation[2] == 0)) {
+                m *= mat4::rotate(rotation[0], rotation[1], rotation[2]);    
             }
-            if (scale!=NULL) {
-                if (!(scale[0] == 1 && scale[1] == 1 && scale[2] == 1)) {
-                    m *= mat4::scale(scale[0],scale[1],scale[2]);
-                }
+             
+            if (!(scale[0] == 1 && scale[1] == 1 && scale[2] == 1)) {
+                m *= mat4::scale(scale[0],scale[1],scale[2]);
             }
             
             return m;
         };
+
         static vec4 vec4_multiply(vec4 m1, mat4 m2) {
             vec4 mOut;
 
@@ -313,7 +324,7 @@ namespace CubicVR {
         };
         
         static vec3 unProject(mat4 pMatrix, mat4 mvMatrix, float width, float height, float winx, float winy, float /* winz */) {
-            vec4 p(((winx / width) * 2.0f) - 1.0, -(((winy / height) * 2.0f) - 1.0), 1.0, 1.0);
+            vec4 p(((winx / width) * 2.0f) - 1.0f, -(((winy / height) * 2.0f) - 1.0f), 1.0f, 1.0f);
             
             vec4 invp = mat4::vec4_multiply(mat4::vec4_multiply(p, mat4::inverse(pMatrix)), mat4::inverse(mvMatrix));
             
diff --git a/external/cubicvr2/math/transform.h b/external/cubicvr2/math/transform.h
index bd6ddde..9037128 100644
--- a/external/cubicvr2/math/transform.h
+++ b/external/cubicvr2/math/transform.h
@@ -73,7 +73,7 @@ namespace CubicVR {
         
         void pushMatrix(mat4 m) {
             c_stack++;
-            m_stack[c_stack] = (m ? m : getIdentity());
+            m_stack[c_stack] = m;
         }
         
         void popMatrix() {
@@ -88,14 +88,10 @@ namespace CubicVR {
             m_cache.clear();
             c_stack = 0;
             valid = 0;
-            delete result;
+
             result = mat4::identity();
             
-            if (init_mat != NULL) {
-                m_stack[0] = init_mat;
-            } else {
-                setIdentity();
-            }
+            m_stack[0] = init_mat; 
         }
         
         void translate(__float x, __float y, __float z) {
diff --git a/external/cubicvr2/math/vec2.h b/external/cubicvr2/math/vec2.h
index 24011c7..330f09d 100644
--- a/external/cubicvr2/math/vec2.h
+++ b/external/cubicvr2/math/vec2.h
@@ -12,6 +12,7 @@
 #include <iostream>
 #include <cmath>
 #include "cubic_types.h"
+#include <stddef.h>
 
 namespace CubicVR {
     #define vec2SG(c,x,y) \
@@ -20,20 +21,27 @@ namespace CubicVR {
 
     struct vec2 {
         __float x, y;
+
     public:
         __float& u() { return x; }
         __float& v() { return y; }
         
-//        __float  operator [] (unsigned i) const { return ((__float *)this)[i]; }
-#ifndef _WIN32
-		__float& operator [] (unsigned i)       { return ((__float *)this)[i]; }
-#endif        
+        //access as-array:
+        inline __float& operator [] (size_t i) {
+            __float* as_array = (__float*)this;
+            return (as_array[i]);
+        }
+
+        inline const __float& operator [] (size_t i) const {
+            __float* as_array = (__float*)this;
+            return (as_array[i]);
+        }
+
         vec2 (__float xi,__float yi) { x = xi; y = yi;  }
         vec2 () { x = y = 0.0f; }
-        
-        operator __float*() const { return (__float *)this; }
-        
+         
         vec2 operator*(__float v) { return vec2( x*v, y*v ); }
+
         //    vec2 operator*(vec2 v) { return vec2::cross(*this,v); }
         vec2 operator+(vec2 v) { return vec2::add(*this,v); }
         vec2 operator-(vec2 v) { return vec2::subtract(*this,v); }
diff --git a/external/cubicvr2/math/vec3.h b/external/cubicvr2/math/vec3.h
index 220bf60..33bc652 100644
--- a/external/cubicvr2/math/vec3.h
+++ b/external/cubicvr2/math/vec3.h
@@ -12,6 +12,7 @@
 #include <iostream>
 #include "cubic_types.h"
 #include <cmath>
+#include <stddef.h>
 
 namespace CubicVR {
     
@@ -23,19 +24,24 @@ namespace CubicVR {
     struct vec3 {
         __float x,y,z;
 
-        operator __float*() const { return (__float *)this; }
-
         __float& r() { return x; }
         __float& g() { return y; }
         __float& b() { return z; }
         
-#ifndef _WIN32
-        __float& operator [] (unsigned i)       { return ((__float *)this)[i]; }
-#endif
+        //access as-array:
+        inline __float& operator [] (size_t i) {
+            __float* as_array = (__float*)this;
+            return (as_array[i]);
+        }
+
+        inline const __float& operator [] (size_t i) const {
+            __float* as_array = (__float*)this;
+            return (as_array[i]);
+        }
+
         vec3 (__float xi,__float yi,__float zi) { x = xi; y = yi; z = zi; }
         vec3 () { x = y = z = 0.0f; }
         
-        
         vec3 operator*(__float v) { return vec3(x*v, y*v, z*v); }
         vec3 operator*(vec3 v) { return vec3::cross(*this,v); }
         vec3 operator+(vec3 v) { return vec3::add(*this,v); }
diff --git a/external/cubicvr2/math/vec4.h b/external/cubicvr2/math/vec4.h
index ad795c1..9983148 100644
--- a/external/cubicvr2/math/vec4.h
+++ b/external/cubicvr2/math/vec4.h
@@ -12,6 +12,7 @@
 #include <iostream>
 #include "cubic_types.h"
 #include <cmath>
+#include <stddef.h>
 
 namespace CubicVR {
 
@@ -20,23 +21,29 @@ namespace CubicVR {
     c & COMBINE(set,x)(vec3 value) { y = value; return *this; }
 
     struct vec4 {
-        __float x,y,z,w;
+
+        __float x, y, z, w;
+
     public:
         __float& r() { return x; }
         __float& g() { return y; }
         __float& b() { return z; }
         __float& a() { return w; }
         
-//        __float  operator [] (unsigned i) const { return ((__float *)this)[i]; }
-#ifndef _WIN32
-        __float& operator [] (unsigned i)       { return ((__float *)this)[i]; }
-#endif
+        //access as-array:
+        inline __float& operator [] (size_t i) {
+            __float* as_array = (__float*)this;
+            return (as_array[i]);
+        }
+
+        inline const __float& operator [] (size_t i) const {
+            __float* as_array = (__float*)this;
+            return (as_array[i]);
+        }
 
         vec4 (__float xi,__float yi,__float zi,__float wi) { x = xi; y = yi; z = zi; w = wi; }
         vec4 () { x = y = z = w =  0.0f; }
         
-        operator __float*() const { return (__float *)this; }
-        
         vec4 operator*(__float v) { return vec4(x*v, y*v, z*v, w*v); }
 //        vec4 operator*(vec4 v) { return vec4::cross(*this,v); }
 //        vec4 operator+(vec4 v) { return vec4::add(*this,v); }
diff --git a/src/AppConfig.cpp b/src/AppConfig.cpp
index 176838b..f85ab7c 100644
--- a/src/AppConfig.cpp
+++ b/src/AppConfig.cpp
@@ -4,6 +4,8 @@
 #include "AppConfig.h"
 #include "CubicSDR.h"
 
+#include <wx/msgdlg.h>
+
 DeviceConfig::DeviceConfig() : deviceId("") {
 	ppm.store(0);
 	offset.store(0);
@@ -39,6 +41,14 @@ long DeviceConfig::getSampleRate() {
     return sampleRate.load();
 }
 
+void DeviceConfig::setAntennaName(const std::string& name) {
+    antennaName = name;
+}
+
+const std::string& DeviceConfig::getAntennaName() {
+    return antennaName;
+}
+
 void DeviceConfig::setAGCMode(bool agcMode) {
     this->agcMode.store(agcMode);
 }
@@ -81,7 +91,9 @@ std::string DeviceConfig::getDeviceName() {
 }
 
 void DeviceConfig::save(DataNode *node) {
+
     std::lock_guard < std::mutex > lock(busy_lock);
+    
     *node->newChild("id") = deviceId;
     *node->newChild("name") = deviceName;
     *node->newChild("ppm") = ppm.load();
@@ -89,6 +101,10 @@ void DeviceConfig::save(DataNode *node) {
     *node->newChild("sample_rate") = sampleRate.load();
     *node->newChild("agc_mode") = agcMode.load()?1:0;
 
+    if (!antennaName.empty()) {
+        *node->newChild("antenna") = antennaName;
+    }
+
     if (streamOpts.size()) {
         DataNode *streamOptsNode = node->newChild("streamOpts");
         for (ConfigSettings::const_iterator opt_i = streamOpts.begin(); opt_i != streamOpts.end(); opt_i++) {
@@ -149,6 +165,12 @@ void DeviceConfig::load(DataNode *node) {
         sample_rate_node->element()->get(sampleRateValue);
         setSampleRate(sampleRateValue);
     }
+    if (node->hasAnother("antenna")) {
+        DataNode *antenna_node = node->getNext("antenna");
+        std::string antennaNameValue;
+        antenna_node->element()->get(antennaNameValue);
+        setAntennaName(antennaNameValue);
+    }
     if (node->hasAnother("streamOpts")) {
         DataNode *streamOptsNode = node->getNext("streamOpts");
         for (int i = 0, iMax = streamOptsNode->numChildren(); i<iMax; i++) {
@@ -485,6 +507,51 @@ bool AppConfig::getBookmarksVisible() {
     return bookmarksVisible.load();
 }
 
+void AppConfig::setRecordingPath(std::string recPath) {
+    recordingPath = recPath;
+}
+
+std::string AppConfig::getRecordingPath() {
+    return recordingPath;
+}
+
+bool AppConfig::verifyRecordingPath() {
+    string recPathStr = wxGetApp().getConfig()->getRecordingPath();
+    
+    if (recPathStr.empty()) {
+        wxMessageBox( wxT("Recording path is not set.  Please use 'Set Recording Path' from the 'File' Menu."), wxT("Recording Path Error"), wxICON_INFORMATION);
+        
+        return false;
+    }
+    
+    wxFileName recPath(recPathStr);
+    
+    if (!recPath.Exists() || !recPath.IsDirWritable()) {
+        wxMessageBox( wxT("Recording path does not exist or is not writable.  Please use 'Set Recording Path' from the 'File' Menu."), wxT("Recording Path Error"), wxICON_INFORMATION);
+        
+        return false;
+    }
+    
+    return true;
+}
+
+
+void  AppConfig::setRecordingSquelchOption(int enumChoice) {
+	recordingSquelchOption = enumChoice;
+}
+
+int  AppConfig::getRecordingSquelchOption() {
+	return recordingSquelchOption;
+}
+
+void  AppConfig::setRecordingFileTimeLimit(int nbSeconds) {
+	recordingFileTimeLimitSeconds = nbSeconds;
+}
+
+int  AppConfig::getRecordingFileTimeLimit() {
+	return recordingFileTimeLimitSeconds;
+}
+
 
 void AppConfig::setConfigName(std::string configName) {
     this->configName = configName;
@@ -539,6 +606,12 @@ bool AppConfig::save() {
         *window_node->newChild("bookmark_visible") = bookmarksVisible.load();
     }
     
+	//Recording settings:
+    DataNode *rec_node = cfg.rootNode()->newChild("recording");
+    *rec_node->newChild("path") = recordingPath;
+	*rec_node->newChild("squelch") = recordingSquelchOption;
+	*rec_node->newChild("file_time_limit") = recordingFileTimeLimitSeconds;
+    
     DataNode *devices_node = cfg.rootNode()->newChild("devices");
 
     std::map<std::string, DeviceConfig *>::iterator device_config_i;
@@ -721,6 +794,26 @@ bool AppConfig::load() {
         }
     }
     
+	//Recording settings:
+    if (cfg.rootNode()->hasAnother("recording")) {
+        DataNode *rec_node = cfg.rootNode()->getNext("recording");
+
+        if (rec_node->hasAnother("path")) {
+            DataNode *rec_path = rec_node->getNext("path");
+            recordingPath = rec_path->element()->toString();
+        }
+
+		if (rec_node->hasAnother("squelch")) {
+			DataNode *rec_squelch = rec_node->getNext("squelch");
+			rec_squelch->element()->get(recordingSquelchOption);
+		}
+
+		if (rec_node->hasAnother("file_time_limit")) {
+			DataNode *rec_file_time_limit = rec_node->getNext("file_time_limit");
+			rec_file_time_limit->element()->get(recordingFileTimeLimitSeconds);
+		}
+    }
+    
     if (cfg.rootNode()->hasAnother("devices")) {
         DataNode *devices_node = cfg.rootNode()->getNext("devices");
 
diff --git a/src/AppConfig.h b/src/AppConfig.h
index 5d78e78..c1fe392 100644
--- a/src/AppConfig.h
+++ b/src/AppConfig.h
@@ -31,6 +31,9 @@ public:
     void setSampleRate(long srate);
     long getSampleRate();
 
+    void setAntennaName(const std::string& name);
+    const std::string& getAntennaName();
+
     void setAGCMode(bool agcMode);
     bool getAGCMode();
     
@@ -64,12 +67,14 @@ public:
 private:
     std::string deviceId;
     std::string deviceName;
+
     std::mutex busy_lock;
 
     std::atomic_int ppm;
     std::atomic_llong offset;
     std::atomic_bool agcMode;
     std::atomic_long sampleRate;
+    std::string antennaName;
     ConfigSettings streamOpts;
     ConfigGains gains;
     std::map<std::string, std::string> settings;
@@ -133,6 +138,16 @@ public:
     void setBookmarksVisible(bool state);
     bool getBookmarksVisible();
     
+	//Recording settings:
+    void setRecordingPath(std::string recPath);
+    std::string getRecordingPath();
+	bool verifyRecordingPath();
+
+	void setRecordingSquelchOption(int enumChoice);
+	int getRecordingSquelchOption();
+    
+	void setRecordingFileTimeLimit(int nbSeconds);
+	int getRecordingFileTimeLimit();
     
 #if USE_HAMLIB
     int getRigModel();
@@ -180,6 +195,10 @@ private:
     std::atomic_int dbOffset;
     std::vector<SDRManualDef> manualDevices;
     std::atomic_bool bookmarksVisible;
+
+    std::string recordingPath = "";
+	int recordingSquelchOption = 0;
+	int recordingFileTimeLimitSeconds = 0;
 #if USE_HAMLIB
     std::atomic_int rigModel, rigRate;
     std::string rigPort;
diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp
index ca5a8c1..d17a02e 100644
--- a/src/AppFrame.cpp
+++ b/src/AppFrame.cpp
@@ -18,17 +18,21 @@
 
 #include <vector>
 #include <algorithm>
-#include "AudioThread.h"
+#include "AudioSinkFileThread.h"
 #include "CubicSDR.h"
 #include "DataTree.h"
 #include "ColorTheme.h"
 #include "DemodulatorMgr.h"
 #include "ImagePanel.h"
+#include "ActionDialog.h"
 
 #include <thread>
+#include <iostream>
+#include <iomanip>
 
 #include <wx/panel.h>
 #include <wx/numformatter.h>
+#include <stddef.h>
 
 #ifdef __linux__
 #include "CubicSDR.xpm"
@@ -50,6 +54,22 @@ wxEND_EVENT_TABLE()
 #endif
 
 
+
+class ActionDialogBookmarkReset : public ActionDialog {
+public:
+    ActionDialogBookmarkReset() : ActionDialog(wxGetApp().getAppFrame(), wxID_ANY, wxT("Reset Bookmarks?")) {
+        m_questionText->SetLabelText(wxT("Resetting bookmarks will erase all current bookmarks; are you sure?"));
+    }
+    
+    void doClickOK() {
+        wxGetApp().getBookmarkMgr().resetBookmarks();
+        wxGetApp().getBookmarkMgr().updateBookmarks();
+        wxGetApp().getBookmarkMgr().updateActiveList();
+    }
+};
+
+
+
 /* split a string by 'seperator' into a vector of string */
 std::vector<std::string> str_explode(const std::string &seperator, const std::string &in_str);
 
@@ -57,7 +77,7 @@ std::vector<std::string> str_explode(const std::string &seperator, const std::st
 #define APPFRAME_MODEMPROPS_MAXSIZE 240
 
 AppFrame::AppFrame() :
-        wxFrame(NULL, wxID_ANY, CUBICSDR_TITLE), activeDemodulator(NULL) {
+        wxFrame(NULL, wxID_ANY, CUBICSDR_TITLE), activeDemodulator(nullptr) {
 
 #ifdef __linux__
     SetIcon(wxICON(cubicsdr));
@@ -100,7 +120,7 @@ AppFrame::AppFrame() :
 #endif
             
     gainCanvas = new GainCanvas(demodPanel, attribList);
-    gainCanvas->setHelpTip("Tuner gains in dB. Click / use Mousewheel to change.");
+    gainCanvas->setHelpTip("Tuner gains, usually in dB. Click / use Mousewheel to change.");
     gainSizerItem = demodTray->Add(gainCanvas, 0, wxEXPAND | wxALL, 0);
     gainSizerItem->Show(false);
     gainSpacerItem = demodTray->AddSpacer(1);
@@ -399,43 +419,13 @@ AppFrame::AppFrame() :
 
     // Make a menubar
     menuBar = new wxMenuBar;
-    wxMenu *menu = new wxMenu;
-#ifndef __APPLE__ 
-#ifdef CUBICSDR_ENABLE_ABOUT_DIALOG
-    menu->Append(wxID_ABOUT_CUBICSDR, "About " CUBICSDR_INSTALL_NAME);
-#endif
-#endif
-    menu->Append(wxID_SDR_DEVICES, "SDR Devices");
-    menu->AppendSeparator();
-    menu->Append(wxID_SDR_START_STOP, "Stop / Start Device");
-    menu->AppendSeparator();
-    menu->Append(wxID_OPEN, "&Open Session");
-    menu->Append(wxID_SAVE, "&Save Session");
-    menu->Append(wxID_SAVEAS, "Save Session &As..");
-    menu->AppendSeparator();
-    menu->Append(wxID_RESET, "&Reset Session");
-            
-#ifndef __APPLE__
-    menu->AppendSeparator();
-    menu->Append(wxID_CLOSE);
-#else
-#ifdef CUBICSDR_ENABLE_ABOUT_DIALOG
-    if ( wxApp::s_macAboutMenuItemId != wxID_NONE ) {
-        wxString aboutLabel;
-        aboutLabel.Printf(_("About %s"), CUBICSDR_INSTALL_NAME);
-        menu->Append( wxApp::s_macAboutMenuItemId, aboutLabel);
-    }
-#endif
-#endif
-
-    menuBar->Append(menu, wxT("&File"));
+   
+    menuBar->Append(makeFileMenu(), wxT("&File"));
             
     settingsMenu = new wxMenu;
           
     menuBar->Append(settingsMenu, wxT("&Settings"));
             
-    menu = new wxMenu;
-
     std::vector<RtAudio::DeviceInfo>::iterator devices_i;
     std::map<int, RtAudio::DeviceInfo>::iterator mdevices_i;
     AudioThread::enumerateDevices(devices);
@@ -469,7 +459,7 @@ AppFrame::AppFrame() :
     menuBar->Append(sampleRateMenu, wxT("Sample &Rate"));
 
     // Audio Sample Rates
-    menu = new wxMenu;
+    wxMenu *audioSampleRateMenu = new wxMenu;
 
 #define NUM_RATES_DEFAULT 4
     unsigned int desired_rates[NUM_RATES_DEFAULT] = { 48000, 44100, 96000, 192000 };
@@ -499,7 +489,7 @@ AppFrame::AppFrame() :
     for (mdevices_i = outputDevices.begin(); mdevices_i != outputDevices.end(); mdevices_i++) {
         int menu_id = wxID_AUDIO_BANDWIDTH_BASE + wxID_AUDIO_DEVICE_MULTIPLIER * mdevices_i->first;
         wxMenu *subMenu = new wxMenu;
-        menu->AppendSubMenu(subMenu, mdevices_i->second.name, wxT("Description?"));
+        audioSampleRateMenu->AppendSubMenu(subMenu, mdevices_i->second.name, wxT("Description?"));
 
         int j = 0;
         for (std::vector<unsigned int>::iterator srate = mdevices_i->second.sampleRates.begin(); srate != mdevices_i->second.sampleRates.end();
@@ -517,7 +507,12 @@ AppFrame::AppFrame() :
         }
     }
 
-    menuBar->Append(menu, wxT("Audio &Sample Rate"));
+    menuBar->Append(audioSampleRateMenu, wxT("Audio &Sample Rate"));
+
+	//Add a Recording menu
+	menuBar->Append(makeRecordingMenu(), wxT("Recordin&g"));
+	//
+	updateRecordingMenu();
 
     //Add Display menu
     displayMenu = new wxMenu;
@@ -526,7 +521,7 @@ AppFrame::AppFrame() :
 
     int fontScale = wxGetApp().getConfig()->getFontScale();
 
-    fontMenu->AppendRadioItem(wxID_DISPLAY_BASE, "Normal")->Check(GLFont::GLFONT_SCALE_NORMAL == fontScale);
+    fontMenu->AppendRadioItem(wxID_DISPLAY_BASE, "Default")->Check(GLFont::GLFONT_SCALE_NORMAL == fontScale);
     fontMenu->AppendRadioItem(wxID_DISPLAY_BASE + 1, "1.5x")->Check(GLFont::GLFONT_SCALE_MEDIUM == fontScale);
     fontMenu->AppendRadioItem(wxID_DISPLAY_BASE + 2, "2.0x")->Check(GLFont::GLFONT_SCALE_LARGE == fontScale);
 
@@ -720,6 +715,137 @@ AppFrame::~AppFrame() {
     t_FFTData->join();
 }
 
+wxMenu *AppFrame::makeFileMenu() {
+    
+    wxMenu *menu = new wxMenu;
+#ifndef __APPLE__ 
+#ifdef CUBICSDR_ENABLE_ABOUT_DIALOG
+    menu->Append(wxID_ABOUT_CUBICSDR, "About " CUBICSDR_INSTALL_NAME);
+#endif
+#endif
+    menu->Append(wxID_SDR_DEVICES, "SDR Devices");
+    menu->AppendSeparator();
+    menu->Append(wxID_SDR_START_STOP, "Stop / Start Device");
+    menu->AppendSeparator();
+
+    wxMenu *sessionMenu = new wxMenu;
+    
+    sessionMenu->Append(wxID_OPEN, "&Open Session");
+    sessionMenu->Append(wxID_SAVE, "&Save Session");
+    sessionMenu->Append(wxID_SAVEAS, "Save Session &As..");
+    sessionMenu->AppendSeparator();
+    sessionMenu->Append(wxID_RESET, "&Reset Session");
+
+    menu->AppendSubMenu(sessionMenu, "Session");
+
+    menu->AppendSeparator();
+
+    wxMenu *bookmarkMenu = new wxMenu;
+    
+    bookmarkMenu->Append(wxID_OPEN_BOOKMARKS, "Open Bookmarks");
+	bookmarkMenu->Append(wxID_SAVE_BOOKMARKS, "Save Bookmarks");
+	bookmarkMenu->Append(wxID_SAVEAS_BOOKMARKS, "Save Bookmarks As..");
+	bookmarkMenu->AppendSeparator();
+	bookmarkMenu->Append(wxID_RESET_BOOKMARKS, "Reset Bookmarks");
+
+    menu->AppendSubMenu(bookmarkMenu, "Bookmarks");
+    
+#ifndef __APPLE__
+    menu->AppendSeparator();
+    menu->Append(wxID_CLOSE);
+#else
+#ifdef CUBICSDR_ENABLE_ABOUT_DIALOG
+    if (wxApp::s_macAboutMenuItemId != wxID_NONE) {
+        wxString aboutLabel;
+        aboutLabel.Printf(_("About %s"), CUBICSDR_INSTALL_NAME);
+        menu->Append(wxApp::s_macAboutMenuItemId, aboutLabel);
+    }
+#endif
+#endif
+
+	fileMenu = menu;
+
+    return menu;
+}
+
+wxMenu *AppFrame::makeRecordingMenu() {
+	
+	recordingMenuItems.clear();
+
+	wxMenu *menu = new wxMenu;
+
+	recordingMenuItems[wxID_RECORDING_PATH] = menu->Append(wxID_RECORDING_PATH, getSettingsLabel("Set Recording Path", "<Not Set>"));
+
+	menu->AppendSeparator();
+
+	//Squelch options as sub-menu:
+	wxMenu *subMenu = new wxMenu;
+	recordingMenuItems[wxID_RECORDING_SQUELCH_BASE] = menu->AppendSubMenu(subMenu, "Squelch");
+
+	recordingMenuItems[wxID_RECORDING_SQUELCH_SILENCE] = subMenu->AppendRadioItem(wxID_RECORDING_SQUELCH_SILENCE, "Record Silence", 
+		"Record below squelch-break audio as silence, i.e records as the user may hear.");
+	recordingMenuItems[wxID_RECORDING_SQUELCH_SKIP] = subMenu->AppendRadioItem(wxID_RECORDING_SQUELCH_SKIP, "Skip Silence", 
+		"Do not record below squelch-break audio, i.e squelch-break audio parts are packed together.");
+	recordingMenuItems[wxID_RECORDING_SQUELCH_ALWAYS] = subMenu->AppendRadioItem(wxID_RECORDING_SQUELCH_ALWAYS, "Record Always", 
+		"Record everything irrespective of the squelch level.");
+	
+	recordingMenuItems[wxID_RECORDING_FILE_TIME_LIMIT] = menu->Append(wxID_RECORDING_FILE_TIME_LIMIT, getSettingsLabel("File time limit", "<Not Set>"), 
+		"Creates a new file automatically, each time the recording lasts longer than the limit, named according to the current time.");
+
+	recordingMenuItems[wxID_RECORDING_SQUELCH_SILENCE]->Check(true);
+
+	recordingMenu = menu;
+
+	return menu;
+}
+
+void AppFrame::updateRecordingMenu() {
+
+	// Recording path:
+	std::string recPath = wxGetApp().getConfig()->getRecordingPath();
+	if (recPath.length() > 32) {
+		recPath = "..." + recPath.substr(recPath.length() - 32, 32);
+	}
+
+	recordingMenuItems[wxID_RECORDING_PATH]->SetItemLabel(getSettingsLabel("Set Recording Path", recPath.empty() ? "<Not Set>" : recPath));
+
+	//Squelch options:
+	int squelchEnumValue = wxGetApp().getConfig()->getRecordingSquelchOption();
+
+	if (squelchEnumValue == AudioSinkFileThread::SQUELCH_RECORD_SILENCE) {
+
+		recordingMenuItems[wxID_RECORDING_SQUELCH_SILENCE]->Check(true);
+		recordingMenuItems[wxID_RECORDING_SQUELCH_BASE]->SetItemLabel(getSettingsLabel("Squelch", "Record Silence"));
+
+	} else if (squelchEnumValue == AudioSinkFileThread::SQUELCH_SKIP_SILENCE) {
+
+		recordingMenuItems[wxID_RECORDING_SQUELCH_SKIP]->Check(true);
+		recordingMenuItems[wxID_RECORDING_SQUELCH_BASE]->SetItemLabel(getSettingsLabel("Squelch", "Skip Silence"));
+
+	} else if (squelchEnumValue == AudioSinkFileThread::SQUELCH_RECORD_ALWAYS) {
+
+		recordingMenuItems[wxID_RECORDING_SQUELCH_ALWAYS]->Check(true);
+		recordingMenuItems[wxID_RECORDING_SQUELCH_BASE]->SetItemLabel(getSettingsLabel("Squelch", "Record Always"));
+	}
+	else {
+		recordingMenuItems[wxID_RECORDING_SQUELCH_SILENCE]->Check(true);
+		recordingMenuItems[wxID_RECORDING_SQUELCH_BASE]->SetItemLabel(getSettingsLabel("Squelch", "Record Silence"));
+
+	}
+
+	//File time limit:
+	int fileTimeLimitSeconds = wxGetApp().getConfig()->getRecordingFileTimeLimit();
+
+	if (fileTimeLimitSeconds <= 0) {
+		
+		recordingMenuItems[wxID_RECORDING_FILE_TIME_LIMIT]->SetItemLabel(getSettingsLabel("File time limit","<Not Set>"));
+	}
+	else {
+		recordingMenuItems[wxID_RECORDING_FILE_TIME_LIMIT]->SetItemLabel(getSettingsLabel("File time limit",
+			std::to_string(fileTimeLimitSeconds), "s"));
+	}
+}
+
 void AppFrame::initDeviceParams(SDRDeviceInfo *devInfo) {
     this->devInfo = devInfo;
     deviceChanged.store(true);
@@ -751,11 +877,13 @@ void AppFrame::updateDeviceParams() {
 
     newSettingsMenu->AppendSeparator();
 
-    newSettingsMenu->Append(wxID_SET_DB_OFFSET, "Power Level Offset");
-    newSettingsMenu->Append(wxID_SET_FREQ_OFFSET, "Frequency Offset");
+    settingsMenuItems.clear();
+
+    settingsMenuItems[wxID_SET_DB_OFFSET] = newSettingsMenu->Append(wxID_SET_DB_OFFSET, getSettingsLabel("Power Level Offset",  std::to_string(wxGetApp().getConfig()->getDBOffset()), "dB"));
+    settingsMenuItems[wxID_SET_FREQ_OFFSET] =  newSettingsMenu->Append(wxID_SET_FREQ_OFFSET, getSettingsLabel("Frequency Offset", std::to_string(wxGetApp().getOffset() / 1000 ) , "KHz"));
 
     if (devInfo->hasCORR(SOAPY_SDR_RX, 0)) {
-        newSettingsMenu->Append(wxID_SET_PPM, "Device PPM");
+        settingsMenuItems[wxID_SET_PPM] = newSettingsMenu->Append(wxID_SET_PPM, getSettingsLabel("Device PPM", std::to_string(wxGetApp().getPPM()) , "ppm"));
     }
 
     if (devInfo->getDriver() != "rtlsdr") {
@@ -770,47 +898,107 @@ void AppFrame::updateDeviceParams() {
     } else if (!wxGetApp().getAGCMode()) {
         wxGetApp().setAGCMode(true);
     }
-    
+
+    //Add an Antenna menu if more than one (RX) antenna, to keep the UI free of useless entries
+    antennaNames.clear();
+    antennaMenuItems.clear();
+    std::vector<std::string> availableAntennas = devInfo->getAntennaNames(SOAPY_SDR_RX, 0);
+ 
+    if (availableAntennas.size() > 1) {
+              
+        newSettingsMenu->AppendSeparator();
+
+        antennaNames = availableAntennas;
+
+        wxMenu *subMenu = new wxMenu;
+        
+        int i = 0;
+        std::string antennaChecked;
+        for (std::string currentAntenna : availableAntennas) {
+           
+            antennaMenuItems[wxID_ANTENNAS_BASE + i] = subMenu->AppendRadioItem(wxID_ANTENNAS_BASE + i, currentAntenna);
+
+            if (wxGetApp().getAntennaName() == currentAntenna) {
+                antennaMenuItems[wxID_ANTENNAS_BASE + i]->Check(true);
+                antennaChecked = currentAntenna;
+            }
+
+            i++;
+        }
+        antennaMenuItems[wxID_ANTENNA_CURRENT] = newSettingsMenu->AppendSubMenu(subMenu, "Antenna");
+        
+        //Change the Antenna label to indicate the current antenna.
+        if (!antennaChecked.empty()) {
+        
+            antennaMenuItems[wxID_ANTENNA_CURRENT]->SetItemLabel(getSettingsLabel("Antenna", antennaChecked));
+        }
+    }
+
+    //Add an informative, read-only menu entry to display the current TX selected antenna, if any.
+    if (devInfo->getAntennaNames(SOAPY_SDR_TX, 0).size() > 1) {
+
+        currentTXantennaName = devInfo->getAntennaName(SOAPY_SDR_TX, 0);
+        
+        newSettingsMenu->AppendSeparator();
+        
+        antennaMenuItems[wxID_ANTENNA_CURRENT_TX] = newSettingsMenu->Append(wxID_ANTENNA_CURRENT_TX, getSettingsLabel("TX Antenna", currentTXantennaName));
+        antennaMenuItems[wxID_ANTENNA_CURRENT_TX]->Enable(false);
+    }
+
+    //Runtime settings part
     SoapySDR::ArgInfoList::const_iterator args_i;
     settingArgs = soapyDev->getSettingInfo();
 
     if (settingArgs.size()) {
         newSettingsMenu->AppendSeparator();
     }
-    
+    //for each Runtime option of index i:
     for (args_i = settingArgs.begin(); args_i != settingArgs.end(); args_i++) {
+
         SoapySDR::ArgInfo arg = (*args_i);
+
         std::string currentVal = soapyDev->readSetting(arg.key);
-        if (arg.type == SoapySDR::ArgInfo::BOOL) {
+        
+		if (arg.type == SoapySDR::ArgInfo::BOOL) {
             wxMenuItem *item = newSettingsMenu->AppendCheckItem(wxID_SETTINGS_BASE+i, arg.name, arg.description);
             item->Check(currentVal=="true");
             i++;
         } else if (arg.type == SoapySDR::ArgInfo::INT) {
-            newSettingsMenu->Append(wxID_SETTINGS_BASE+i, arg.name, arg.description);
+            
+            settingsMenuItems[wxID_SETTINGS_BASE + i] = newSettingsMenu->Append(wxID_SETTINGS_BASE + i, getSettingsLabel(arg.name, currentVal, arg.units), arg.description);
             i++;
         } else if (arg.type == SoapySDR::ArgInfo::FLOAT) {
-            newSettingsMenu->Append(wxID_SETTINGS_BASE+i, arg.name, arg.description);
+            settingsMenuItems[wxID_SETTINGS_BASE + i] = newSettingsMenu->Append(wxID_SETTINGS_BASE + i, getSettingsLabel(arg.name, currentVal, arg.units), arg.description);
             i++;
         } else if (arg.type == SoapySDR::ArgInfo::STRING) {
             if (arg.options.size()) {
                 wxMenu *subMenu = new wxMenu;
                 int j = 0;
-                for (std::vector<std::string>::iterator str_i = arg.options.begin(); str_i != arg.options.end(); str_i++) {
-                    std::string optName = (*str_i);
+                std::vector<int> subItemsIds;
+				//for each of this options
+                for (std::string optName : arg.options) {
+					//by default the option name is the same as the displayed name.
                     std::string displayName = optName;
-                    if (arg.optionNames.size()) {
+                    
+					if (arg.optionNames.size()) {
                         displayName = arg.optionNames[j];
                     }
                     wxMenuItem *item = subMenu->AppendRadioItem(wxID_SETTINGS_BASE+i, displayName);
-                    if (currentVal == (*str_i)) {
+                    subItemsIds.push_back(wxID_SETTINGS_BASE + i);
+                    
+                    if (currentVal == optName) {
                         item->Check(true);
                     }
                     j++;
                     i++;
                 }
-                newSettingsMenu->AppendSubMenu(subMenu, arg.name, arg.description);
+                settingsMenuItems[wxID_SETTINGS_BASE + i] = newSettingsMenu->AppendSubMenu(subMenu, getSettingsLabel(arg.name, currentVal, arg.units), arg.description);
+                //map subitems ids to their parent item !
+                for (int currentSubId : subItemsIds) {
+                    settingsMenuItems[currentSubId] = settingsMenuItems[wxID_SETTINGS_BASE + i];
+                }
             } else {
-                newSettingsMenu->Append(wxID_SETTINGS_BASE+i, arg.name, arg.description);
+                settingsMenuItems[wxID_SETTINGS_BASE + i] = newSettingsMenu->Append(wxID_SETTINGS_BASE + i, getSettingsLabel(arg.name, currentVal, arg.units), arg.description);
                 i++;
             }
         }
@@ -876,7 +1064,6 @@ void AppFrame::updateDeviceParams() {
     newSampleRateMenu->AppendSeparator();
     sampleRateMenuItems[wxID_BANDWIDTH_MANUAL_DIALOG] = newSampleRateMenu->Append(wxID_BANDWIDTH_MANUAL_DIALOG, wxT("Manual Entry..."));
 
-   
     menuBar->Replace(2, newSampleRateMenu, wxT("Sample &Rate"));
     sampleRateMenu = newSampleRateMenu;
 
@@ -885,9 +1072,6 @@ void AppFrame::updateDeviceParams() {
         gainSizerItem->Show(true);
         gainSizerItem->SetMinSize(devInfo->getSoapyDevice()->listGains(SOAPY_SDR_RX,0).size()*50,0);
         demodTray->Layout();
-        gainCanvas->updateGainUI();
-        gainCanvas->Refresh();
-        gainCanvas->Refresh();
     } else {
         gainSpacerItem->Show(false);
         gainSizerItem->Show(false);
@@ -1060,6 +1244,7 @@ bool AppFrame::actionOnMenuReset(wxCommandEvent& event) {
 
         SetTitle(CUBICSDR_TITLE);
         currentSessionFile = "";
+		currentBookmarkFile = "";
         bookmarkSplitter->Unsplit(bookmarkView);
         bookmarkSplitter->SplitVertically(bookmarkView, mainVisSplitter, wxGetApp().getConfig()->getBookmarkSplit());
         hideBookmarksItem->Check(false);
@@ -1098,7 +1283,14 @@ bool AppFrame::actionOnMenuAbout(wxCommandEvent& event) {
 
 bool AppFrame::actionOnMenuSettings(wxCommandEvent& event) {
 
-    if (event.GetId() >= wxID_SETTINGS_BASE && event.GetId() < settingsIdMax) {
+    if (event.GetId() >= wxID_ANTENNAS_BASE && event.GetId() < wxID_ANTENNAS_BASE + antennaNames.size()) {
+
+        wxGetApp().setAntennaName(antennaNames[event.GetId() - wxID_ANTENNAS_BASE]);
+      
+        antennaMenuItems[wxID_ANTENNA_CURRENT]->SetItemLabel(getSettingsLabel("Antenna", wxGetApp().getAntennaName()));
+        return true;
+    } 
+    else if (event.GetId() >= wxID_SETTINGS_BASE && event.GetId() < settingsIdMax) {
 
         int setIdx = event.GetId() - wxID_SETTINGS_BASE;
         int menuIdx = 0;
@@ -1109,6 +1301,9 @@ bool AppFrame::actionOnMenuSettings(wxCommandEvent& event) {
             if (arg.type == SoapySDR::ArgInfo::STRING && arg.options.size() && setIdx >= menuIdx && setIdx < menuIdx + (int)arg.options.size()) {
                 int optIdx = setIdx - menuIdx;
                 wxGetApp().getSDRThread()->writeSetting(arg.key, arg.options[optIdx]);
+                
+                //update parent menu item label to display the current value
+                settingsMenuItems[menuIdx + wxID_SETTINGS_BASE]->SetItemLabel(getSettingsLabel(arg.name, arg.options[optIdx], arg.units));             
                 break;
             }
             else if (arg.type == SoapySDR::ArgInfo::STRING && arg.options.size()) {
@@ -1121,6 +1316,9 @@ bool AppFrame::actionOnMenuSettings(wxCommandEvent& event) {
                 }
                 else if (arg.type == SoapySDR::ArgInfo::STRING) {
                     wxString stringVal = wxGetTextFromUser(arg.description, arg.name, wxGetApp().getSDRThread()->readSetting(arg.key));
+
+                    settingsMenuItems[menuIdx + wxID_SETTINGS_BASE]->SetItemLabel(getSettingsLabel(arg.name, stringVal.ToStdString(), arg.units));
+
                     if (stringVal.ToStdString() != "") {
                         wxGetApp().getSDRThread()->writeSetting(arg.key, stringVal.ToStdString());
                     }
@@ -1135,6 +1333,9 @@ bool AppFrame::actionOnMenuSettings(wxCommandEvent& event) {
                         currentVal = 0;
                     }
                     int intVal = wxGetNumberFromUser(arg.description, arg.units, arg.name, currentVal, arg.range.minimum(), arg.range.maximum(), this);
+
+                    settingsMenuItems[menuIdx + wxID_SETTINGS_BASE]->SetItemLabel(getSettingsLabel(arg.name, std::to_string(intVal), arg.units));
+
                     if (intVal != -1) {
                         wxGetApp().getSDRThread()->writeSetting(arg.key, std::to_string(intVal));
                     }
@@ -1148,6 +1349,7 @@ bool AppFrame::actionOnMenuSettings(wxCommandEvent& event) {
                     catch (std::invalid_argument e) {
                         // ...
                     }
+                    settingsMenuItems[menuIdx + wxID_SETTINGS_BASE]->SetItemLabel(getSettingsLabel(arg.name, floatVal.ToStdString(), arg.units));
                     break;
                 }
                 else {
@@ -1158,7 +1360,7 @@ bool AppFrame::actionOnMenuSettings(wxCommandEvent& event) {
                 menuIdx++;
             }
         } //end for
-
+		
         return true;
     }
 
@@ -1282,7 +1484,6 @@ bool AppFrame::actionOnMenuAudioSampleRate(wxCommandEvent& event) {
             }
             i++;
         }
-
     }
 
     return false;
@@ -1324,9 +1525,153 @@ bool AppFrame::actionOnMenuLoadSave(wxCommandEvent& event) {
         return true;
     }
 
+	//save mecanic for bookmark files
+	else if (event.GetId() == wxID_SAVE_BOOKMARKS) {
+
+		if (!currentBookmarkFile.empty()) {
+			wxGetApp().getBookmarkMgr().saveToFile(currentBookmarkFile, false, true);
+		}
+		else {
+			wxFileDialog saveFileDialog(this, _("Save XML Bookmark file"), "", "", "XML files (*.xml)|*.xml", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
+			if (saveFileDialog.ShowModal() == wxID_CANCEL) {
+				return true;
+			}
+
+			// Make sure the file name actually ends in .xml
+			std::string fileName = saveFileDialog.GetPath().ToStdString();
+			std::string lcFileName = fileName;
+
+			std::transform(lcFileName.begin(), lcFileName.end(), lcFileName.begin(), ::tolower);
+
+			if (lcFileName.find_last_of(".xml") != lcFileName.length() - 1) {
+				fileName.append(".xml");
+			}
+
+			wxGetApp().getBookmarkMgr().saveToFile(fileName, false, true);
+			currentBookmarkFile = fileName;
+		}
+
+		return true;
+	}
+	else if (event.GetId() == wxID_OPEN_BOOKMARKS) {
+
+		wxFileDialog openFileDialog(this, _("Open XML Bookmark file"), "", "", "XML files (*.xml)|*.xml", wxFD_OPEN | wxFD_FILE_MUST_EXIST);
+		if (openFileDialog.ShowModal() == wxID_CANCEL) {
+			return true;
+		}
+		if (wxGetApp().getBookmarkMgr().loadFromFile(openFileDialog.GetPath().ToStdString(), false, true)) {
+			
+			wxGetApp().getBookmarkMgr().updateBookmarks();
+			wxGetApp().getBookmarkMgr().updateActiveList();
+
+			currentBookmarkFile = openFileDialog.GetPath().ToStdString();
+		}
+		else {
+			//failure at loading.
+			currentBookmarkFile = "";
+		}
+
+		return true;
+	}
+	else if (event.GetId() == wxID_SAVEAS_BOOKMARKS) {
+
+		wxFileDialog saveFileDialog(this, _("Save XML Bookmark file"), "", "", "XML files (*.xml)|*.xml", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
+		if (saveFileDialog.ShowModal() == wxID_CANCEL) {
+			return true;
+		}
+
+		// Make sure the file name actually ends in .xml
+		std::string fileName = saveFileDialog.GetPath().ToStdString();
+		std::string lcFileName = fileName;
+
+		std::transform(lcFileName.begin(), lcFileName.end(), lcFileName.begin(), ::tolower);
+
+		if (lcFileName.find_last_of(".xml") != lcFileName.length() - 1) {
+			fileName.append(".xml");
+		}
+
+		wxGetApp().getBookmarkMgr().saveToFile(fileName, false, true);
+		currentBookmarkFile = fileName;
+
+		return true;
+	}
+	else if (event.GetId() == wxID_RESET_BOOKMARKS) {
+
+        ActionDialog::showDialog(new ActionDialogBookmarkReset());
+
+		return true;
+	}
+
     return false;
 }
 
+bool AppFrame::actionOnMenuRecording(wxCommandEvent& event) {
+
+	if (event.GetId() == wxID_RECORDING_PATH) {
+
+		std::string recPath = wxGetApp().getConfig()->getRecordingPath();
+
+		wxDirDialog recPathDialog(this, _("File Path for Recordings"), recPath, wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
+		if (recPathDialog.ShowModal() == wxID_CANCEL) {
+			return true;
+		}
+
+		wxGetApp().getConfig()->setRecordingPath(recPathDialog.GetPath().ToStdString());
+
+		updateRecordingMenu();
+		return true;
+
+	}
+	else if (event.GetId() == wxID_RECORDING_SQUELCH_SILENCE) {
+
+		wxGetApp().getConfig()->setRecordingSquelchOption(AudioSinkFileThread::SQUELCH_RECORD_SILENCE);
+
+		updateRecordingMenu();
+		return true;
+	}
+	else if (event.GetId() == wxID_RECORDING_SQUELCH_SKIP) {
+
+		wxGetApp().getConfig()->setRecordingSquelchOption(AudioSinkFileThread::SQUELCH_SKIP_SILENCE);
+
+		updateRecordingMenu();
+		return true;
+	}
+	else if (event.GetId() == wxID_RECORDING_SQUELCH_ALWAYS) {
+		
+		wxGetApp().getConfig()->setRecordingSquelchOption(AudioSinkFileThread::SQUELCH_RECORD_ALWAYS);
+
+		updateRecordingMenu();
+		return true;
+	}
+	else if (event.GetId() == wxID_RECORDING_FILE_TIME_LIMIT) {
+
+		int currentFileLimitSeconds = wxGetApp().getConfig()->getRecordingFileTimeLimit();
+
+		long newFileLimit = wxGetNumberFromUser(wxString("\nFile time limit:\n") + 
+			"\nCreates a new file automatically, each time the recording lasts longer than the limit, named according to the current time.\n\n  " + 
+			+ "min: 0 s (no limit)"
+			+ ", max: 36000 s (10 hours)\n",
+			"Time in seconds",
+			"File Time Limit",
+			//If a manual sample rate has already been input, recall this one.
+			currentFileLimitSeconds > 0 ? currentFileLimitSeconds : 0,
+			0,
+			36000,
+			this);
+
+		if (newFileLimit != -1) {
+
+			wxGetApp().getConfig()->setRecordingFileTimeLimit((int)newFileLimit);
+
+			updateRecordingMenu();
+		}
+
+		return true;
+	}
+
+	return false;
+}
+
 bool AppFrame::actionOnMenuRig(wxCommandEvent& event) {
     
     bool bManaged = false;
@@ -1498,10 +1843,13 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
         wxGetApp().getSDRThread()->setIQSwap(!wxGetApp().getSDRThread()->getIQSwap());
     } 
     else if (event.GetId() == wxID_SET_FREQ_OFFSET) {
-        long ofs = wxGetNumberFromUser("Shift the displayed frequency by this amount.\ni.e. -125000000 for -125 MHz", "Frequency (Hz)",
-                "Frequency Offset", wxGetApp().getOffset(), -2000000000, 2000000000, this);
+        //enter in KHz to accomodate > 2GHz shifts for down/upconverters on 32 bit platforms.
+        long ofs = wxGetNumberFromUser("Shift the displayed frequency by this amount of KHz.\ni.e. -125000 for -125 MHz", "Frequency (KHz)",
+                "Frequency Offset", (long long)(wxGetApp().getOffset() / 1000.0) , -2000000000, 2000000000, this);
         if (ofs != -1) {
-            wxGetApp().setOffset(ofs);
+            wxGetApp().setOffset((long long) ofs * 1000);
+          
+            settingsMenuItems[wxID_SET_FREQ_OFFSET]->SetItemLabel(getSettingsLabel("Frequency Offset", std::to_string(wxGetApp().getOffset() / 1000), "KHz"));
         }
     } 
     else if (event.GetId() == wxID_SET_DB_OFFSET) {
@@ -1509,6 +1857,7 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
                                        "Power Level Offset", wxGetApp().getConfig()->getDBOffset(), -1000, 1000, this);
         if (ofs != -1) {
             wxGetApp().getConfig()->setDBOffset(ofs);
+            settingsMenuItems[wxID_SET_DB_OFFSET]->SetItemLabel(getSettingsLabel("Power Level Offset", std::to_string(wxGetApp().getConfig()->getDBOffset()), "dB"));
         }
     } 
     else if (actionOnMenuAGC(event)) {
@@ -1521,6 +1870,8 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
         long ofs = wxGetNumberFromUser("Frequency correction for device in PPM.\ni.e. -51 for -51 PPM\n\nNote: you can adjust PPM interactively\nby holding ALT over the frequency tuning bar.\n", "Parts per million (PPM)",
                 "Frequency Correction", wxGetApp().getPPM(), -1000, 1000, this);
             wxGetApp().setPPM(ofs);
+
+            settingsMenuItems[wxID_SET_PPM]->SetItemLabel(getSettingsLabel("Device PPM", std::to_string(wxGetApp().getPPM()), "ppm"));
     } 
     else if (actionOnMenuLoadSave(event)) {
         return;
@@ -1540,9 +1891,12 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
     else if (actionOnMenuAudioSampleRate(event)) {
         return;
     }
-    else if (actionOnMenuDisplay(event)) {
+    else if (actionOnMenuRecording(event)) {
         return;
     }
+	else if (actionOnMenuDisplay(event)) {
+		return;
+	}
     //Optional : Rig 
     else if (actionOnMenuRig(event)) {
         return;
@@ -1611,8 +1965,18 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
     if (deviceChanged.load()) {
         updateDeviceParams();
     }
+
+    //Refresh the current TX antenna on, if any:
+    if ((antennaMenuItems.find(wxID_ANTENNA_CURRENT_TX) != antennaMenuItems.end()) && devInfo) {
+        std::string actualTxAntenna = devInfo->getAntennaName(SOAPY_SDR_TX, 0);
+        
+        if (currentTXantennaName != actualTxAntenna) {
+            currentTXantennaName = actualTxAntenna;
+            antennaMenuItems[wxID_ANTENNA_CURRENT_TX]->SetItemLabel(getSettingsLabel("TX Antenna", currentTXantennaName));
+        }
+    }
     
-    DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
+    DemodulatorInstancePtr demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
 
     if (demod && demod->isModemInitialized()) {
         if (demod->isTracking()) {
@@ -1637,7 +2001,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
             wxGetApp().getDemodMgr().setLastBandwidth(demod->getBandwidth());
         }
 
-        if (demod != activeDemodulator) {
+        if (demod.get() != activeDemodulator) {
             demodSignalMeter->setInputValue(demod->getSquelchLevel());
             demodGainMeter->setInputValue(demod->getGain());
             wxGetApp().getDemodMgr().setLastGain(demod->getGain());
@@ -1781,7 +2145,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
             demod->setGain(demodGainMeter->getInputValue());
             demodGainMeter->setLevel(demodGainMeter->getInputValue());
         }
-        activeDemodulator = demod;
+        activeDemodulator = demod.get();
     } else if (demod) {
         // Wait state for current demodulator modem to activate..
     } else {
@@ -2010,13 +2374,15 @@ void AppFrame::OnAboutDialogClose(wxCommandEvent& event) {
 }
 
 void AppFrame::saveSession(std::string fileName) {
+
     DataTree s("cubicsdr_session");
     DataNode *header = s.rootNode()->newChild("header");
     //save as wstring to prevent problems 
     header->newChild("version")->element()->set(wxString(CUBICSDR_VERSION).ToStdWstring());
     
     *header->newChild("center_freq") = wxGetApp().getFrequency();
-    *header->newChild("sample_rate") = wxGetApp().getSampleRate();
+    *header->newChild("sample_rate") = wxGetApp().getSampleRate();       
+    *header->newChild("solo_mode") = wxGetApp().getSoloMode()?1:0;
     
     if (waterfallCanvas->getViewState()) {
         DataNode *viewState = header->newChild("view_state");
@@ -2027,11 +2393,12 @@ void AppFrame::saveSession(std::string fileName) {
     
     DataNode *demods = s.rootNode()->newChild("demodulators");
 
-    std::vector<DemodulatorInstance *> &instances = wxGetApp().getDemodMgr().getDemodulators();
+    //make a local copy snapshot of the list
+    std::vector<DemodulatorInstancePtr> instances = wxGetApp().getDemodMgr().getDemodulators();
     
-    for (auto instance_i : instances) {
+    for (auto instance : instances) {
         DataNode *demod = demods->newChild("demodulator");
-        wxGetApp().getDemodMgr().saveInstance(demod, instance_i);
+        wxGetApp().getDemodMgr().saveInstance(demod, instance);
     } //end for demodulators
 
     // Make sure the file name actually ends in .xml
@@ -2051,11 +2418,17 @@ void AppFrame::saveSession(std::string fileName) {
 }
 
 bool AppFrame::loadSession(std::string fileName) {
+
     DataTree l;
     if (!l.LoadFromFileXML(fileName)) {
         return false;
     }
 
+	//Check if it is a session file, read the root node.
+	if (l.rootNode()->getName() != "cubicsdr_session") {
+		return false;
+	}
+
 	wxGetApp().getDemodMgr().setActiveDemodulator(nullptr, false);
 
     wxGetApp().getDemodMgr().terminateAll();
@@ -2134,14 +2507,24 @@ bool AppFrame::loadSession(std::string fileName) {
             }
         }
 
-        DemodulatorInstance *loadedActiveDemod = nullptr;
-        DemodulatorInstance *newDemod = nullptr;
+        if (header->hasAnother("solo_mode")) {
+            
+            int solo_mode_activated = *header->getNext("solo_mode");
+
+            wxGetApp().setSoloMode((solo_mode_activated > 0) ? true : false);
+        }
+        else {
+            wxGetApp().setSoloMode(false);
+        }
+
+        DemodulatorInstancePtr loadedActiveDemod = nullptr;
+        DemodulatorInstancePtr newDemod = nullptr;
         
         if (l.rootNode()->hasAnother("demodulators")) {
             
         DataNode *demodulators = l.rootNode()->getNext("demodulators");
 
-        std::vector<DemodulatorInstance *> demodsLoaded;
+        std::vector<DemodulatorInstancePtr> demodsLoaded;
         
         while (demodulators->hasAnother("demodulator")) {
             DataNode *demod = demodulators->getNext("demodulator");
@@ -2162,7 +2545,7 @@ bool AppFrame::loadSession(std::string fileName) {
         }
         
         if (demodsLoaded.size()) {
-            wxGetApp().bindDemodulators(&demodsLoaded);
+            wxGetApp().notifyDemodulatorsChanged();
         }
             
         } // if l.rootNode()->hasAnother("demodulators")
@@ -2291,14 +2674,14 @@ FrequencyDialog::FrequencyDialogTarget AppFrame::getFrequencyDialogTarget() {
     return target;
 }
 
-void AppFrame::gkNudgeLeft(DemodulatorInstance *demod, int snap) {
+void AppFrame::gkNudgeLeft(DemodulatorInstancePtr demod, int snap) {
     if (demod) {
         demod->setFrequency(demod->getFrequency()-snap);
         demod->updateLabel(demod->getFrequency());
     }
 }
 
-void AppFrame::gkNudgeRight(DemodulatorInstance *demod, int snap) {
+void AppFrame::gkNudgeRight(DemodulatorInstancePtr demod, int snap) {
     if (demod) {
         demod->setFrequency(demod->getFrequency()+snap);
         demod->updateLabel(demod->getFrequency());
@@ -2324,7 +2707,10 @@ int AppFrame::OnGlobalKeyDown(wxKeyEvent &event) {
         return -1;
     }
     
-    DemodulatorInstance *demod = nullptr, *lastDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
+    DemodulatorInstancePtr demod = nullptr;
+     
+    DemodulatorInstancePtr lastDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
+    
     int snap = wxGetApp().getFrequencySnap();
     
     if (event.ControlDown()) {
@@ -2375,6 +2761,7 @@ int AppFrame::OnGlobalKeyDown(wxKeyEvent &event) {
         case 'S':
         case 'P':
         case 'M':
+        case 'R':
             return 1;
         case '0':
         case '1':
@@ -2449,8 +2836,8 @@ int AppFrame::OnGlobalKeyUp(wxKeyEvent &event) {
         return 1;
     }
 
-    DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getActiveDemodulator();
-    DemodulatorInstance *lastDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
+    DemodulatorInstancePtr activeDemod = wxGetApp().getDemodMgr().getActiveDemodulator();
+    DemodulatorInstancePtr lastDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
     
 #ifdef wxHAS_RAW_KEY_CODES
     switch (event.GetRawKeyCode()) {
@@ -2515,6 +2902,13 @@ int AppFrame::OnGlobalKeyUp(wxKeyEvent &event) {
             wxGetApp().setSoloMode(!wxGetApp().getSoloMode());
             return 1;
             break;
+        case 'R':
+            if (event.ShiftDown()) {
+                toggleAllActiveDemodRecording();
+            } else {
+                toggleActiveDemodRecording();
+            }
+            break;
         case 'P':
             wxGetApp().getSpectrumProcessor()->setPeakHold(!wxGetApp().getSpectrumProcessor()->getPeakHold());
             if (wxGetApp().getDemodSpectrumProcessor()) {
@@ -2559,6 +2953,43 @@ int AppFrame::OnGlobalKeyUp(wxKeyEvent &event) {
     return 1;
 }
 
+void AppFrame::toggleActiveDemodRecording() {
+    if (!wxGetApp().getConfig()->verifyRecordingPath()) {
+        return;
+    }
+    
+    DemodulatorInstancePtr activeDemod = wxGetApp().getDemodMgr().getActiveDemodulator();
+    
+    if (activeDemod) {
+        activeDemod->setRecording(!activeDemod->isRecording());
+        wxGetApp().getBookmarkMgr().updateActiveList();
+    }
+}
+
+void AppFrame::toggleAllActiveDemodRecording() {
+    if (!wxGetApp().getConfig()->verifyRecordingPath()) {
+        return;
+    }
+
+    auto activeDemods = wxGetApp().getDemodMgr().getDemodulators();
+
+    bool stateToSet = true;
+
+    for (auto i : activeDemods) {
+        if (i->isActive() && i->isRecording()) {
+            stateToSet = false;
+            break;
+        }
+    }
+
+    for (auto i : activeDemods) {
+        if (i->isActive() && i->isRecording() != stateToSet) {
+            i->setRecording(stateToSet);            
+        }
+    }
+}
+
+
 
 void AppFrame::setWaterfallLinesPerSecond(int lps) {
     waterfallSpeedMeter->setUserInputValue(sqrt(lps));
@@ -2573,7 +3004,7 @@ void AppFrame::setViewState(long long center_freq, int bandwidth) {
     waterfallCanvas->setView(center_freq, bandwidth);
 }
 
-void AppFrame::setViewState(long long center_freq) {
+void AppFrame::setViewState() {
     spectrumCanvas->setCenterFrequency(wxGetApp().getFrequency());
     waterfallCanvas->setCenterFrequency(wxGetApp().getFrequency());
     spectrumCanvas->disableView();
@@ -2597,17 +3028,21 @@ std::vector<std::string> str_explode(const std::string &seperator, const std::st
 {
     std::vector<std::string> vect_out;
     
-    int i = 0, j = 0;
-    int seperator_len = seperator.length();
-    int str_len = in_str.length();
+    size_t i = 0, j = 0;
+    size_t seperator_len = seperator.length();
+    size_t str_len = in_str.length();
     
     while(i < str_len)
     {
         j = in_str.find_first_of(seperator,i);
         
-        if (j == std::string::npos && i < str_len)  j = str_len;
+        if (j == std::string::npos && i < str_len) {
+            j = str_len;
+        }
         
-        if (j == std::string::npos) break;
+        if (j == std::string::npos) {
+            break;
+        }
         
         vect_out.push_back(in_str.substr(i,j-i));
         
@@ -2640,3 +3075,19 @@ void AppFrame::setStatusText(std::string statusText, int value) {
     GetStatusBar()->SetStatusText(
         wxString::Format(statusText.c_str(), wxNumberFormatter::ToString((long)value, wxNumberFormatter::Style_WithThousandsSep)));
 }
+
+wxString AppFrame::getSettingsLabel(const std::string& settingsName,
+                                    const std::string& settingsValue,
+                                    const std::string& settingsSuffix) {
+
+    size_t itemStringSize = 30;
+    int justifValueSize = itemStringSize - settingsName.length() - 1;
+
+    std::stringstream full_label;
+    
+    full_label << settingsName + " : ";
+    full_label << std::right << std::setw(justifValueSize);
+    full_label << settingsValue + " " + settingsSuffix;
+   
+    return wxString(full_label.str());
+}
diff --git a/src/AppFrame.h b/src/AppFrame.h
index 2f656f3..03344ae 100644
--- a/src/AppFrame.h
+++ b/src/AppFrame.h
@@ -26,7 +26,8 @@
 #include "FrequencyDialog.h"
 #include "BookmarkView.h"
 #include "AboutDialog.h"
-
+#include "DemodulatorInstance.h"
+#include "DemodulatorThread.h"
 #include <map>
 
 #define wxID_RT_AUDIO_DEVICE 1000
@@ -42,6 +43,11 @@
 #define wxID_SET_DB_OFFSET 2012
 #define wxID_ABOUT_CUBICSDR 2013
 
+#define wxID_OPEN_BOOKMARKS 2020
+#define wxID_SAVE_BOOKMARKS 2021
+#define wxID_SAVEAS_BOOKMARKS 2022
+#define wxID_RESET_BOOKMARKS 2023
+
 #define wxID_MAIN_SPLITTER 2050
 #define wxID_VIS_SPLITTER 2051
 #define wxID_BM_SPLITTER 2052
@@ -64,8 +70,19 @@
 
 #define wxID_SETTINGS_BASE 2300
 
+#define wxID_ANTENNA_CURRENT 2500
+#define wxID_ANTENNA_CURRENT_TX 2501
+#define wxID_ANTENNAS_BASE 2502
+
 #define wxID_DEVICE_ID 3500
 
+#define  wxID_RECORDING_PATH 8500
+#define  wxID_RECORDING_SQUELCH_BASE 8501
+#define  wxID_RECORDING_SQUELCH_SILENCE 8502
+#define  wxID_RECORDING_SQUELCH_SKIP 8503
+#define  wxID_RECORDING_SQUELCH_ALWAYS 8504
+#define  wxID_RECORDING_FILE_TIME_LIMIT 8505
+
 #define wxID_AUDIO_BANDWIDTH_BASE 9000
 #define wxID_AUDIO_DEVICE_MULTIPLIER 50
 
@@ -91,6 +108,11 @@ public:
     AppFrame();
     ~AppFrame();
 
+    wxMenu *makeFileMenu();
+   
+	wxMenu *makeRecordingMenu();
+	void updateRecordingMenu();
+
     void initDeviceParams(SDRDeviceInfo *devInfo);
     void updateDeviceParams();
 
@@ -103,19 +125,22 @@ public:
     void setMainWaterfallFFTSize(int fftSize);
     void setScopeDeviceName(std::string deviceName);
 
-    void gkNudgeLeft(DemodulatorInstance *demod, int snap);
-    void gkNudgeRight(DemodulatorInstance *demod, int snap);
+    void gkNudgeLeft(DemodulatorInstancePtr demod, int snap);
+    void gkNudgeRight(DemodulatorInstancePtr demod, int snap);
 
     int OnGlobalKeyDown(wxKeyEvent &event);
     int OnGlobalKeyUp(wxKeyEvent &event);
     
+    void toggleActiveDemodRecording();
+    void toggleAllActiveDemodRecording();
+    
     void setWaterfallLinesPerSecond(int lps);
     void setSpectrumAvgSpeed(double avg);
     
     FrequencyDialog::FrequencyDialogTarget getFrequencyDialogTarget();
     void refreshGainUI();
     void setViewState(long long center_freq, int bandwidth);
-    void setViewState(long long center_freq);
+    void setViewState();
 
     long long getViewCenterFreq();
     int getViewBandwidth();
@@ -161,8 +186,13 @@ private:
     bool actionOnMenuAudioSampleRate(wxCommandEvent& event);
     bool actionOnMenuDisplay(wxCommandEvent& event);
     bool actionOnMenuLoadSave(wxCommandEvent& event);
+	bool actionOnMenuRecording(wxCommandEvent& event);
     bool actionOnMenuRig(wxCommandEvent& event);
 
+    wxString getSettingsLabel(const std::string& settingsName, 
+                              const std::string& settingsValue, 
+                              const std::string& settingsSuffix = "");
+
     ScopeCanvas *scopeCanvas;
     SpectrumCanvas *spectrumCanvas;
     WaterfallCanvas *waterfallCanvas;
@@ -185,14 +215,26 @@ private:
     wxBoxSizer *demodTray;
     BookmarkView *bookmarkView;
     
-    DemodulatorInstance *activeDemodulator;
+    //Use a raw pointer here to prevent a dangling reference
+    DemodulatorInstance* activeDemodulator;
 
     std::vector<RtAudio::DeviceInfo> devices;
     std::map<int,RtAudio::DeviceInfo> inputDevices;
     std::map<int,RtAudio::DeviceInfo> outputDevices;
+
     std::map<int, wxMenuItem *> outputDeviceMenuItems;
     std::map<int, wxMenuItem *> sampleRateMenuItems;
+    std::map<int, wxMenuItem *> antennaMenuItems;
+    
+    //depending on context, maps the item id to wxMenuItem*,
+    //OR the submenu item id to its parent  wxMenuItem*.
+    std::map<int, wxMenuItem *> settingsMenuItems;
+    
     std::map<int, wxMenuItem *> audioSampleRateMenuItems;
+
+	//
+	std::map<int, wxMenuItem *> recordingMenuItems;
+
     std::map<int, wxMenuItem *> directSamplingMenuItems;
     wxMenuBar *menuBar;
     
@@ -201,14 +243,21 @@ private:
     wxMenuItem *agcMenuItem = nullptr;
     wxMenuItem *iqSwapMenuItem = nullptr;
     wxMenuItem *lowPerfMenuItem = nullptr;
+    wxMenu *fileMenu = nullptr;
     wxMenu *settingsMenu = nullptr;
+	wxMenu *recordingMenu = nullptr;
     
     SoapySDR::ArgInfoList settingArgs;
     int settingsIdMax;
     std::vector<long> sampleRates;
     long manualSampleRate = -1;
+
+    std::vector<std::string> antennaNames;
+
+   std::string currentTXantennaName;
     
     std::string currentSessionFile;
+	std::string currentBookmarkFile;
     
     FFTVisualDataThread *waterfallDataThread;
     
diff --git a/src/BookmarkMgr.cpp b/src/BookmarkMgr.cpp
index 7f0770e..85c4f86 100644
--- a/src/BookmarkMgr.cpp
+++ b/src/BookmarkMgr.cpp
@@ -4,6 +4,7 @@
 #include "BookmarkMgr.h"
 #include "CubicSDR.h"
 #include "DataTree.h"
+#include <wx/string.h>
 
 #define BOOKMARK_RECENTS_MAX 25
 
@@ -18,7 +19,8 @@ BookmarkMgr::BookmarkMgr() {
 //represents an empty BookMarkList that is returned by reference by some functions.
 const BookmarkList BookmarkMgr::emptyResults;
 
-void BookmarkMgr::saveToFile(std::string bookmarkFn, bool backup) {
+void BookmarkMgr::saveToFile(std::string bookmarkFn, bool backup, bool useFullpath) {
+
     DataTree s("cubicsdr_bookmarks");
     DataNode *header = s.rootNode()->newChild("header");
     header->newChild("version")->element()->set(wxString(CUBICSDR_VERSION).ToStdWstring());
@@ -48,7 +50,21 @@ void BookmarkMgr::saveToFile(std::string bookmarkFn, bool backup) {
         *group->newChild("@expanded") = (getExpandState(bmd_i.first)?std::string("true"):std::string("false"));
 
         for (auto &bm_i : bmd_i.second ) {
-            group->newChildCloneFrom("modem", bm_i->node);
+
+			//if a matching demodulator exists, use its data instead to be be saved, because output_device could have been
+			//modified by the user. So, save that "live" version instead.
+			auto matchingDemod = wxGetApp().getDemodMgr().getLastDemodulatorWith(bm_i->type,
+				bm_i->label,
+				bm_i->frequency,
+				bm_i->bandwidth);
+
+			if (matchingDemod != nullptr) {
+
+				wxGetApp().getDemodMgr().saveInstance(group->newChild("modem"), matchingDemod);
+			}
+			else {
+				group->newChildCloneFrom("modem", bm_i->node);
+			}
         }
     }
 
@@ -62,9 +78,18 @@ void BookmarkMgr::saveToFile(std::string bookmarkFn, bool backup) {
         recent_modems->newChildCloneFrom("modem", r_i->node);
     }
 
-    wxFileName saveFile(wxGetApp().getConfig()->getConfigDir(), bookmarkFn);
-    wxFileName saveFileBackup(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".backup");
-    
+	wxFileName saveFile;
+	wxFileName saveFileBackup;
+
+	if (useFullpath) {
+		saveFile.Assign(bookmarkFn);
+		saveFileBackup.Assign(bookmarkFn + ".backup");
+	}
+	else {
+		saveFile.Assign(wxGetApp().getConfig()->getConfigDir(), bookmarkFn);
+		saveFileBackup.Assign(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".backup");
+	}
+
     if (saveFile.IsDirWritable()) {
         // Hopefully leave at least a readable backup in case of failure..
         if (backup && saveFile.FileExists() && (!saveFileBackup.FileExists() || saveFileBackup.IsFileWritable())) {
@@ -74,20 +99,28 @@ void BookmarkMgr::saveToFile(std::string bookmarkFn, bool backup) {
     }
 }
 
-bool BookmarkMgr::loadFromFile(std::string bookmarkFn, bool backup) {
-    wxFileName loadFile(wxGetApp().getConfig()->getConfigDir(), bookmarkFn);
-    wxFileName failFile(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".failedload");
-    wxFileName lastLoaded(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".lastloaded");
-    wxFileName backupFile(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".backup");
+bool BookmarkMgr::loadFromFile(std::string bookmarkFn, bool backup, bool useFullpath) {
+
+	wxFileName loadFile;
+	wxFileName failFile;
+	wxFileName lastLoaded;
+	wxFileName backupFile;
+
+	if (useFullpath) {
+		loadFile.Assign(bookmarkFn);
+		failFile.Assign(bookmarkFn + ".failedload");
+		lastLoaded.Assign(bookmarkFn + ".lastloaded");
+		backupFile.Assign(bookmarkFn + ".backup");	
+	}
+	else {
+		loadFile.Assign(wxGetApp().getConfig()->getConfigDir(), bookmarkFn);
+		failFile.Assign(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".failedload");
+		lastLoaded.Assign(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".lastloaded");
+		backupFile.Assign(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".backup");
+	}
 
     DataTree s;
     bool loadStatusOk = true;
-
-    // Clear any active data
-    bmData.clear();
-    clearRecents();
-    clearRanges();
-    bmDataSorted.clear();
     
     // File exists but is not readable
     if (loadFile.FileExists() && !loadFile.IsFileReadable()) {
@@ -104,6 +137,17 @@ bool BookmarkMgr::loadFromFile(std::string bookmarkFn, bool backup) {
     if (!s.LoadFromFileXML(loadFile.GetFullPath(wxPATH_NATIVE).ToStdString())) {
         return false;
     }
+
+	//Check if it is a bookmark file, read the root node.
+	if (s.rootNode()->getName() != "cubicsdr_bookmarks") {
+		return false;
+	}
+	
+	// Clear any active data
+	bmData.clear();
+	clearRecents();
+	clearRanges();
+	bmDataSorted.clear();
     
     if (s.rootNode()->hasAnother("branches")) {
         DataNode *branches = s.rootNode()->getNext("branches");
@@ -149,7 +193,7 @@ bool BookmarkMgr::loadFromFile(std::string bookmarkFn, bool backup) {
             setExpandState(groupName, (expandState == "true"));
             while (group->hasAnother("modem")) {
                 DataNode *modem = group->getNext("modem");
-                BookmarkEntryPtr be = nodeToBookmark("modem", modem);
+                BookmarkEntryPtr be = nodeToBookmark(modem);
                 if (be) {
                     addBookmark(groupName.c_str(), be);
                 } else {
@@ -165,7 +209,7 @@ bool BookmarkMgr::loadFromFile(std::string bookmarkFn, bool backup) {
         
         while (recent_modems->hasAnother("modem")) {
             DataNode *modem = recent_modems->getNext("modem");
-            BookmarkEntryPtr be = nodeToBookmark("modem", modem);
+            BookmarkEntryPtr be = nodeToBookmark(modem);
             if (be) {
                 addRecent(be);
             } else {
@@ -194,6 +238,17 @@ bool BookmarkMgr::loadFromFile(std::string bookmarkFn, bool backup) {
     return loadStatusOk;
 }
 
+void BookmarkMgr::resetBookmarks() {
+
+	// Clear any active data
+	bmData.clear();
+	clearRecents();
+	clearRanges();
+	bmDataSorted.clear();
+
+	wxGetApp().getAppFrame()->getBookmarkView()->loadDefaultRanges();
+
+}
 
 bool BookmarkMgr::hasLastLoad(std::string bookmarkFn) {
     wxFileName lastLoaded(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".lastloaded");
@@ -205,7 +260,7 @@ bool BookmarkMgr::hasBackup(std::string bookmarkFn) {
     return backupFile.FileExists() && backupFile.IsFileReadable();
 }
 
-void BookmarkMgr::addBookmark(std::string group, DemodulatorInstance *demod) {
+void BookmarkMgr::addBookmark(std::string group, DemodulatorInstancePtr demod) {
     std::lock_guard < std::recursive_mutex > lock(busy_lock);
     
 	//Create a BookmarkEntry from demod data, saving its
@@ -360,7 +415,11 @@ bool BookmarkMgr::getExpandState(std::string groupName) {
 
 void BookmarkMgr::updateActiveList() {
 
-	std::lock_guard < std::recursive_mutex > lockData(busy_lock);
+    std::lock_guard < std::recursive_mutex > lockData(busy_lock);
+
+    if (wxGetApp().isShuttingDown()) {
+        return;
+    }
 	
 	BookmarkView *bmv = wxGetApp().getAppFrame()->getBookmarkView();
     
@@ -392,7 +451,7 @@ void BookmarkMgr::updateBookmarks(std::string group) {
 }
 
 
-void BookmarkMgr::addRecent(DemodulatorInstance *demod) {
+void BookmarkMgr::addRecent(DemodulatorInstancePtr demod) {
     std::lock_guard < std::recursive_mutex > lock(busy_lock);
 
     recents.push_back(demodToBookmarkEntry(demod));
@@ -482,7 +541,7 @@ void BookmarkMgr::clearRanges() {
 }
 
 
-BookmarkEntryPtr BookmarkMgr::demodToBookmarkEntry(DemodulatorInstance *demod) {
+BookmarkEntryPtr BookmarkMgr::demodToBookmarkEntry(DemodulatorInstancePtr demod) {
     
     BookmarkEntryPtr be(new BookmarkEntry);
     
@@ -499,7 +558,7 @@ BookmarkEntryPtr BookmarkMgr::demodToBookmarkEntry(DemodulatorInstance *demod) {
     return be;
 }
 
-BookmarkEntryPtr BookmarkMgr::nodeToBookmark(const char *name_in, DataNode *node) {
+BookmarkEntryPtr BookmarkMgr::nodeToBookmark(DataNode *node) {
     if (!node->hasAnother("frequency") || !node->hasAnother("type") || !node->hasAnother("bandwidth")) {
         return nullptr;
     }
@@ -528,26 +587,28 @@ BookmarkEntryPtr BookmarkMgr::nodeToBookmark(const char *name_in, DataNode *node
 std::wstring BookmarkMgr::getBookmarkEntryDisplayName(BookmarkEntryPtr bmEnt) {
     std::wstring dispName = bmEnt->label;
     
-    if (dispName == "") {
+    if (dispName == L"") {
         std::string freqStr = frequencyToStr(bmEnt->frequency) + " " + bmEnt->type;
-        dispName = wstring(freqStr.begin(),freqStr.end());
+
+        dispName = wxString(freqStr).ToStdWstring();
     }
     
     return dispName;
 }
 
-std::wstring BookmarkMgr::getActiveDisplayName(DemodulatorInstance *demod) {
+std::wstring BookmarkMgr::getActiveDisplayName(DemodulatorInstancePtr demod) {
     std::wstring activeName = demod->getDemodulatorUserLabel();
     
-    if (activeName == "") {
+    if (activeName == L"") {
         std::string wstr = frequencyToStr(demod->getFrequency()) + " " + demod->getDemodulatorType();
-        activeName = std::wstring(wstr.begin(),wstr.end());
+
+        activeName = wxString(wstr).ToStdWstring();
     }
     
     return activeName;
 }
 
-void BookmarkMgr::removeActive(DemodulatorInstance *demod) {
+void BookmarkMgr::removeActive(DemodulatorInstancePtr demod) {
 	
 	std::lock_guard < std::recursive_mutex > lock(busy_lock);
 
diff --git a/src/BookmarkMgr.h b/src/BookmarkMgr.h
index 5f18b69..0560a67 100644
--- a/src/BookmarkMgr.h
+++ b/src/BookmarkMgr.h
@@ -78,14 +78,17 @@ typedef std::map<std::string, bool> BookmarkExpandState;
 class BookmarkMgr {
 public:
     BookmarkMgr();
-    
-    void saveToFile(std::string bookmarkFn, bool backup = true);
-    bool loadFromFile(std::string bookmarkFn, bool backup = true);
+    //if useFullpath = false, use the application config dir.
+	//else assume bookmarkFn is a full path and use it for location.
+    void saveToFile(std::string bookmarkFn, bool backup = true, bool useFullpath = false);
+    bool loadFromFile(std::string bookmarkFn, bool backup = true, bool useFullpath = false);
+
+	void resetBookmarks();
 
     bool hasLastLoad(std::string bookmarkFn);
     bool hasBackup(std::string bookmarkFn);
 
-    void addBookmark(std::string group, DemodulatorInstance *demod);
+    void addBookmark(std::string group, DemodulatorInstancePtr demod);
     void addBookmark(std::string group, BookmarkEntryPtr be);
     void removeBookmark(std::string group, BookmarkEntryPtr be);
     void removeBookmark(BookmarkEntryPtr be);
@@ -105,13 +108,13 @@ public:
     void updateBookmarks();
     void updateBookmarks(std::string group);
 
-    void addRecent(DemodulatorInstance *demod);
+    void addRecent(DemodulatorInstancePtr demod);
     void addRecent(BookmarkEntryPtr be);
     void removeRecent(BookmarkEntryPtr be);
     const BookmarkList& getRecents();
     void clearRecents();
 
-	void removeActive(DemodulatorInstance *demod);
+	void removeActive(DemodulatorInstancePtr demod);
 
     void addRange(BookmarkRangeEntryPtr re);
     void removeRange(BookmarkRangeEntryPtr re);
@@ -119,14 +122,14 @@ public:
     void clearRanges();
 	
     static std::wstring getBookmarkEntryDisplayName(BookmarkEntryPtr bmEnt);
-    static std::wstring getActiveDisplayName(DemodulatorInstance *demod);
+    static std::wstring getActiveDisplayName(DemodulatorInstancePtr demod);
 
 protected:
 
     void trimRecents();
     
-    BookmarkEntryPtr demodToBookmarkEntry(DemodulatorInstance *demod);
-    BookmarkEntryPtr nodeToBookmark(const char *name_in, DataNode *node);
+    BookmarkEntryPtr demodToBookmarkEntry(DemodulatorInstancePtr demod);
+    BookmarkEntryPtr nodeToBookmark(DataNode *node);
     
     BookmarkMap bmData;
     BookmarkMapSorted bmDataSorted;
diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp
index 4e4931c..e6b63b1 100644
--- a/src/CubicSDR.cpp
+++ b/src/CubicSDR.cpp
@@ -32,6 +32,8 @@ IMPLEMENT_APP(CubicSDR)
 
 #include "ActionDialog.h"
 
+#include <memory>
+
 
 //#ifdef ENABLE_DIGITAL_LAB
 //// console output buffer for windows
@@ -201,6 +203,7 @@ CubicSDR::CubicSDR() : frequency(0), offset(0), ppm(0), snap(1), sampleRate(DEFA
         sampleRateInitialized.store(false);
         agcMode.store(true);
         soloMode.store(false);
+        shuttingDown.store(false);
         fdlgTarget = FrequencyDialog::FDIALOG_TARGET_DEFAULT;
         stoppedDev = nullptr;
 }
@@ -290,17 +293,17 @@ bool CubicSDR::OnInit() {
     // Visual Data
     spectrumVisualThread = new SpectrumVisualDataThread();
     
-    pipeIQVisualData = new DemodulatorThreadInputQueue();
+    pipeIQVisualData = std::make_shared<DemodulatorThreadInputQueue>();
     pipeIQVisualData->set_max_num_items(1);
     
-    pipeWaterfallIQVisualData = new DemodulatorThreadInputQueue();
+    pipeWaterfallIQVisualData = std::make_shared<DemodulatorThreadInputQueue>();
     pipeWaterfallIQVisualData->set_max_num_items(128);
     
     getSpectrumProcessor()->setInput(pipeIQVisualData);
     getSpectrumProcessor()->setHideDC(true);
     
     // I/Q Data
-    pipeSDRIQData = new SDRThreadIQDataQueue();
+    pipeSDRIQData = std::make_shared<SDRThreadIQDataQueue>();
     pipeSDRIQData->set_max_num_items(100);
     
     sdrThread = new SDRThread();
@@ -313,7 +316,7 @@ bool CubicSDR::OnInit() {
     sdrPostThread->setOutputQueue("IQDataOutput", pipeWaterfallIQVisualData);
      
 #if CUBICSDR_ENABLE_VIEW_SCOPE
-    pipeAudioVisualData = new DemodulatorThreadOutputQueue();
+    pipeAudioVisualData = std::make_shared<DemodulatorThreadOutputQueue>();
     pipeAudioVisualData->set_max_num_items(1);
     
     scopeProcessor.setInput(pipeAudioVisualData);
@@ -323,7 +326,7 @@ bool CubicSDR::OnInit() {
     
 #if CUBICSDR_ENABLE_VIEW_DEMOD
     demodVisualThread = new SpectrumVisualDataThread();
-    pipeDemodIQVisualData = new DemodulatorThreadInputQueue();
+    pipeDemodIQVisualData = std::make_shared<DemodulatorThreadInputQueue>();
     pipeDemodIQVisualData->set_max_num_items(1);
     
     if (getDemodSpectrumProcessor()) {
@@ -382,49 +385,81 @@ bool CubicSDR::OnInit() {
 }
 
 int CubicSDR::OnExit() {
+    shuttingDown.store(true);
+
 #if USE_HAMLIB
     if (rigIsActive()) {
-        std::cout << "Terminating Rig thread.." << std::endl;
+        std::cout << "Terminating Rig thread.."  << std::endl << std::flush;
         stopRig();
     }
 #endif
 
+    bool terminationSequenceOK = true;
+
     //The thread feeding them all should be terminated first, so: 
-    std::cout << "Terminating SDR thread.." << std::endl;
+    std::cout << "Terminating SDR thread.." << std::endl << std::flush ;
     sdrThread->terminate();
-    sdrThread->isTerminated(3000);
-   
-    if (t_SDR) {
-       t_SDR->join();
-       delete t_SDR;
-       t_SDR = nullptr;
+    terminationSequenceOK = terminationSequenceOK && sdrThread->isTerminated(3000);
+
+    //in case termination sequence goes wrong, kill App brutally now because it can get stuck. 
+    if (!terminationSequenceOK) {
+        //no trace here because it could occur if the device is not started.  
+        ::exit(11);
     }
 
-    std::cout << "Terminating SDR post-processing thread.." << std::endl;
+    std::cout << "Terminating SDR post-processing thread.." << std::endl << std::flush;
     sdrPostThread->terminate();
 
-    std::cout << "Terminating All Demodulators.." << std::endl;
+    //Wait for termination for sdrPostThread second:: since it is doing
+    //mostly blocking push() to the other threads, they must stay alive
+    //so that sdrPostThread can complete a processing loop and die.
+    terminationSequenceOK = terminationSequenceOK && sdrPostThread->isTerminated(3000);
+
+    //in case termination sequence goes wrong, kill App brutally now because it can get stuck. 
+    if (!terminationSequenceOK) {
+        std::cout << "Cannot terminate application properly, calling exit() now." << std::endl << std::flush;
+        ::exit(12);
+    }
+
+    std::cout << "Terminating All Demodulators.." << std::endl << std::flush;
     demodMgr.terminateAll();
-   
-    std::cout << "Terminating Visual Processor threads.." << std::endl;
+
+    std::cout << "Terminating Visual Processor threads.." << std::endl << std::flush;
     spectrumVisualThread->terminate();
     if (demodVisualThread) {
         demodVisualThread->terminate();
     }
     
     //Wait nicely
-    sdrPostThread->isTerminated(1000);
-    spectrumVisualThread->isTerminated(1000);
+    terminationSequenceOK = terminationSequenceOK &&  spectrumVisualThread->isTerminated(1000);
+
     if (demodVisualThread) {
-        demodVisualThread->isTerminated(1000);
+        terminationSequenceOK = terminationSequenceOK && demodVisualThread->isTerminated(1000);
+    }
+
+    //in case termination sequence goes wrong, kill App brutally because it can get stuck. 
+    if (!terminationSequenceOK) {
+        std::cout << "Cannot terminate application properly, calling exit() now." << std::endl << std::flush;
+        ::exit(13);
+    }
+
+    //Then join the thread themselves:
+    if (t_SDR) {
+        t_SDR->join();
     }
 
-    //Then join the thread themselves
     t_PostSDR->join();
-    if (t_DemodVisual) t_DemodVisual->join();
+    
+    if (t_DemodVisual) {
+        t_DemodVisual->join();
+    }
+    
     t_SpectrumVisual->join();
 
-    //Now only we can delete
+    //Now only we can delete:
+    delete t_SDR;
+    t_SDR = nullptr;
+
     delete sdrThread;
     sdrThread = nullptr;
 
@@ -445,19 +480,12 @@ int CubicSDR::OnExit() {
 
     delete demodVisualThread;
     demodVisualThread = nullptr;
-    
-    delete pipeIQVisualData;
-    pipeIQVisualData = nullptr;
-
-    delete pipeAudioVisualData;
-    pipeAudioVisualData = nullptr;
-
-    delete pipeSDRIQData;
-    pipeSDRIQData = nullptr;
 
     delete m_glContext;
     m_glContext = nullptr;
 
+    std::cout << "Application termination complete." << std::endl << std::flush;
+
 #ifdef __APPLE__
     AudioThread::deviceCleanup();
 #endif
@@ -601,9 +629,22 @@ long long CubicSDR::getOffset() {
 
 void CubicSDR::setOffset(long long ofs) {
     offset = ofs;
-    sdrThread->setOffset(offset);
-    SDRDeviceInfo *dev = getDevice();
-    config.getDevice(dev->getDeviceId())->setOffset(ofs);
+    
+    if (sdrThread && !sdrThread->isTerminated()) {
+        sdrThread->setOffset(offset);
+    }
+}
+
+void CubicSDR::setAntennaName(const std::string& name) {
+    antennaName = name;
+     
+    if (sdrThread && !sdrThread->isTerminated()) {
+        sdrThread->setAntenna(antennaName);
+    }
+}
+
+const std::string& CubicSDR::getAntennaName() {
+    return antennaName;
 }
 
 long long CubicSDR::getFrequency() {
@@ -626,12 +667,18 @@ bool CubicSDR::isFrequencyLocked() {
 
 void CubicSDR::unlockFrequency() {
     frequency_locked.store(false);
-    sdrThread->unlockFrequency();
+    if (sdrThread && !sdrThread->isTerminated()) {
+        sdrThread->unlockFrequency();
+    }
 }
 
 void CubicSDR::setSampleRate(long long rate_in) {
     sampleRate = rate_in;
-    sdrThread->setSampleRate(sampleRate);
+    
+    if (sdrThread && !sdrThread->isTerminated()) {
+        sdrThread->setSampleRate(sampleRate);
+    }
+
     setFrequency(frequency);
 
     if (rate_in <= CHANNELIZER_RATE_MAX / 8) {
@@ -722,13 +769,8 @@ void CubicSDR::setDevice(SDRDeviceInfo *dev, int waitMsForTermination) {
 
         setPPM(devConfig->getPPM());
         setOffset(devConfig->getOffset());
-        
-
-        if (devConfig->getAGCMode()) {
-            setAGCMode(true);
-        } else {
-            setAGCMode(false);
-        }
+        setAGCMode(devConfig->getAGCMode());
+        setAntennaName(devConfig->getAntennaName());
 
         t_SDR = new std::thread(&SDRThread::threadMain, sdrThread);
 }
@@ -760,15 +802,15 @@ SpectrumVisualProcessor *CubicSDR::getDemodSpectrumProcessor() {
     }
 }
 
-DemodulatorThreadOutputQueue* CubicSDR::getAudioVisualQueue() {
+DemodulatorThreadOutputQueuePtr CubicSDR::getAudioVisualQueue() {
     return pipeAudioVisualData;
 }
 
-DemodulatorThreadInputQueue* CubicSDR::getIQVisualQueue() {
+DemodulatorThreadInputQueuePtr CubicSDR::getIQVisualQueue() {
     return pipeIQVisualData;
 }
 
-DemodulatorThreadInputQueue* CubicSDR::getWaterfallVisualQueue() {
+DemodulatorThreadInputQueuePtr CubicSDR::getWaterfallVisualQueue() {
     return pipeWaterfallIQVisualData;
 }
 
@@ -789,30 +831,21 @@ SDRThread *CubicSDR::getSDRThread() {
 }
 
 
-void CubicSDR::bindDemodulator(DemodulatorInstance *demod) {
-    if (!demod) {
-        return;
-    }
-    sdrPostThread->bindDemodulator(demod);
-}
-
-void CubicSDR::bindDemodulators(std::vector<DemodulatorInstance *> *demods) {
-    if (!demods) {
-        return;
-    }
-    sdrPostThread->bindDemodulators(demods);
+void CubicSDR::notifyDemodulatorsChanged() {
+    
+    sdrPostThread->notifyDemodulatorsChanged();
 }
 
 long long CubicSDR::getSampleRate() {
     return sampleRate;
 }
 
-void CubicSDR::removeDemodulator(DemodulatorInstance *demod) {
+void CubicSDR::removeDemodulator(DemodulatorInstancePtr demod) {
     if (!demod) {
         return;
     }
     demod->setActive(false);
-    sdrPostThread->removeDemodulator(demod);
+    sdrPostThread->notifyDemodulatorsChanged();
     wxGetApp().getAppFrame()->notifyUpdateModemProperties();
 }
 
@@ -831,11 +864,8 @@ void CubicSDR::saveConfig() {
 
 void CubicSDR::setPPM(int ppm_in) {
     ppm = ppm_in;
-    sdrThread->setPPM(ppm);
-
-    SDRDeviceInfo *dev = getDevice();
-    if (dev) {
-        config.getDevice(dev->getDeviceId())->setPPM(ppm_in);
+    if (sdrThread && !sdrThread->isTerminated()) {
+        sdrThread->setPPM(ppm);
     }
 }
 
@@ -887,7 +917,7 @@ void CubicSDR::showFrequencyInput(FrequencyDialog::FrequencyDialogTarget targetM
 
 void CubicSDR::showLabelInput() {
 
-    DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getActiveDemodulator();
+    DemodulatorInstancePtr activeDemod = wxGetApp().getDemodMgr().getActiveDemodulator();
 
     if (activeDemod != nullptr) {
 
@@ -917,8 +947,12 @@ bool CubicSDR::areDevicesReady() {
     return devicesReady.load();
 }
 
-void CubicSDR::notifyMainUIOfDeviceChange() {
+void CubicSDR::notifyMainUIOfDeviceChange(bool forceRefreshOfGains) {
     appframe->notifyDeviceChanged();
+
+	if (forceRefreshOfGains) {
+		appframe->refreshGainUI();
+	}
 }
 
 bool CubicSDR::areDevicesEnumerating() {
@@ -947,7 +981,10 @@ bool CubicSDR::isDeviceSelectorOpen() {
 
 void CubicSDR::setAGCMode(bool mode) {
     agcMode.store(mode);
-    sdrThread->setAGCMode(mode);
+
+    if (sdrThread && !sdrThread->isTerminated()) {
+        sdrThread->setAGCMode(mode);
+    }
 }
 
 bool CubicSDR::getAGCMode() {
@@ -995,6 +1032,11 @@ bool CubicSDR::getSoloMode() {
     return soloMode.load();
 }
 
+bool CubicSDR::isShuttingDown()
+{
+    return shuttingDown.load();
+}
+
 int CubicSDR::FilterEvent(wxEvent& event) {
     if (!appframe) {
         return -1;
diff --git a/src/CubicSDR.h b/src/CubicSDR.h
index 3dbbbc4..d097829 100644
--- a/src/CubicSDR.h
+++ b/src/CubicSDR.h
@@ -91,6 +91,9 @@ public:
 
     void setOffset(long long ofs);
     long long getOffset();
+
+    void setAntennaName(const std::string& name);
+    const std::string& getAntennaName();
     
     void setDBOffset(int ofs);
     int getDBOffset();
@@ -98,6 +101,7 @@ public:
     void setSampleRate(long long rate_in);
     long long getSampleRate();
 
+   
     std::vector<SDRDeviceInfo *> *getDevices();
     void setDevice(SDRDeviceInfo *dev, int waitMsForTermination);
     void stopDevice(bool store, int waitMsForTermination);
@@ -107,19 +111,19 @@ public:
     SpectrumVisualProcessor *getSpectrumProcessor();
     SpectrumVisualProcessor *getDemodSpectrumProcessor();
     
-    DemodulatorThreadOutputQueue* getAudioVisualQueue();
-    DemodulatorThreadInputQueue* getIQVisualQueue();
-    DemodulatorThreadInputQueue* getWaterfallVisualQueue();
-    DemodulatorThreadInputQueue* getActiveDemodVisualQueue();
+    DemodulatorThreadOutputQueuePtr getAudioVisualQueue();
+    DemodulatorThreadInputQueuePtr getIQVisualQueue();
+    DemodulatorThreadInputQueuePtr getWaterfallVisualQueue();
+    DemodulatorThreadInputQueuePtr getActiveDemodVisualQueue();
     DemodulatorMgr &getDemodMgr();
     BookmarkMgr &getBookmarkMgr();
 
     SDRPostThread *getSDRPostThread();
     SDRThread *getSDRThread();
 
-    void bindDemodulator(DemodulatorInstance *demod);
-    void bindDemodulators(std::vector<DemodulatorInstance *> *demods);
-    void removeDemodulator(DemodulatorInstance *demod);
+    void notifyDemodulatorsChanged();
+   
+    void removeDemodulator(DemodulatorInstancePtr demod);
 
     void setFrequencySnap(int snap);
     int getFrequencySnap();
@@ -139,7 +143,7 @@ public:
     bool areModulesMissing();
     std::string getNotification();
 
-    void notifyMainUIOfDeviceChange();
+    void notifyMainUIOfDeviceChange(bool forceRefreshOfGains = false);
     
     void addRemote(std::string remoteAddr);
     void removeRemote(std::string remoteAddr);
@@ -166,6 +170,8 @@ public:
 
     void setSoloMode(bool solo);
     bool getSoloMode();
+
+    bool isShuttingDown();
     
 #ifdef USE_HAMLIB
     RigThread *getRigThread();
@@ -189,7 +195,9 @@ private:
     std::atomic_llong offset;
     std::atomic_int ppm, snap;
     std::atomic_llong sampleRate;
+    std::string antennaName;
     std::atomic_bool agcMode;
+    std::atomic_bool shuttingDown;
 
     SDRThread *sdrThread = nullptr;
     SDREnumerator *sdrEnum = nullptr;
@@ -197,12 +205,12 @@ private:
     SpectrumVisualDataThread *spectrumVisualThread = nullptr;
     SpectrumVisualDataThread *demodVisualThread = nullptr;
 
-    SDRThreadIQDataQueue* pipeSDRIQData = nullptr;
-    DemodulatorThreadInputQueue* pipeIQVisualData = nullptr;
-    DemodulatorThreadOutputQueue* pipeAudioVisualData = nullptr;
-    DemodulatorThreadInputQueue* pipeDemodIQVisualData = nullptr;
-    DemodulatorThreadInputQueue* pipeWaterfallIQVisualData = nullptr;
-    DemodulatorThreadInputQueue* pipeActiveDemodIQVisualData = nullptr;
+    SDRThreadIQDataQueuePtr pipeSDRIQData;
+    DemodulatorThreadInputQueuePtr pipeIQVisualData;
+    DemodulatorThreadOutputQueuePtr pipeAudioVisualData;
+    DemodulatorThreadInputQueuePtr pipeDemodIQVisualData;
+    DemodulatorThreadInputQueuePtr pipeWaterfallIQVisualData;
+    DemodulatorThreadInputQueuePtr pipeActiveDemodIQVisualData;
 
     ScopeVisualProcessor scopeProcessor;
     
diff --git a/src/CubicSDRDefs.h b/src/CubicSDRDefs.h
index e5cc4ca..3beb96b 100644
--- a/src/CubicSDRDefs.h
+++ b/src/CubicSDRDefs.h
@@ -59,3 +59,7 @@ const char filePathSeparator =
 
 //Represents the amount of time to process in the FFT distributor. 
 #define FFT_DISTRIBUTOR_BUFFER_IN_SECONDS 0.250
+
+//The maximum number of listed sample rates for a device, to be able to handle 
+//devices returning an insane amount because they have quasi-continuous ranges (UHD...)
+#define DEVICE_SAMPLE_RATES_MAX_NB     25
\ No newline at end of file
diff --git a/src/DemodLabelDialog.cpp b/src/DemodLabelDialog.cpp
index 251c356..139793f 100644
--- a/src/DemodLabelDialog.cpp
+++ b/src/DemodLabelDialog.cpp
@@ -13,7 +13,7 @@ EVT_SHOW(DemodLabelDialog::OnShow)
 wxEND_EVENT_TABLE()
 
 DemodLabelDialog::DemodLabelDialog(wxWindow * parent, wxWindowID id, const wxString & title, 
-        DemodulatorInstance *demod, const wxPoint & position,
+        DemodulatorInstancePtr demod, const wxPoint & position,
         const wxSize & size, long style) :
         wxDialog(parent, id, title, position, size, style) {
 
diff --git a/src/DemodLabelDialog.h b/src/DemodLabelDialog.h
index cee9cff..ab13aa9 100644
--- a/src/DemodLabelDialog.h
+++ b/src/DemodLabelDialog.h
@@ -16,7 +16,7 @@ class DemodLabelDialog : public wxDialog
 public:
   
     DemodLabelDialog( wxWindow * parent, wxWindowID id, const wxString & title,
-                  DemodulatorInstance *demod = NULL,
+                  DemodulatorInstancePtr demod = nullptr,
                   const wxPoint & pos = wxDefaultPosition,
                   const wxSize & size = wxDefaultSize,
                   long style = wxDEFAULT_DIALOG_STYLE);
@@ -24,7 +24,7 @@ public:
     wxTextCtrl * dialogText;
 
 private:
-    DemodulatorInstance *activeDemod = nullptr;
+    DemodulatorInstancePtr activeDemod = nullptr;
     void OnEnter ( wxCommandEvent &event );
     void OnChar ( wxKeyEvent &event );
 	void OnShow(wxShowEvent &event);
diff --git a/src/FrequencyDialog.cpp b/src/FrequencyDialog.cpp
index f16ad3b..a272d4c 100644
--- a/src/FrequencyDialog.cpp
+++ b/src/FrequencyDialog.cpp
@@ -12,11 +12,13 @@ EVT_CHAR_HOOK(FrequencyDialog::OnChar)
 EVT_SHOW(FrequencyDialog::OnShow)
 wxEND_EVENT_TABLE()
 
-FrequencyDialog::FrequencyDialog(wxWindow * parent, wxWindowID id, const wxString & title, DemodulatorInstance *demod, const wxPoint & position,
+FrequencyDialog::FrequencyDialog(wxWindow * parent, wxWindowID id, const wxString & title, DemodulatorInstancePtr demod, const wxPoint & position,
         const wxSize & size, long style, FrequencyDialogTarget targetMode, wxString initString) :
         wxDialog(parent, id, title, position, size, style) {
     wxString freqStr;
+    
     activeDemod = demod;
+    
     this->targetMode = targetMode;
 	this->initialString = initString;
 
@@ -53,7 +55,7 @@ FrequencyDialog::FrequencyDialog(wxWindow * parent, wxWindowID id, const wxStrin
             
     dialogText = new wxTextCtrl(this, wxID_FREQ_INPUT, freqStr, wxPoint(6, 1), wxSize(size.GetWidth() - 20, size.GetHeight() - 70),
     wxTE_PROCESS_ENTER);
-    dialogText->SetFont(wxFont(20, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD));
+    dialogText->SetFont(wxFont(15, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD));
 
     Centre();
 
@@ -122,7 +124,7 @@ void FrequencyDialog::OnChar(wxKeyEvent& event) {
                     }
                     if (freq == freq2) {
                         wxGetApp().setFrequency(freq_ctr);
-                        wxGetApp().getAppFrame()->setViewState(freq_ctr);
+                        wxGetApp().getAppFrame()->setViewState();
                     } else {
                         if (wxGetApp().getSampleRate()/4 > range_bw) {
                             wxGetApp().setFrequency(freq_ctr + wxGetApp().getSampleRate()/4);
diff --git a/src/FrequencyDialog.h b/src/FrequencyDialog.h
index 259de20..6d260b9 100644
--- a/src/FrequencyDialog.h
+++ b/src/FrequencyDialog.h
@@ -24,7 +24,7 @@ public:
         FDIALOG_TARGET_GAIN
     } FrequencyDialogTarget;
     FrequencyDialog ( wxWindow * parent, wxWindowID id, const wxString & title,
-                  DemodulatorInstance *demod = NULL,
+                  DemodulatorInstancePtr demod = nullptr,
                   const wxPoint & pos = wxDefaultPosition,
                   const wxSize & size = wxDefaultSize,
                   long style = wxDEFAULT_DIALOG_STYLE,
@@ -34,7 +34,7 @@ public:
     wxTextCtrl * dialogText;
 
 private:
-    DemodulatorInstance *activeDemod;
+    DemodulatorInstancePtr activeDemod;
     void OnEnter ( wxCommandEvent &event );
     void OnChar ( wxKeyEvent &event );
 	void OnShow(wxShowEvent &event);
diff --git a/src/IOThread.cpp b/src/IOThread.cpp
index 029fe73..5d78b64 100644
--- a/src/IOThread.cpp
+++ b/src/IOThread.cpp
@@ -3,9 +3,7 @@
 
 #include "IOThread.h"
 #include <typeinfo>
-
-std::mutex ReBufferGC::g_mutex;
-std::set<ReferenceCounter *> ReBufferGC::garbage;
+#include <memory>
 
 #define SPIN_WAIT_SLEEP_MS 5
 
@@ -71,32 +69,32 @@ void IOThread::terminate() {
     stopping.store(true);
 };
 
-void IOThread::onBindOutput(std::string /* name */, ThreadQueueBase* /* threadQueue */) {
+void IOThread::onBindOutput(std::string /* name */, ThreadQueueBasePtr /* threadQueue */) {
    
 };
 
-void IOThread::onBindInput(std::string /* name */, ThreadQueueBase* /* threadQueue */) {
+void IOThread::onBindInput(std::string /* name */, ThreadQueueBasePtr /* threadQueue */) {
     
 };
 
-void IOThread::setInputQueue(std::string qname, ThreadQueueBase *threadQueue) {
+void IOThread::setInputQueue(std::string qname, ThreadQueueBasePtr threadQueue) {
     std::lock_guard < std::mutex > lock(m_queue_bindings_mutex);
     input_queues[qname] = threadQueue;
     this->onBindInput(qname, threadQueue);
 };
 
-ThreadQueueBase *IOThread::getInputQueue(std::string qname) {
+ThreadQueueBasePtr IOThread::getInputQueue(std::string qname) {
     std::lock_guard < std::mutex > lock(m_queue_bindings_mutex);
     return input_queues[qname];
 };
 
-void IOThread::setOutputQueue(std::string qname, ThreadQueueBase *threadQueue) {
+void IOThread::setOutputQueue(std::string qname, ThreadQueueBasePtr threadQueue) {
     std::lock_guard < std::mutex > lock(m_queue_bindings_mutex);
     output_queues[qname] = threadQueue;
     this->onBindOutput(qname, threadQueue);
 };
 
-ThreadQueueBase *IOThread::getOutputQueue(std::string qname) {
+ThreadQueueBasePtr IOThread::getOutputQueue(std::string qname) {
     std::lock_guard < std::mutex > lock(m_queue_bindings_mutex);
     return output_queues[qname];
 };
@@ -130,7 +128,7 @@ bool IOThread::isTerminated(int waitMs) {
         }
     }
 
-    std::cout << "ERROR: thread '" << typeid(*this).name() << "' has not terminated in time ! (> " << waitMs << " ms)" << std::endl;
+    std::cout << "ERROR: thread '" << typeid(*this).name() << "' has not terminated in time ! (> " << waitMs << " ms)" << std::endl << std::flush;
 
     return terminated.load();
 }
diff --git a/src/IOThread.h b/src/IOThread.h
index 46ce897..20455f3 100644
--- a/src/IOThread.h
+++ b/src/IOThread.h
@@ -11,7 +11,8 @@
 #include <string>
 #include <iostream>
 #include <thread>
-
+#include <memory>
+#include <climits>
 #include "ThreadBlockingQueue.h"
 #include "Timer.h"
 
@@ -23,163 +24,135 @@ struct map_string_less : public std::binary_function<std::string,std::string,boo
     }
 };
 
-
-class ReferenceCounter {
-
+template <typename PtrType>
+class ReBufferAge {
 public:
 
-    //default constructor, initialized with refcont 1, sounds very natural
-    ReferenceCounter() {
-        refCount = 1;
-    }
-    
-//    void setIndex(int idx) {
-//        std::lock_guard < std::recursive_mutex > lock(m_mutex);
-//        index = idx;
-//    }
-
-//    int getIndex() {
-//        std::lock_guard < std::recursive_mutex > lock(m_mutex);
-//        return index;
-//    }
-
-    void setRefCount(int rc) {
-        std::lock_guard < std::recursive_mutex > lock(m_mutex);
-        refCount = rc;
-    }
-    
-    void decRefCount() {
-        std::lock_guard < std::recursive_mutex > lock(m_mutex);
-        refCount--;
-    }
-    
-    int getRefCount() {
-        std::lock_guard < std::recursive_mutex > lock(m_mutex);
-        return refCount;
-    }
-
-    // Access to the own mutex protecting the ReferenceCounter, i.e the monitor of the class
-     std::recursive_mutex& getMonitor() const {
-        return m_mutex;
+    ReBufferAge(PtrType p, int a) {
+        ptr = p;
+        age = a;
     }
 
-protected:
-    //this is a basic mutex for all ReferenceCounter derivatives operations INCLUDING the counter itself for consistency !
-   mutable std::recursive_mutex m_mutex;
+    PtrType ptr;
+    int age;
 
-private:
-   int refCount;
-//   int index;
+    virtual ~ReBufferAge() {};
 };
 
-
 #define REBUFFER_GC_LIMIT 100
+#define REBUFFER_WARNING_THRESHOLD 150
 
-class ReBufferGC {
-public:
-    static void garbageCollect() {
-        std::lock_guard < std::mutex > lock(g_mutex);
-        
-        std::deque<ReferenceCounter *> garbageRemoval;
-        for (typename std::set<ReferenceCounter *>::iterator i = garbage.begin(); i != garbage.end(); i++) {
-            if ((*i)->getRefCount() <= 0) {
-                garbageRemoval.push_back(*i);
-            }
-            else {
-//                std::cout << "Garbage in queue buffer idx #" << (*i)->getIndex() << ", " << (*i)->getRefCount() << " usage(s)" << std::endl;
-                std::cout << "Garbage in queue buffer with " << (*i)->getRefCount() << " usage(s)" << std::endl;
-            }
-        }
-        if ( garbageRemoval.size() ) {
-            std::cout << "Garbage collecting " << garbageRemoval.size() << " ReBuffer(s)" << std::endl;
-            while (!garbageRemoval.empty()) {
-                ReferenceCounter *ref = garbageRemoval.back();
-                garbageRemoval.pop_back();
-                garbage.erase(ref);
-                delete ref;
-            }
-        }
-    }
-    
-    static void addGarbage(ReferenceCounter *ref) {
-        std::lock_guard < std::mutex > lock(g_mutex);
-        garbage.insert(ref);
-    }
-    
-private:
-    static std::mutex g_mutex;
-    static std::set<ReferenceCounter *> garbage;
-};
-
-
-template<class BufferType = ReferenceCounter>
+template<typename BufferType>
 class ReBuffer {
     
+    typedef typename std::shared_ptr<BufferType> ReBufferPtr;
+   
 public:
+
+	//Virtual destructor to assure correct freeing of all descendants.
+	virtual ~ReBuffer() {
+		//nothing
+	}
+
+	//constructor
     ReBuffer(std::string bufferId) : bufferId(bufferId) {
-//        indexCounter.store(0);
+		//nothing
     }
     
-    BufferType *getBuffer() {
+    /// Return a new ReBuffer_ptr usable by the application.
+    ReBufferPtr getBuffer() {
+
         std::lock_guard < std::mutex > lock(m_mutex);
 
-        BufferType* buf = nullptr;
-        for (outputBuffersI = outputBuffers.begin(); outputBuffersI != outputBuffers.end(); outputBuffersI++) {
-            if (buf == nullptr && (*outputBuffersI)->getRefCount() <= 0) {
-                buf = (*outputBuffersI);
-                buf->setRefCount(1);
-            } else if ((*outputBuffersI)->getRefCount() <= 0) {
-                (*outputBuffersI)->decRefCount();
+        // iterate the ReBufferAge list: if the std::shared_ptr count == 1, it means 
+        //it is only referenced in outputBuffers itself, so available for re-use.
+        //else if the std::shared_ptr count <= 1, make it age.
+        //else the ReBufferPtr is in use, don't use it.
+
+        ReBufferPtr buf = nullptr;
+
+        outputBuffersI it = outputBuffers.begin();
+
+       while (it != outputBuffers.end()) {
+
+           //careful here: take care of reading the use_count directly
+           //through the iterator, else it's value is wrong if a temp variable 
+           //is used.
+           long use = it->ptr.use_count();
+
+            //1. If we encounter a ReBufferPtr with a use count of 0, this
+            //is a bug since it is supposed to be at least 1, because it is referenced here.
+            //in this case, purge it from here and trace.
+            if (use == 0) {
+                std::cout << "Warning: in ReBuffer '" << bufferId << "' count '" << outputBuffers.size() << "', found 1 dangling buffer !" << std::endl << std::flush;
+                it = outputBuffers.erase(it);    
+            } 
+            else if (use == 1) {
+                if (buf == nullptr) {
+                    it->age = 1;  //select this one.
+                    buf = it->ptr;
+                    // std::cout << "**" << std::flush;
+                    it++;
+                }
+                else {
+                    //make the other unused buffers age
+                    it->age--;
+                    it++;
+                }
             }
-        }
-        
-        if (buf != nullptr) {
-            if (outputBuffers.back()->getRefCount() < -REBUFFER_GC_LIMIT) {
-                BufferType *ref = outputBuffers.back();
+            else {
+                it++;
+            }
+        } //end while
+
+       //2.1 Garbage collect the oldest (last element) if it aged too much, and return the buffer
+       if (buf != nullptr) {
+            
+           if (outputBuffers.back().age < -REBUFFER_GC_LIMIT) {
+                //by the nature of the shared_ptr, memory will ne deallocated automatically.           
                 outputBuffers.pop_back();
-                delete ref;
+                //std::cout << "--" << std::flush;
             }
-//            buf->setIndex(indexCounter++);
             return buf;
         }
-        
-#define REBUFFER_WARNING_THRESHOLD 100
+
         if (outputBuffers.size() > REBUFFER_WARNING_THRESHOLD) {
-            std::cout << "Warning: ReBuffer '" << bufferId << "' count '" << outputBuffers.size() << "' exceeds threshold of '" << REBUFFER_WARNING_THRESHOLD << "'" << std::endl;
+            std::cout << "Warning: ReBuffer '" << bufferId << "' count '" << outputBuffers.size() << "' exceeds threshold of '" << REBUFFER_WARNING_THRESHOLD << "'" << std::endl << std::flush;
         }
-
-        //by default created with refcount = 1
-        buf = new BufferType();
-//        buf->setIndex(indexCounter++);
-        outputBuffers.push_back(buf);
         
-        return buf;
+        //3.We need to allocate a new buffer. 
+        ReBufferAge < ReBufferPtr > newBuffer(std::make_shared<BufferType>(), 1);
+
+        outputBuffers.push_back(newBuffer);
+
+        // std::cout << "++" << std::flush;
+        return newBuffer.ptr;
     }
     
+    /// Purge the cache.
     void purge() {
         std::lock_guard < std::mutex > lock(m_mutex);
-//        if (bufferId == "DemodulatorThreadBuffers") {
-//            std::cout << "'" << bufferId << "' purging.. total indexes: " << indexCounter.load() << std::endl;
-//        }
-        while (!outputBuffers.empty()) {
-            BufferType *ref = outputBuffers.front();
-            outputBuffers.pop_front();
-            if (ref->getRefCount() <= 0) {
-                delete ref;
-            } else {
-                // Something isn't done with it yet; throw it on the pile.. keep this as a bug indicator for now..
-                std::cout << "'" << bufferId << "' pushed garbage.." << std::endl;
-                ReBufferGC::addGarbage(ref);
-            }
-        }
+
+        // since outputBuffers are full std::shared_ptr,
+        //purging if will effectively loose the local reference,
+        // so the std::shared_ptr will naturally be deallocated
+        //when their time comes.  
+        outputBuffers.clear();
     }
 
-   private:
+private:
+
+    //name of the buffer cache kind
     std::string bufferId;
-    std::deque<BufferType*> outputBuffers;
-    typename std::deque<BufferType*>::iterator outputBuffersI;
-    mutable std::mutex m_mutex;
-//    std::atomic_int indexCounter;
+    
+    //the ReBuffer cache: use a std:deque to also release
+    //memory when ReBufferPtr are GCed.
+    std::deque< ReBufferAge < ReBufferPtr > > outputBuffers;
+
+    typedef typename std::deque< ReBufferAge < ReBufferPtr > >::iterator outputBuffersI;
+
+    //mutex protecting access to outputBuffers.
+    std::mutex m_mutex;
 };
 
 
@@ -210,20 +183,20 @@ public:
     //If wait < 0, the wait in infinite until the thread dies.
     bool isTerminated(int waitMs = 0);
     
-    virtual void onBindOutput(std::string name, ThreadQueueBase* threadQueue);
-    virtual void onBindInput(std::string name, ThreadQueueBase* threadQueue);
+    virtual void onBindOutput(std::string name, ThreadQueueBasePtr threadQueue);
+    virtual void onBindInput(std::string name, ThreadQueueBasePtr threadQueue);
 
-    void setInputQueue(std::string qname, ThreadQueueBase *threadQueue);
-    ThreadQueueBase *getInputQueue(std::string qname);
-    void setOutputQueue(std::string qname, ThreadQueueBase *threadQueue);
-    ThreadQueueBase *getOutputQueue(std::string qname);
+    void setInputQueue(std::string qname, ThreadQueueBasePtr threadQueue);
+    ThreadQueueBasePtr getInputQueue(std::string qname);
+    void setOutputQueue(std::string qname, ThreadQueueBasePtr threadQueue);
+    ThreadQueueBasePtr getOutputQueue(std::string qname);
     
 protected:
-    std::map<std::string, ThreadQueueBase *, map_string_less> input_queues;
-    std::map<std::string, ThreadQueueBase *, map_string_less> output_queues;
+    std::map<std::string, ThreadQueueBasePtr, map_string_less> input_queues;
+    std::map<std::string, ThreadQueueBasePtr, map_string_less> output_queues;
 
     //this protects against concurrent changes in input/output bindings: get/set/Input/OutPutQueue
-    mutable std::mutex m_queue_bindings_mutex;
+    std::mutex m_queue_bindings_mutex;
 
     //true when a termination is ordered
     std::atomic_bool stopping;
diff --git a/src/ModemProperties.cpp b/src/ModemProperties.cpp
index 9984bdc..4fa02df 100644
--- a/src/ModemProperties.cpp
+++ b/src/ModemProperties.cpp
@@ -101,7 +101,7 @@ void ModemProperties::initDefaultProperties() {
     defaultProps["._audio_output"] = addArgInfoProperty(m_propertyGrid, outputArg);
 }
 
-void ModemProperties::initProperties(ModemArgInfoList newArgs, DemodulatorInstance *demodInstance) {
+void ModemProperties::initProperties(ModemArgInfoList newArgs, DemodulatorInstancePtr demodInstance) {
     args = newArgs;
     demodContext = demodInstance;
     
diff --git a/src/ModemProperties.h b/src/ModemProperties.h
index 268e366..c708f61 100644
--- a/src/ModemProperties.h
+++ b/src/ModemProperties.h
@@ -24,7 +24,7 @@ public:
     ~ModemProperties();
     
     void initDefaultProperties();
-    void initProperties(ModemArgInfoList newArgs, DemodulatorInstance *demodInstance);
+    void initProperties(ModemArgInfoList newArgs, DemodulatorInstancePtr demodInstance);
     bool isMouseInView();
     void setCollapsed(bool state);
     bool isCollapsed();
@@ -46,7 +46,8 @@ private:
     wxBoxSizer* bSizer;
     wxPropertyGrid* m_propertyGrid;
     ModemArgInfoList args;
-    DemodulatorInstance *demodContext;
+    DemodulatorInstancePtr demodContext;
+
     std::map<std::string, wxPGProperty *> props;
     bool mouseInView, collapsed;
     
diff --git a/src/audio/AudioFile.cpp b/src/audio/AudioFile.cpp
new file mode 100644
index 0000000..6b15db7
--- /dev/null
+++ b/src/audio/AudioFile.cpp
@@ -0,0 +1,50 @@
+// Copyright (c) Charles J. Cliffe
+// SPDX-License-Identifier: GPL-2.0+
+
+#include "AudioFile.h"
+#include "CubicSDR.h"
+#include <sstream>
+
+AudioFile::AudioFile() {
+
+}
+
+AudioFile::~AudioFile() {
+
+}
+
+void AudioFile::setOutputFileName(std::string filename) {
+    filenameBase = filename;
+}
+
+std::string AudioFile::getOutputFileName() {
+
+    std::string recPath = wxGetApp().getConfig()->getRecordingPath();
+
+    // Strip any invalid characters from the name
+    std::string stripChars("<>:\"/\\|?*");
+    std::string filenameBaseSafe = filenameBase;
+
+    for (size_t i = 0, iMax = filenameBaseSafe.length(); i < iMax; i++) {
+        if (stripChars.find(filenameBaseSafe[i]) != std::string::npos) {
+            filenameBaseSafe.replace(i,1,"_");
+        }
+    }
+    
+    // Create output file name
+	std::stringstream outputFileName;
+	outputFileName << recPath << filePathSeparator << filenameBaseSafe;
+
+    int idx = 0;
+
+    // If the file exists; then find the next non-existing file in sequence.
+	std::string fileNameCandidate = outputFileName.str();
+
+    while (FILE *file = fopen((fileNameCandidate + "." + getExtension()).c_str(), "r")) {
+        fclose(file);
+		fileNameCandidate = outputFileName.str() +  "-" + std::to_string(++idx);
+    }
+
+    return fileNameCandidate + "." + getExtension();
+}
+
diff --git a/src/audio/AudioFile.h b/src/audio/AudioFile.h
new file mode 100644
index 0000000..c8636b8
--- /dev/null
+++ b/src/audio/AudioFile.h
@@ -0,0 +1,25 @@
+// Copyright (c) Charles J. Cliffe
+// SPDX-License-Identifier: GPL-2.0+
+
+#pragma once
+
+#include "AudioThread.h"
+
+class AudioFile
+{
+
+public:
+    AudioFile();
+    virtual ~AudioFile();
+
+    virtual void setOutputFileName(std::string filename);
+    virtual std::string getExtension() = 0;
+    virtual std::string getOutputFileName();
+
+    virtual bool writeToFile(AudioThreadInputPtr input) = 0;
+    virtual bool closeFile() = 0;
+
+protected:
+    std::string filenameBase;
+
+};
\ No newline at end of file
diff --git a/src/audio/AudioFileWAV.cpp b/src/audio/AudioFileWAV.cpp
new file mode 100644
index 0000000..d0629ab
--- /dev/null
+++ b/src/audio/AudioFileWAV.cpp
@@ -0,0 +1,219 @@
+// Copyright (c) Charles J. Cliffe
+// SPDX-License-Identifier: GPL-2.0+
+
+#include "AudioFileWAV.h"
+#include "CubicSDR.h"
+#include <iomanip>
+
+//limit file size to 2GB (- margin) for maximum compatibility.
+#define MAX_WAV_FILE_SIZE (0x7FFFFFFF - 1024)
+
+// Simple endian io read/write handling from 
+// http://www.cplusplus.com/forum/beginner/31584/#msg171056
+namespace little_endian_io
+{
+    template <typename Word>
+    std::ostream& write_word(std::ostream& outs, Word value, unsigned size = sizeof(Word)) {
+        for (; size; --size, value >>= 8) {
+            outs.put(static_cast <char> (value & 0xFF));
+        }
+        return outs;
+    }
+
+    template <typename Word>
+    std::istream& read_word(std::istream& ins, Word& value, unsigned size = sizeof(Word)) {
+        for (unsigned n = 0, value = 0; n < size; ++n) {
+            value |= ins.get() << (8 * n);
+        }
+        return ins;
+    }
+}
+
+namespace big_endian_io
+{
+    template <typename Word>
+    std::ostream& write_word(std::ostream& outs, Word value, unsigned size = sizeof(Word)) {
+        while (size) {
+            outs.put(static_cast <char> ((value >> (8 * --size)) & 0xFF));
+        }
+        return outs;
+    }
+
+    template <typename Word>
+    std::istream& read_word(std::istream& ins, Word& value, unsigned size = sizeof(Word)) {
+        for (value = 0; size; --size) {
+            value = (value << 8) | ins.get();
+        }
+        return ins;
+    }
+}
+
+using namespace little_endian_io;
+
+AudioFileWAV::AudioFileWAV() : AudioFile() {
+}
+
+AudioFileWAV::~AudioFileWAV() {
+}
+
+
+std::string AudioFileWAV::getExtension()
+{
+    return "wav";
+}
+
+bool AudioFileWAV::writeToFile(AudioThreadInputPtr input)
+{
+    if (!outputFileStream.is_open()) {
+
+        std::string ofName = getOutputFileName();
+                
+        outputFileStream.open(ofName.c_str(), std::ios::binary);
+		currentFileSize = 0;
+
+		writeHeaderToFileStream(input);
+    }
+
+	size_t maxRoomInCurrentFileInSamples = getMaxWritableNumberOfSamples(input);
+
+	if (maxRoomInCurrentFileInSamples >= input->data.size()) {
+		writePayloadToFileStream(input, 0, input->data.size());
+	}
+	else {
+		//we complete the current file and open another:
+		writePayloadToFileStream(input, 0, maxRoomInCurrentFileInSamples);
+
+		closeFile();
+
+		// Open a new file with the next sequence number, and dump the rest of samples in it.
+		currentSequenceNumber++;
+		currentFileSize = 0;
+
+		std::string ofName = getOutputFileName();
+		outputFileStream.open(ofName.c_str(), std::ios::binary);
+		
+		writeHeaderToFileStream(input);
+		writePayloadToFileStream(input, maxRoomInCurrentFileInSamples, input->data.size());
+	}
+
+    return true;
+}
+
+bool AudioFileWAV::closeFile()
+{
+    if (outputFileStream.is_open()) {
+        size_t file_length = outputFileStream.tellp();
+
+        // Fix the data chunk header to contain the data size
+        outputFileStream.seekp(dataChunkPos + 4);
+        write_word(outputFileStream, file_length - dataChunkPos + 8);
+
+        // Fix the file header to contain the proper RIFF chunk size, which is (file size - 8) bytes
+        outputFileStream.seekp(0 + 4);
+        write_word(outputFileStream, file_length - 8, 4);
+
+        outputFileStream.close();
+		currentFileSize = 0;
+    }
+
+    return true;
+}
+
+void AudioFileWAV::writeHeaderToFileStream(AudioThreadInputPtr input) {
+
+	// Based on simple wav file output code from
+	// http://www.cplusplus.com/forum/beginner/166954/
+
+	// Write the wav file headers
+	outputFileStream << "RIFF----WAVEfmt "; // (chunk size to be filled in later)
+	write_word(outputFileStream, 16, 4); // no extension data
+	write_word(outputFileStream, 1, 2); // PCM - integer samples
+	write_word(outputFileStream, input->channels, 2); // channels
+	write_word(outputFileStream, input->sampleRate, 4); // samples per second (Hz)
+	write_word(outputFileStream, (input->sampleRate * 16 * input->channels) / 8, 4); // (Sample Rate * BitsPerSample * Channels) / 8
+	write_word(outputFileStream, input->channels * 2, 2); // data block size (size of integer samples, one for each channel, in bytes)
+	write_word(outputFileStream, 16, 2); // number of bits per sample (use a multiple of 8)
+
+										 // Write the data chunk header
+	dataChunkPos = outputFileStream.tellp();
+	currentFileSize = dataChunkPos;
+	outputFileStream << "data----";  // (chunk size to be filled in later)
+}
+
+void AudioFileWAV::writePayloadToFileStream(AudioThreadInputPtr input, size_t startInputPosition, size_t endInputPosition) {
+
+	// Prevent clipping
+	float intScale = (input->peak < 1.0) ? 32767.0f : (32767.0f / input->peak);
+
+	if (input->channels == 1) {
+		for (size_t i = startInputPosition, iMax = endInputPosition; i < iMax; i++) {
+
+			write_word(outputFileStream, int(input->data[i] * intScale), 2);
+			
+			currentFileSize += 2;
+		}
+	}
+	else if (input->channels == 2) {
+		for (size_t i = startInputPosition, iMax = endInputPosition / 2; i < iMax; i++) {
+
+			write_word(outputFileStream, int(input->data[i * 2] * intScale), 2);
+			write_word(outputFileStream, int(input->data[i * 2 + 1] * intScale), 2);
+
+			currentFileSize += 4;
+		}
+	}
+}
+
+size_t AudioFileWAV::getMaxWritableNumberOfSamples(AudioThreadInputPtr input) {
+
+	long long remainingBytesInFile = (long long)(MAX_WAV_FILE_SIZE) - currentFileSize;
+
+    return (size_t)(remainingBytesInFile / (input->channels * 2));
+	
+}
+
+void AudioFileWAV::setOutputFileName(std::string filename) {
+
+	if (filename != filenameBase) {
+
+		currentSequenceNumber = 0;
+	}
+
+	AudioFile::setOutputFileName(filename);
+}
+
+std::string AudioFileWAV::getOutputFileName() {
+
+	std::string recPath = wxGetApp().getConfig()->getRecordingPath();
+
+	// Strip any invalid characters from the name
+	std::string stripChars("<>:\"/\\|?*");
+	std::string filenameBaseSafe = filenameBase;
+
+	for (size_t i = 0, iMax = filenameBaseSafe.length(); i < iMax; i++) {
+		if (stripChars.find(filenameBaseSafe[i]) != std::string::npos) {
+			filenameBaseSafe.replace(i, 1, "_");
+		}
+	}
+
+	// Create output file name
+	std::stringstream outputFileName;
+	outputFileName << recPath << filePathSeparator << filenameBaseSafe;
+
+	//customized part: append a sequence number.
+	if (currentSequenceNumber > 0) {
+		outputFileName << "_" << std::setfill('0') << std::setw(3) << currentSequenceNumber;
+	}
+
+	int idx = 0;
+
+	// If the file exists; then find the next non-existing file in sequence.
+	std::string fileNameCandidate = outputFileName.str();
+
+	while (FILE *file = fopen((fileNameCandidate + "." + getExtension()).c_str(), "r")) {
+		fclose(file);
+		fileNameCandidate = outputFileName.str() + "-" + std::to_string(++idx);
+	}
+
+	return fileNameCandidate + "." + getExtension();
+}
\ No newline at end of file
diff --git a/src/audio/AudioFileWAV.h b/src/audio/AudioFileWAV.h
new file mode 100644
index 0000000..1dc9672
--- /dev/null
+++ b/src/audio/AudioFileWAV.h
@@ -0,0 +1,42 @@
+// Copyright (c) Charles J. Cliffe
+// SPDX-License-Identifier: GPL-2.0+
+
+#pragma once
+
+#include "AudioFile.h"
+
+#include <fstream>
+
+class AudioFileWAV : public AudioFile {
+
+public:
+    AudioFileWAV();
+    ~AudioFileWAV();
+
+	//override to manage name change with multi-part WAV. 
+	virtual void setOutputFileName(std::string filename);
+
+	//override of the base method to generate multi-part 
+	//WAV to overcome the WAV format size limit.
+	virtual std::string getOutputFileName();
+
+    virtual std::string getExtension();
+
+    virtual bool writeToFile(AudioThreadInputPtr input);
+    virtual bool closeFile();
+
+protected:
+    std::ofstream outputFileStream;
+    size_t dataChunkPos;
+	long long currentFileSize = 0;
+	int currentSequenceNumber = 0;
+
+private:
+
+	size_t getMaxWritableNumberOfSamples(AudioThreadInputPtr input);
+
+	void writeHeaderToFileStream(AudioThreadInputPtr input);
+
+	//write [startInputPosition; endInputPosition[ samples from input into the file.
+	void writePayloadToFileStream(AudioThreadInputPtr input, size_t startInputPosition, size_t endInputPosition);
+};
\ No newline at end of file
diff --git a/src/audio/AudioSinkFileThread.cpp b/src/audio/AudioSinkFileThread.cpp
new file mode 100644
index 0000000..e49b57b
--- /dev/null
+++ b/src/audio/AudioSinkFileThread.cpp
@@ -0,0 +1,140 @@
+// Copyright (c) Charles J. Cliffe
+// SPDX-License-Identifier: GPL-2.0+
+
+#include "AudioSinkFileThread.h"
+#include <ctime>
+
+#define HEARTBEAT_CHECK_PERIOD_MICROS (50 * 1000) 
+
+AudioSinkFileThread::AudioSinkFileThread() : AudioSinkThread() {
+
+}
+
+AudioSinkFileThread::~AudioSinkFileThread() {
+    if (audioFileHandler != nullptr) {
+        audioFileHandler->closeFile();
+    }
+}
+
+void AudioSinkFileThread::sink(AudioThreadInputPtr input) {
+    if (!audioFileHandler) {
+        return;
+    }
+
+	//by default, always write something
+	bool isSomethingToWrite = true;
+
+	if (input->is_squelch_active) {
+
+		if (squelchOption == SQUELCH_RECORD_SILENCE) {
+		
+			//patch with "silence"
+			input->data.assign(input->data.size(), 0.0f);
+			input->peak = 0.0f;
+		}
+		else if (squelchOption == SQUELCH_SKIP_SILENCE) {
+			isSomethingToWrite = false;
+		}
+	}
+
+	//else, nothing to do record as if squelch was not enabled.
+	
+	if (!isSomethingToWrite) {
+		return;
+	}
+
+	if (fileTimeLimit > 0) {
+		durationMeasurement.update();
+
+		//duration exeeded, close this file and create another
+		//with "now" as timestamp.
+		if (durationMeasurement.getSeconds() > fileTimeLimit) {
+			
+			audioFileHandler->closeFile();
+
+			//initialize the filename of the AudioFile with the current time
+			time_t t = std::time(nullptr);
+			tm ltm = *std::localtime(&t);
+
+			//  GCC 5+
+			//    fileName << "_" << std::put_time(&ltm, "%d-%m-%Y_%H-%M-%S");
+
+			char timeStr[512];
+			//International format: Year.Month.Day, also lexicographically sortable
+			strftime(timeStr, sizeof(timeStr), "%Y-%m-%d_%H-%M-%S", &ltm);
+
+			audioFileHandler->setOutputFileName(fileNameBase + std::string("_") + timeStr);
+
+			//reset duration counter
+			durationMeasurement.start();
+			//the following writeToFile will take care of creating another file.
+		}
+	}
+
+    // forward to output file handler
+    audioFileHandler->writeToFile(input);
+}
+
+void AudioSinkFileThread::inputChanged(AudioThreadInput oldProps, AudioThreadInputPtr newProps) {
+    // close, set new parameters, adjust file name sequence and re-open?
+    if (!audioFileHandler) {
+        return;
+    }
+
+    audioFileHandler->closeFile();
+
+	//reset duration counter
+	durationMeasurement.start();
+}
+
+void AudioSinkFileThread::setAudioFileNameBase(const std::string& baseName) {
+
+	fileNameBase = baseName;
+}
+
+void AudioSinkFileThread::setAudioFileHandler(AudioFile * output) {
+    audioFileHandler = output;
+	
+	//initialize the filename of the AudioFile with the current time
+	time_t t = std::time(nullptr);
+	tm ltm = *std::localtime(&t);
+
+	//  GCC 5+
+	//    fileName << "_" << std::put_time(&ltm, "%d-%m-%Y_%H-%M-%S");
+
+	char timeStr[512];
+	//International format: Year.Month.Day, also lexicographically sortable
+	strftime(timeStr, sizeof(timeStr), "%Y-%m-%d_%H-%M-%S", &ltm);
+
+	audioFileHandler->setOutputFileName(fileNameBase + std::string("_") + timeStr);
+
+	// reset Timer
+	durationMeasurement.start();
+}
+
+void AudioSinkFileThread::setSquelchOption(int squelchOptEnumValue) {
+
+	if (squelchOptEnumValue == AudioSinkFileThread::SQUELCH_RECORD_SILENCE) {
+		squelchOption = AudioSinkFileThread::SQUELCH_RECORD_SILENCE;
+	}
+	else if (squelchOptEnumValue == AudioSinkFileThread::SQUELCH_SKIP_SILENCE) {
+		squelchOption = AudioSinkFileThread::SQUELCH_SKIP_SILENCE;
+	}
+	else if (squelchOptEnumValue == AudioSinkFileThread::SQUELCH_RECORD_ALWAYS) {
+		squelchOption = AudioSinkFileThread::SQUELCH_RECORD_ALWAYS;
+	}
+	else {
+		squelchOption = AudioSinkFileThread::SQUELCH_RECORD_SILENCE;
+	}
+}
+
+// Time limit
+void AudioSinkFileThread::setFileTimeLimit(int nbSeconds) {
+
+	if (nbSeconds > 0) {
+		fileTimeLimit = nbSeconds;
+	}
+	else {
+		fileTimeLimit = 0;
+	}
+}
diff --git a/src/audio/AudioSinkFileThread.h b/src/audio/AudioSinkFileThread.h
new file mode 100644
index 0000000..f0bdb73
--- /dev/null
+++ b/src/audio/AudioSinkFileThread.h
@@ -0,0 +1,50 @@
+// Copyright (c) Charles J. Cliffe
+// SPDX-License-Identifier: GPL-2.0+
+
+#pragma once
+
+#include "AudioSinkThread.h"
+#include "AudioFile.h"
+#include "Timer.h"
+
+class AudioSinkFileThread : public AudioSinkThread {
+
+public:
+    AudioSinkFileThread();
+    ~AudioSinkFileThread();
+
+	enum SquelchOption {
+		SQUELCH_RECORD_SILENCE = 0, // default value, record as a user would hear it.
+		SQUELCH_SKIP_SILENCE = 1,  // skip below-squelch level. 
+		SQUELCH_RECORD_ALWAYS = 2, // record irrespective of the squelch level.
+		SQUELCH_RECORD_MAX
+	};
+
+    virtual void sink(AudioThreadInputPtr input);
+    virtual void inputChanged(AudioThreadInput oldProps, AudioThreadInputPtr newProps);
+
+    void setAudioFileHandler(AudioFile *output);
+
+	void setAudioFileNameBase(const std::string& baseName);
+
+	//Squelch 
+	void setSquelchOption(int squelchOptEnumValue);
+
+	// Time limit
+	void setFileTimeLimit(int nbSeconds);
+
+protected:
+
+	std::string fileNameBase;
+
+    AudioFile *audioFileHandler = nullptr;
+
+	SquelchOption squelchOption = SQUELCH_RECORD_SILENCE;
+	int fileTimeLimit = 0;
+
+	int fileTimeDurationSeconds = -1;
+
+	Timer durationMeasurement;
+
+};
+
diff --git a/src/audio/AudioSinkThread.cpp b/src/audio/AudioSinkThread.cpp
new file mode 100644
index 0000000..edf3152
--- /dev/null
+++ b/src/audio/AudioSinkThread.cpp
@@ -0,0 +1,54 @@
+// Copyright (c) Charles J. Cliffe
+// SPDX-License-Identifier: GPL-2.0+
+
+#include "AudioSinkThread.h"
+
+#define HEARTBEAT_CHECK_PERIOD_MICROS (50 * 1000) 
+
+AudioSinkThread::AudioSinkThread() {
+    inputQueuePtr = std::make_shared<AudioThreadInputQueue>();
+    inputQueuePtr->set_max_num_items(1000);
+    setInputQueue("input", inputQueuePtr);
+}
+
+AudioSinkThread::~AudioSinkThread() {
+
+}
+
+void AudioSinkThread::run() {
+#ifdef __APPLE__
+    pthread_t tID = pthread_self();	 // ID of this thread
+    int priority = sched_get_priority_max(SCHED_RR) - 1;
+    sched_param prio = { priority }; // scheduling priority of thread
+    pthread_setschedparam(tID, SCHED_RR, &prio);
+#endif
+
+    AudioThreadInputPtr inp;
+    AudioThreadInput inputRef;
+
+    while (!stopping) {
+        if (!inputQueuePtr->pop(inp, HEARTBEAT_CHECK_PERIOD_MICROS)) {
+            continue;
+        }
+
+        if (inputRef.channels != inp->channels || 
+                inputRef.frequency != inp->frequency ||
+                inputRef.inputRate != inp->inputRate ||
+                inputRef.sampleRate != inp->sampleRate) {
+
+            inputChanged(inputRef, inp);
+
+            inputRef.channels = inp->channels;
+            inputRef.frequency = inp->frequency;
+            inputRef.inputRate = inp->inputRate;
+            inputRef.sampleRate = inp->sampleRate;
+        }
+
+        sink(inp);
+    }
+}
+
+void AudioSinkThread::terminate() {
+    IOThread::terminate();
+    inputQueuePtr->flush();
+}
diff --git a/src/audio/AudioSinkThread.h b/src/audio/AudioSinkThread.h
new file mode 100644
index 0000000..754c75d
--- /dev/null
+++ b/src/audio/AudioSinkThread.h
@@ -0,0 +1,25 @@
+// Copyright (c) Charles J. Cliffe
+// SPDX-License-Identifier: GPL-2.0+
+
+#pragma once
+
+#include "AudioThread.h"
+
+class AudioSinkThread : public IOThread {
+
+public:
+
+    AudioSinkThread();
+    virtual ~AudioSinkThread();
+
+	virtual void run();
+	virtual void terminate();
+
+    virtual void sink(AudioThreadInputPtr input) = 0;
+    virtual void inputChanged(AudioThreadInput oldProps, AudioThreadInputPtr newProps) = 0;
+
+protected:
+    std::recursive_mutex m_mutex;
+    AudioThreadInputQueuePtr inputQueuePtr;
+
+};
diff --git a/src/audio/AudioThread.cpp b/src/audio/AudioThread.cpp
index e0d4ad1..e5db98b 100644
--- a/src/audio/AudioThread.cpp
+++ b/src/audio/AudioThread.cpp
@@ -11,23 +11,26 @@
 #include <memory.h>
 #include <mutex>
 
+//50 ms
+#define HEARTBEAT_CHECK_PERIOD_MICROS (50 * 1000) 
 
 std::map<int, AudioThread *> AudioThread::deviceController;
 std::map<int, int> AudioThread::deviceSampleRate;
 std::map<int, std::thread *> AudioThread::deviceThread;
 
-AudioThread::AudioThread() : IOThread(),
-        currentInput(nullptr), inputQueue(nullptr), nBufferFrames(1024), sampleRate(0) {
+std::recursive_mutex AudioThread::m_device_mutex;
 
-	audioQueuePtr.store(0); 
-	underflowCount.store(0);
+AudioThread::AudioThread() : IOThread(), nBufferFrames(1024), sampleRate(0) {
+
+	audioQueuePtr = 0; 
+	underflowCount = 0;
 	active.store(false);
 	outputDevice.store(-1);
     gain = 1.0;
 }
 
 AudioThread::~AudioThread() {
-
+	std::lock_guard<std::recursive_mutex> lock(m_mutex);
 }
 
 std::recursive_mutex & AudioThread::getMutex()
@@ -46,10 +49,10 @@ void AudioThread::bindThread(AudioThread *other) {
 
 void AudioThread::removeThread(AudioThread *other) {
     
-    std::lock_guard<std::recursive_mutex> lock(m_mutex);
+	std::lock_guard<std::recursive_mutex> lock(m_mutex);
+
+    auto i = std::find(boundThreads.begin(), boundThreads.end(), other);
 
-    std::vector<AudioThread *>::iterator i;
-    i = std::find(boundThreads.begin(), boundThreads.end(), other);
     if (i != boundThreads.end()) {
         boundThreads.erase(i);
     }
@@ -57,9 +60,9 @@ void AudioThread::removeThread(AudioThread *other) {
 
 void AudioThread::deviceCleanup() {
 
-    std::map<int, AudioThread *>::iterator i;
+	std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
 
-    for (i = deviceController.begin(); i != deviceController.end(); i++) {
+    for (auto i = deviceController.begin(); i != deviceController.end(); i++) {
         i->second->terminate();
     }
 }
@@ -71,7 +74,7 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
 
     //Zero output buffer in all cases: this allow to mute audio if no AudioThread data is 
     //actually active.
-    memset(out, 0, nBufferFrames * 2 * sizeof(float));
+    ::memset(out, 0, nBufferFrames * 2 * sizeof(float));
 
     AudioThread *src = (AudioThread *) userData;
    
@@ -82,7 +85,7 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
     }
 
     if (status) {
-       std::cout << "Audio buffer underflow.." << (src->underflowCount++) << std::endl;
+       std::cout << "Audio buffer underflow.." << (src->underflowCount++) << std::endl << std::flush;
     }
 
     if (src->boundThreads.empty()) {
@@ -123,7 +126,7 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
                     if (srcmix->currentInput->sampleRate == src->getSampleRate()) {
                         break;
                     }
-                    srcmix->currentInput->decRefCount();
+                   
                 }
                 srcmix->currentInput = nullptr;
             } //end while
@@ -140,7 +143,7 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
             if (!srcmix->inputQueue->empty()) {
                 srcmix->audioQueuePtr = 0;
                 if (srcmix->currentInput) {
-                    srcmix->currentInput->decRefCount();
+                   
                     srcmix->currentInput = nullptr;
                 }
 
@@ -160,7 +163,7 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
                 if (srcmix->audioQueuePtr >= srcmix->currentInput->data.size()) {
                     srcmix->audioQueuePtr = 0;
                     if (srcmix->currentInput) {
-                        srcmix->currentInput->decRefCount();
+                       
                         srcmix->currentInput = nullptr;
                     }
 
@@ -187,7 +190,7 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
                 if (srcmix->audioQueuePtr >= srcmix->currentInput->data.size()) {
                     srcmix->audioQueuePtr = 0;
                     if (srcmix->currentInput) {
-                        srcmix->currentInput->decRefCount();
+                       
                         srcmix->currentInput = nullptr;
                     }
 
@@ -277,23 +280,47 @@ void AudioThread::enumerateDevices(std::vector<RtAudio::DeviceInfo> &devs) {
 
 void AudioThread::setDeviceSampleRate(int deviceId, int sampleRate) {
    
+	AudioThread* matchingAudioThread = nullptr;
 
-    if (deviceController.find(deviceId) != deviceController.end()) {
-        AudioThreadCommand refreshDevice;
-        refreshDevice.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_SAMPLE_RATE;
-        refreshDevice.int_value = sampleRate;
-        //VSO : blocking push !
-        deviceController[deviceId]->getCommandQueue()->push(refreshDevice);
-    }
+	//scope lock here to minimize the common unique static lock contention
+	{
+		std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
+
+		if (deviceController.find(deviceId) != deviceController.end()) {
+
+			matchingAudioThread = deviceController[deviceId];
+		}
+	}
+
+	//out-of-lock test
+	if (matchingAudioThread != nullptr) {
+
+		AudioThreadCommand refreshDevice;
+		refreshDevice.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_SAMPLE_RATE;
+		refreshDevice.int_value = sampleRate;
+		//VSO : blocking push !
+		matchingAudioThread->getCommandQueue()->push(refreshDevice);
+	}
 }
 
 void AudioThread::setSampleRate(int sampleRate) {
 
-    std::lock_guard<std::recursive_mutex> lock(m_mutex);
+	bool outputIsThis = false;
+
+	//scope lock here to minimize the common unique static lock contention
+	{
+		std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
 
-    if (deviceController[outputDevice.load()] == this) {
-        deviceSampleRate[outputDevice.load()] = sampleRate;
+		if (deviceController[outputDevice.load()] == this) {
+			outputIsThis = true;
+			deviceSampleRate[outputDevice.load()] = sampleRate;
+		}
+	}
 
+    std::lock_guard<std::recursive_mutex> lock(m_mutex);
+
+    if (outputIsThis) {
+       
         dac.stopStream();
         dac.closeStream();
 
@@ -302,14 +329,12 @@ void AudioThread::setSampleRate(int sampleRate) {
             srcmix->setSampleRate(sampleRate);
         }
 
-        std::vector<DemodulatorInstance *>::iterator demod_i;
-        std::vector<DemodulatorInstance *> *demodulators;
+        //make a local copy, snapshot of the list of demodulators
+        std::vector<DemodulatorInstancePtr> demodulators = wxGetApp().getDemodMgr().getDemodulators();
 
-        demodulators = &wxGetApp().getDemodMgr().getDemodulators();
-
-        for (demod_i = demodulators->begin(); demod_i != demodulators->end(); demod_i++) {
-            if ((*demod_i)->getOutputDevice() == outputDevice.load()) {
-                (*demod_i)->setAudioSampleRate(sampleRate);
+        for (auto demod : demodulators) {
+            if (demod->getOutputDevice() == outputDevice.load()) {
+                demod->setAudioSampleRate(sampleRate);
             }
         }
 
@@ -328,7 +353,8 @@ int AudioThread::getSampleRate() {
 
 void AudioThread::setupDevice(int deviceId) {
 
-    std::lock_guard<std::recursive_mutex> lock(m_mutex);
+	//global lock to setup the device...
+	std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
 
     parameters.deviceId = deviceId;
     parameters.nChannels = 2;
@@ -381,6 +407,7 @@ void AudioThread::setupDevice(int deviceId) {
 }
 
 int AudioThread::getOutputDevice() {
+
     std::lock_guard<std::recursive_mutex> lock(m_mutex);
 
     if (outputDevice == -1) {
@@ -391,7 +418,8 @@ int AudioThread::getOutputDevice() {
 
 void AudioThread::setInitOutputDevice(int deviceId, int sampleRate) {
     
-    std::lock_guard<std::recursive_mutex> lock(m_mutex);
+	//global lock 
+    std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
 
     outputDevice = deviceId;
     if (sampleRate == -1) {
@@ -422,14 +450,16 @@ void AudioThread::run() {
     setupDevice((outputDevice.load() == -1) ? (dac.getDefaultOutputDevice()) : outputDevice.load());
 
 //    std::cout << "Audio thread started." << std::endl;
-
-    inputQueue = static_cast<AudioThreadInputQueue *>(getInputQueue("AudioDataInput"));
+    
+    inputQueue = std::static_pointer_cast<AudioThreadInputQueue>(getInputQueue("AudioDataInput"));
     
     //Infinite loop, witing for commands or for termination
     while (!stopping) {
         AudioThreadCommand command;
 
-        cmdQueue.pop(command);
+        if (!cmdQueue.pop(command, HEARTBEAT_CHECK_PERIOD_MICROS)) {
+            continue;
+        }
 
         if (command.cmd == AudioThreadCommand::AUDIO_THREAD_CMD_SET_DEVICE) {
             setupDevice(command.int_value);
@@ -438,27 +468,22 @@ void AudioThread::run() {
             setSampleRate(command.int_value);
         }
     }
-    
-    //Thread termination, prevent fancy things to happen, lock the whole thing:
-    //This way audioThreadCallback is rightly protected from thread termination
-    std::lock_guard<std::recursive_mutex> lock(m_mutex);
-
+   
     // Drain any remaining inputs, with a non-blocking pop
-    AudioThreadInput *ref;
-    while (inputQueue && inputQueue->try_pop(ref)) {
-       
-        if (ref) {
-            ref->decRefCount();
-        }
-    } //end while
-    
-    //Nullify currentInput...
-    if (currentInput) {
-        currentInput->setRefCount(0);
-        currentInput = nullptr;
+    if (inputQueue != nullptr) {
+        inputQueue->flush();
     }
 
-    //Stop 
+	//Thread termination, prevent fancy things to happen, lock the whole thing:
+	//This way audioThreadCallback is rightly protected from thread termination
+	std::lock_guard<std::recursive_mutex> lock(m_mutex);
+
+	//Nullify currentInput...
+	currentInput = nullptr;
+
+    //Stop : this affects the device list , so must be protected globally.
+	std::lock_guard<std::recursive_mutex> global_lock(m_device_mutex);
+
     if (deviceController[parameters.deviceId] != this) {
         deviceController[parameters.deviceId]->removeThread(this);
     } else {
@@ -479,9 +504,6 @@ void AudioThread::run() {
 
 void AudioThread::terminate() {
     IOThread::terminate();
-    AudioThreadCommand endCond;   // push an empty input to bump the queue
-    //VSO: blocking push
-    cmdQueue.push(endCond);
 }
 
 bool AudioThread::isActive() {
@@ -491,25 +513,34 @@ bool AudioThread::isActive() {
 }
 
 void AudioThread::setActive(bool state) {
-    
+
+	AudioThread* matchingAudioThread = nullptr;
+
+	//scope lock here to minimize the common unique static lock contention
+	{
+		std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
+
+		if (deviceController.find(parameters.deviceId) != deviceController.end()) {
+
+			matchingAudioThread = deviceController[parameters.deviceId];
+		}
+	}
+
     std::lock_guard<std::recursive_mutex> lock(m_mutex);
 
-    AudioThreadInput *dummy;
+    if (matchingAudioThread == nullptr) {
+        return;
+    }
+
     if (state && !active && inputQueue) {
-        deviceController[parameters.deviceId]->bindThread(this);
+		matchingAudioThread->bindThread(this);
     } else if (!state && active) {
-        deviceController[parameters.deviceId]->removeThread(this);
+		matchingAudioThread->removeThread(this);
     }
 
     // Activity state changing, clear any inputs
     if(inputQueue) {
-
-        while (inputQueue->try_pop(dummy)) {  // flush queue, non-blocking pop
-            
-            if (dummy) {
-                dummy->decRefCount();
-            }
-        }
+        inputQueue->flush();
     }
     active = state;
 }
@@ -519,21 +550,12 @@ AudioThreadCommandQueue *AudioThread::getCommandQueue() {
 }
 
 void AudioThread::setGain(float gain_in) {
-    
-    std::lock_guard<std::recursive_mutex> lock(m_mutex);
-
-    if (gain < 0.0) {
-        gain = 0.0;
+   
+    if (gain_in < 0.0) {
+        gain_in = 0.0;
     }
-    if (gain > 2.0) {
-        gain = 2.0;
+    if (gain_in > 2.0) {
+        gain_in = 2.0;
     }
     gain = gain_in;
 }
-
-float AudioThread::getGain() {
-    
-    std::lock_guard<std::recursive_mutex> lock(m_mutex);
-
-    return gain;
-}
diff --git a/src/audio/AudioThread.h b/src/audio/AudioThread.h
index ce349c0..7585faa 100644
--- a/src/audio/AudioThread.h
+++ b/src/audio/AudioThread.h
@@ -8,12 +8,12 @@
 #include <map>
 #include <string>
 #include <atomic>
-
+#include <memory>
 #include "ThreadBlockingQueue.h"
 #include "RtAudio.h"
 #include "DemodDefs.h"
 
-class AudioThreadInput: public ReferenceCounter {
+class AudioThreadInput {
 public:
     long long frequency;
     int inputRate;
@@ -21,18 +21,43 @@ public:
     int channels;
     float peak;
     int type;
+	bool is_squelch_active;
+
     std::vector<float> data;
 
     AudioThreadInput() :
-            frequency(0), sampleRate(0), channels(0), peak(0) {
+            frequency(0), inputRate(0), sampleRate(0), channels(0), peak(0), type(0), is_squelch_active(false) {
 
     }
 
-    ~AudioThreadInput() {
-        std::lock_guard < std::recursive_mutex > lock(m_mutex);
+    
+    AudioThreadInput(AudioThreadInput *copyFrom) {
+        copy(copyFrom);
+    }
+    
+    void copy(AudioThreadInput *copyFrom) {
+        frequency = copyFrom->frequency;
+        inputRate = copyFrom->inputRate;
+        sampleRate = copyFrom->sampleRate;
+        channels = copyFrom->channels;
+        peak = copyFrom->peak;
+        type = copyFrom->type;
+        is_squelch_active = copyFrom->is_squelch_active;
+        data.assign(copyFrom->data.begin(), copyFrom->data.end());
+    }
+
+    
+    virtual ~AudioThreadInput() {
+       
     }
 };
 
+typedef std::shared_ptr<AudioThreadInput> AudioThreadInputPtr;
+
+typedef ThreadBlockingQueue<AudioThreadInputPtr> DemodulatorThreadOutputQueue;
+
+typedef std::shared_ptr<DemodulatorThreadOutputQueue> DemodulatorThreadOutputQueuePtr;
+
 class AudioThreadCommand {
 public:
     enum AudioThreadCommandEnum {
@@ -47,30 +72,26 @@ public:
     int int_value;
 };
 
-typedef ThreadBlockingQueue<AudioThreadInput *> AudioThreadInputQueue;
+typedef ThreadBlockingQueue<AudioThreadInputPtr> AudioThreadInputQueue;
 typedef ThreadBlockingQueue<AudioThreadCommand> AudioThreadCommandQueue;
 
+typedef std::shared_ptr<AudioThreadInputQueue> AudioThreadInputQueuePtr;
+typedef std::shared_ptr<AudioThreadCommandQueue> AudioThreadCommandQueuePtr;
+
 class AudioThread : public IOThread {
-public:
-    AudioThreadInput *currentInput;
-    AudioThreadInputQueue *inputQueue;
-    std::atomic_uint audioQueuePtr;
-    std::atomic_uint underflowCount;
-    std::atomic_bool initialized;
-    std::atomic_bool active;
-    std::atomic_int outputDevice;
-    float gain;
 
+public:
+   
     AudioThread();
-    ~AudioThread();
+    virtual ~AudioThread();
 
     static void enumerateDevices(std::vector<RtAudio::DeviceInfo> &devs);
 
-    void setupDevice(int deviceId);
     void setInitOutputDevice(int deviceId, int sampleRate=-1);
     int getOutputDevice();
-    void setSampleRate(int sampleRate);
+   
     int getSampleRate();
+
     virtual void run();
     virtual void terminate();
 
@@ -78,11 +99,31 @@ public:
     void setActive(bool state);
 
     void setGain(float gain_in);
-    float getGain();
+   
+    static std::map<int, int> deviceSampleRate;
 
     AudioThreadCommandQueue *getCommandQueue();
 
+    //give access to the this AudioThread lock
+    std::recursive_mutex& getMutex();
+
+    static void deviceCleanup();
+    static void setDeviceSampleRate(int deviceId, int sampleRate);
+
+    //fields below, only to be used by other AudioThreads !
+    size_t underflowCount;
+    //protected by m_mutex
+    std::vector<AudioThread *> boundThreads;
+    AudioThreadInputQueuePtr inputQueue;
+    AudioThreadInputPtr currentInput;
+    size_t audioQueuePtr;
+    float gain;
+
 private:
+
+    std::atomic_bool active;
+    std::atomic_int outputDevice;
+    
     RtAudio dac;
     unsigned int nBufferFrames;
     RtAudio::StreamOptions opts;
@@ -93,20 +134,16 @@ private:
     //The own m_mutex protecting this AudioThread, in particular boundThreads
     std::recursive_mutex m_mutex;
 
-public:
-    //give access to the this AudioThread lock
-    std::recursive_mutex& getMutex();
+    void setupDevice(int deviceId);
+    void setSampleRate(int sampleRate);
 
     void bindThread(AudioThread *other);
     void removeThread(AudioThread *other);
 
-    static std::map<int,AudioThread *> deviceController;
-    static std::map<int,int> deviceSampleRate;
-    static std::map<int,std::thread *> deviceThread;
-    static void deviceCleanup();
-    static void setDeviceSampleRate(int deviceId, int sampleRate);
-
-    //protected by m_mutex
-   std::vector<AudioThread *> boundThreads;
+    static std::map<int, AudioThread *> deviceController;
+    static std::map<int, std::thread *> deviceThread;
+	
+	//The mutex protecting static deviceController, deviceThread and deviceSampleRate access.
+	static std::recursive_mutex m_device_mutex;
 };
 
diff --git a/src/demod/DemodDefs.h b/src/demod/DemodDefs.h
index d4a922a..bb0a63c 100644
--- a/src/demod/DemodDefs.h
+++ b/src/demod/DemodDefs.h
@@ -9,12 +9,12 @@
 #include <vector>
 #include <atomic>
 #include <mutex>
+#include <memory>
 
 #include "IOThread.h"
 
 class DemodulatorThread;
 
-
 class DemodulatorThreadControlCommand {
 public:
     enum DemodulatorThreadControlCommandEnum {
@@ -29,7 +29,7 @@ public:
     std::string demodType;
 };
 
-class DemodulatorThreadIQData: public ReferenceCounter {
+class DemodulatorThreadIQData {
 public:
     long long frequency;
     long long sampleRate;
@@ -48,7 +48,7 @@ public:
         return *this;
     }
 
-    ~DemodulatorThreadIQData() {
+    virtual ~DemodulatorThreadIQData() {
 
     }
 };
@@ -56,7 +56,7 @@ public:
 class Modem;
 class ModemKit;
 
-class DemodulatorThreadPostIQData: public ReferenceCounter {
+class DemodulatorThreadPostIQData {
 public:
     std::vector<liquid_float_complex> data;
 
@@ -71,13 +71,13 @@ public:
 
     }
 
-    ~DemodulatorThreadPostIQData() {
-        std::lock_guard < std::recursive_mutex > lock(m_mutex);
+    virtual ~DemodulatorThreadPostIQData() {
+       
     }
 };
 
 
-class DemodulatorThreadAudioData: public ReferenceCounter {
+class DemodulatorThreadAudioData {
 public:
     long long frequency;
     unsigned int sampleRate;
@@ -95,11 +95,17 @@ public:
 
     }
 
-    ~DemodulatorThreadAudioData() {
+    virtual ~DemodulatorThreadAudioData() {
 
     }
 };
+typedef std::shared_ptr<DemodulatorThreadIQData> DemodulatorThreadIQDataPtr;
+typedef std::shared_ptr<DemodulatorThreadPostIQData> DemodulatorThreadPostIQDataPtr;
 
-typedef ThreadBlockingQueue<DemodulatorThreadIQData *> DemodulatorThreadInputQueue;
-typedef ThreadBlockingQueue<DemodulatorThreadPostIQData *> DemodulatorThreadPostInputQueue;
+typedef ThreadBlockingQueue<DemodulatorThreadIQDataPtr> DemodulatorThreadInputQueue;
+typedef ThreadBlockingQueue<DemodulatorThreadPostIQDataPtr> DemodulatorThreadPostInputQueue;
 typedef ThreadBlockingQueue<DemodulatorThreadControlCommand> DemodulatorThreadControlCommandQueue;
+
+typedef std::shared_ptr<DemodulatorThreadInputQueue> DemodulatorThreadInputQueuePtr;
+typedef std::shared_ptr<DemodulatorThreadPostInputQueue> DemodulatorThreadPostInputQueuePtr;
+typedef std::shared_ptr<DemodulatorThreadControlCommandQueue> DemodulatorThreadControlCommandQueuePtr;
diff --git a/src/demod/DemodulatorInstance.cpp b/src/demod/DemodulatorInstance.cpp
index 355daa6..39e9014 100644
--- a/src/demod/DemodulatorInstance.cpp
+++ b/src/demod/DemodulatorInstance.cpp
@@ -1,9 +1,17 @@
 // Copyright (c) Charles J. Cliffe
 // SPDX-License-Identifier: GPL-2.0+
 
+#include <memory>
+#include <iomanip>
+
 #include "DemodulatorInstance.h"
 #include "CubicSDR.h"
 
+#include "DemodulatorThread.h"
+#include "DemodulatorPreThread.h"
+#include "AudioSinkFileThread.h"
+#include "AudioFileWAV.h"
+
 #if USE_HAMLIB
 #include "RigThread.h"
 #endif
@@ -42,6 +50,7 @@ DemodulatorInstance::DemodulatorInstance() {
 	active.store(false);
 	squelch.store(false);
     muted.store(false);
+    recording.store(false);
     deltaLock.store(false);
     deltaLockOfs.store(0);
 	currentOutputDevice.store(-1);
@@ -52,9 +61,9 @@ DemodulatorInstance::DemodulatorInstance() {
     label.store(new std::string("Unnamed"));
     user_label.store(new std::wstring());
 
-    pipeIQInputData = new DemodulatorThreadInputQueue;
+    pipeIQInputData = std::make_shared<DemodulatorThreadInputQueue>();
     pipeIQInputData->set_max_num_items(100);
-    pipeIQDemodData = new DemodulatorThreadPostInputQueue;
+    pipeIQDemodData = std::make_shared< DemodulatorThreadPostInputQueue>();
     pipeIQInputData->set_max_num_items(100);
     
     audioThread = new AudioThread();
@@ -63,10 +72,10 @@ DemodulatorInstance::DemodulatorInstance() {
     demodulatorPreThread->setInputQueue("IQDataInput",pipeIQInputData);
     demodulatorPreThread->setOutputQueue("IQDataOutput",pipeIQDemodData);
             
-    pipeAudioData = new AudioThreadInputQueue;
+    pipeAudioData = std::make_shared<AudioThreadInputQueue>();
     pipeAudioData->set_max_num_items(10);
 
-    threadQueueControl = new DemodulatorThreadControlCommandQueue;
+    threadQueueControl = std::make_shared<DemodulatorThreadControlCommandQueue>();
     threadQueueControl->set_max_num_items(2);
 
     demodulatorThread = new DemodulatorThread(this);
@@ -78,25 +87,48 @@ DemodulatorInstance::DemodulatorInstance() {
 }
 
 DemodulatorInstance::~DemodulatorInstance() {
-#if ENABLE_DIGITAL_LAB
-    delete activeOutput;
-#endif
-    delete audioThread;
-    delete demodulatorThread;
-    delete demodulatorPreThread;
-    delete pipeIQInputData;
-    delete pipeIQDemodData;
-    delete threadQueueControl;
-    delete pipeAudioData;
     
-    wxGetApp().getBookmarkMgr().updateActiveList();
+    std::lock_guard < std::recursive_mutex > lockData(m_thread_control_mutex);
+
+    //now that DemodulatorInstance are managed through shared_ptr, we 
+    //should enter here ONLY when it is no longer used by any piece of code, anywhere.
+    //so active wait on IsTerminated(), then die.
+#define TERMINATION_SPIN_WAIT_MS (20)
+#define MAX_WAIT_FOR_TERMINATION_MS (3000.0)
+    //this is a stupid busy plus sleep loop
+    int  nbCyclesToWait = (MAX_WAIT_FOR_TERMINATION_MS / TERMINATION_SPIN_WAIT_MS) + 1;
+    int currentCycle = 0;
+
+    while (currentCycle < nbCyclesToWait) {
+        
+        if (isTerminated()) {
+            std::cout << "Garbage collected demodulator instance '" << getLabel() << "'... " << std::endl << std::flush;
+
+#if ENABLE_DIGITAL_LAB
+            delete activeOutput;
+#endif           
+            delete demodulatorPreThread;
+            delete demodulatorThread;
+            delete audioThread;
+            delete audioSinkThread;
+
+            break;
+        }
+        else {
+            std::this_thread::sleep_for(std::chrono::milliseconds(TERMINATION_SPIN_WAIT_MS));
+        }
+        currentCycle++;
+    } //end while
 }
 
-void DemodulatorInstance::setVisualOutputQueue(DemodulatorThreadOutputQueue *tQueue) {
+void DemodulatorInstance::setVisualOutputQueue(DemodulatorThreadOutputQueuePtr tQueue) {
     demodulatorThread->setOutputQueue("AudioVisualOutput", tQueue);
 }
 
 void DemodulatorInstance::run() {
+
+    std::lock_guard < std::recursive_mutex > lockData(m_thread_control_mutex);
+
     if (active) {
         return;
     }
@@ -127,8 +159,6 @@ void DemodulatorInstance::run() {
 #endif
 
     active = true;
-
-    wxGetApp().getBookmarkMgr().updateActiveList();
 }
 
 void DemodulatorInstance::updateLabel(long long freq) {
@@ -149,10 +179,22 @@ void DemodulatorInstance::terminate() {
 
 //    std::cout << "Terminating demodulator audio thread.." << std::endl;
     audioThread->terminate();
+
 //    std::cout << "Terminating demodulator thread.." << std::endl;
     demodulatorThread->terminate();
+   
 //    std::cout << "Terminating demodulator preprocessor thread.." << std::endl;
     demodulatorPreThread->terminate();
+
+    if (audioSinkThread != nullptr) {
+        stopRecording();
+    }
+
+    //that will actually unblock the currently blocked push().
+    pipeIQInputData->flush();
+    pipeAudioData->flush();
+    pipeIQDemodData->flush();
+    threadQueueControl->flush();
 }
 
 std::string DemodulatorInstance::getLabel() {
@@ -166,20 +208,30 @@ void DemodulatorInstance::setLabel(std::string labelStr) {
 
 bool DemodulatorInstance::isTerminated() {
 
-    //
+    std::lock_guard < std::recursive_mutex > lockData(m_thread_control_mutex);
+
     bool audioTerminated = audioThread->isTerminated();
     bool demodTerminated = demodulatorThread->isTerminated();
     bool preDemodTerminated = demodulatorPreThread->isTerminated();
+    bool audioSinkTerminated = (audioSinkThread == nullptr) || audioSinkThread->isTerminated();
 
-    //Cleanup the worker threads, if the threads are indeed terminated
-    if (audioTerminated) {
+    //Cleanup the worker threads, if the threads are indeed terminated.
+    // threads are linked as  t_PreDemod ==> t_Demod ==> t_Audio
+    //so terminate in the same order to starve the following threads in succession.
+    //i.e waiting on timed-pop so able to se their stopping flag.
 
-        if (t_Audio) {
-            t_Audio->join();
+    if (preDemodTerminated) {
+        
+         if (t_PreDemod) {
 
-            delete t_Audio;
-            t_Audio = nullptr;
-        }
+#ifdef __APPLE__
+            pthread_join(t_PreDemod, NULL);
+#else
+            t_PreDemod->join();
+            delete t_PreDemod;
+#endif
+            t_PreDemod = nullptr;
+         }
     }
 
     if (demodTerminated) {
@@ -195,21 +247,30 @@ bool DemodulatorInstance::isTerminated() {
         }
     }
 
-    if (preDemodTerminated) {
-        
-         if (t_PreDemod) {
+    if (audioTerminated) {
 
+        if (t_Audio) {
 #ifdef __APPLE__
             pthread_join(t_PreDemod, NULL);
 #else
-            t_PreDemod->join();
-            delete t_PreDemod;
+            t_Audio->join();
+            delete t_Audio;
 #endif
-            t_PreDemod = nullptr;
-         }
+            t_Audio = nullptr;
+        }
+    }
+
+    if (audioSinkTerminated) {
+
+        if (t_AudioSink != nullptr) {
+            t_AudioSink->join();
+
+            delete t_AudioSink;
+            t_AudioSink = nullptr;
+        }
     }
 
-    bool terminated = audioTerminated && demodTerminated && preDemodTerminated;
+    bool terminated = audioTerminated && demodTerminated && preDemodTerminated && audioSinkTerminated;
 
     return terminated;
 }
@@ -218,7 +279,7 @@ bool DemodulatorInstance::isActive() {
     return active;
 }
 
-void DemodulatorInstance::setActive(bool state) {
+void DemodulatorInstance::setActive(bool state) {    
     if (active && !state) {
 #if ENABLE_DIGITAL_LAB
         if (activeOutput) {
@@ -226,7 +287,9 @@ void DemodulatorInstance::setActive(bool state) {
         }
 #endif
         audioThread->setActive(state);
+  
         DemodulatorThread::releaseSquelchLock(this);
+
     } else if (!active && state) {
 #if ENABLE_DIGITAL_LAB
         if (activeOutput && getModemType() == "digital") {
@@ -406,7 +469,7 @@ void DemodulatorInstance::setFrequency(long long freq) {
     }
 #endif
 #if USE_HAMLIB
-    if (wxGetApp().rigIsActive() && wxGetApp().getRigThread()->getFollowModem() && wxGetApp().getDemodMgr().getLastActiveDemodulator() == this) {
+    if (wxGetApp().rigIsActive() && wxGetApp().getRigThread()->getFollowModem() && wxGetApp().getDemodMgr().getLastActiveDemodulator().get() == this) {
         wxGetApp().getRigThread()->setFrequency(freq,true);
     }
 #endif
@@ -483,11 +546,26 @@ void DemodulatorInstance::setMuted(bool muted) {
     wxGetApp().getDemodMgr().setLastMuted(muted);
 }
 
+bool DemodulatorInstance::isRecording()
+{
+    return recording.load();
+}
+
+void DemodulatorInstance::setRecording(bool recording_in)
+{
+    if (!recording.load() && recording_in) {
+        startRecording();
+    }
+    else if (recording.load() && !recording_in) {
+        stopRecording();
+    }
+}
+
 DemodVisualCue *DemodulatorInstance::getVisualCue() {
     return &visualCue;
 }
 
-DemodulatorThreadInputQueue *DemodulatorInstance::getIQInputDataPipe() {
+DemodulatorThreadInputQueuePtr DemodulatorInstance::getIQInputDataPipe() {
     return pipeIQInputData;
 }
 
@@ -540,6 +618,65 @@ ModemSettings DemodulatorInstance::getLastModemSettings(std::string demodType) {
     }
 }
 
+
+void DemodulatorInstance::startRecording() {
+    if (recording.load()) {
+        return;
+    }
+
+    AudioSinkFileThread *newSinkThread = new AudioSinkFileThread();
+    AudioFileWAV *afHandler = new AudioFileWAV();
+
+    std::stringstream fileName;
+    
+    std::wstring userLabel = getDemodulatorUserLabel();
+
+    wxString userLabelForFileName(userLabel);
+    std::string userLabelStr = userLabelForFileName.ToStdString();
+
+    if (!userLabelStr.empty()) {
+        fileName << userLabelStr;
+    } else {
+        fileName << getLabel();
+    }
+   
+	newSinkThread->setAudioFileNameBase(fileName.str());
+
+	//attach options:
+    newSinkThread->setSquelchOption(wxGetApp().getConfig()->getRecordingSquelchOption());
+	newSinkThread->setFileTimeLimit(wxGetApp().getConfig()->getRecordingFileTimeLimit());
+
+    newSinkThread->setAudioFileHandler(afHandler);
+
+    audioSinkThread = newSinkThread;
+    t_AudioSink = new std::thread(&AudioSinkThread::threadMain, audioSinkThread);
+
+    demodulatorThread->setOutputQueue("AudioSink", audioSinkThread->getInputQueue("input"));
+
+    recording.store(true);
+}
+
+
+void DemodulatorInstance::stopRecording() {
+    if (!recording.load()) {
+        return;
+    }
+
+    demodulatorThread->setOutputQueue("AudioSink", nullptr);
+    audioSinkThread->terminate();
+    
+    t_AudioSink->join();
+
+    delete t_AudioSink;
+    delete audioSinkThread;
+
+    t_AudioSink = nullptr;
+    audioSinkThread = nullptr;
+
+    recording.store(false);
+}
+
+
 #if ENABLE_DIGITAL_LAB
 ModemDigitalOutput *DemodulatorInstance::getOutput() {
     if (activeOutput == nullptr) {
diff --git a/src/demod/DemodulatorInstance.h b/src/demod/DemodulatorInstance.h
index 749c6ec..297df69 100644
--- a/src/demod/DemodulatorInstance.h
+++ b/src/demod/DemodulatorInstance.h
@@ -6,12 +6,12 @@
 #include <vector>
 #include <map>
 #include <thread>
-
-#include "DemodulatorThread.h"
-#include "DemodulatorPreThread.h"
-
+#include <memory>
+#include "DemodDefs.h"
 #include "ModemDigital.h"
 #include "ModemAnalog.h"
+#include "AudioThread.h"
+#include "AudioSinkThread.h"
 
 #if ENABLE_DIGITAL_LAB
 #include "DigitalConsole.h"
@@ -30,6 +30,8 @@ private:
     std::atomic_int squelchBreak;
 };
 
+class DemodulatorThread;
+class DemodulatorPreThread;
 
 class DemodulatorInstance {
 public:
@@ -48,7 +50,7 @@ public:
     DemodulatorInstance();
     ~DemodulatorInstance();
 
-    void setVisualOutputQueue(DemodulatorThreadOutputQueue *tQueue);
+    void setVisualOutputQueue(DemodulatorThreadOutputQueuePtr tQueue);
 
     void run();
     void terminate();
@@ -109,9 +111,12 @@ public:
     bool isMuted();
     void setMuted(bool muted);
 
+    bool isRecording();
+    void setRecording(bool recording);
+
     DemodVisualCue *getVisualCue();
     
-    DemodulatorThreadInputQueue *getIQInputDataPipe();
+    DemodulatorThreadInputQueuePtr getIQInputDataPipe();
 
     ModemArgInfoList getModemArgs();
     std::string readModemSetting(std::string setting);
@@ -131,14 +136,23 @@ public:
 #endif
         
 protected:
-    DemodulatorThreadInputQueue* pipeIQInputData;
-    DemodulatorThreadPostInputQueue* pipeIQDemodData;
-    AudioThreadInputQueue *pipeAudioData;
+    void startRecording();
+    void stopRecording();
+
+private:
+    DemodulatorThreadInputQueuePtr pipeIQInputData;
+    DemodulatorThreadPostInputQueuePtr pipeIQDemodData;
+    AudioThreadInputQueuePtr pipeAudioData;
     DemodulatorPreThread *demodulatorPreThread;
     DemodulatorThread *demodulatorThread;
-    DemodulatorThreadControlCommandQueue *threadQueueControl;
+    DemodulatorThreadControlCommandQueuePtr threadQueueControl;
 
-private:
+    AudioSinkThread *audioSinkThread = nullptr;
+    std::thread *t_AudioSink = nullptr;
+    AudioThreadInputQueuePtr audioSinkInputQueue;
+
+    //protects child thread creation and termination 
+    std::recursive_mutex m_thread_control_mutex;
 
     std::atomic<std::string *> label; //
     // User editable buffer, 16 bit string.
@@ -148,6 +162,8 @@ private:
     std::atomic_bool squelch;
     std::atomic_bool muted;
     std::atomic_bool deltaLock;
+    std::atomic_bool recording;
+
     std::atomic_int deltaLockOfs;
 
     std::atomic_int currentOutputDevice;
@@ -160,3 +176,5 @@ private:
     ModemDigitalOutput *activeOutput;
 #endif
 };
+
+typedef std::shared_ptr<DemodulatorInstance> DemodulatorInstancePtr;
diff --git a/src/demod/DemodulatorMgr.cpp b/src/demod/DemodulatorMgr.cpp
index 4fa9e85..40978b9 100644
--- a/src/demod/DemodulatorMgr.cpp
+++ b/src/demod/DemodulatorMgr.cpp
@@ -17,13 +17,11 @@
 
 #include "DataTree.h"
 
-bool demodFreqCompare (DemodulatorInstance *i, DemodulatorInstance *j) { return (i->getFrequency()<j->getFrequency()); }
-bool inactiveCompare (DemodulatorInstance *i, DemodulatorInstance *j) { return (i->isActive()<j->isActive()); }
+bool demodFreqCompare (DemodulatorInstancePtr i, DemodulatorInstancePtr j) { return (i->getFrequency() < j->getFrequency()); }
+bool inactiveCompare (DemodulatorInstancePtr i, DemodulatorInstancePtr j) { return (i->isActive() < j->isActive()); }
 
 DemodulatorMgr::DemodulatorMgr() {
-    activeDemodulator = NULL;
-    lastActiveDemodulator = NULL;
-    activeVisualDemodulator = NULL;
+
     lastBandwidth = DEFAULT_DEMOD_BW;
     lastDemodType = DEFAULT_DEMOD_TYPE;
     lastSquelchEnabled = false;
@@ -37,9 +35,11 @@ DemodulatorMgr::~DemodulatorMgr() {
     terminateAll();
 }
 
-DemodulatorInstance *DemodulatorMgr::newThread() {
+DemodulatorInstancePtr DemodulatorMgr::newThread() {
     std::lock_guard < std::recursive_mutex > lock(demods_busy);
-    DemodulatorInstance *newDemod = new DemodulatorInstance;
+    
+    //create a new instance of DemodulatorInstance here.
+    DemodulatorInstancePtr newDemod = std::make_shared<DemodulatorInstance>();
 
     std::stringstream label;
     label << demods.size();
@@ -51,27 +51,33 @@ DemodulatorInstance *DemodulatorMgr::newThread() {
 }
 
 void DemodulatorMgr::terminateAll() {
+
     std::lock_guard < std::recursive_mutex > lock(demods_busy);
+    
     while (demods.size()) {
 
-        DemodulatorInstance *d = demods.back();
+        DemodulatorInstancePtr d = demods.back();
         demods.pop_back();
-        wxGetApp().removeDemodulator(d);
         deleteThread(d);
     }
 }
 
-std::vector<DemodulatorInstance *> &DemodulatorMgr::getDemodulators() {
+std::vector<DemodulatorInstancePtr> DemodulatorMgr::getDemodulators() {
     std::lock_guard < std::recursive_mutex > lock(demods_busy);
     return demods;
 }
 
-std::vector<DemodulatorInstance *> DemodulatorMgr::getOrderedDemodulators(bool actives) {
+std::vector<DemodulatorInstancePtr> DemodulatorMgr::getOrderedDemodulators(bool actives) {
     std::lock_guard < std::recursive_mutex > lock(demods_busy);
-    std::vector<DemodulatorInstance *> demods_ordered = demods;
+    
+    auto demods_ordered = demods;
+    
     if (actives) {
+        
         std::sort(demods_ordered.begin(), demods_ordered.end(), inactiveCompare);
-        std::vector<DemodulatorInstance *>::iterator i;
+        
+        std::vector<DemodulatorInstancePtr>::iterator i;
+        
         for (i = demods_ordered.begin(); i != demods_ordered.end(); i++) {
             if ((*i)->isActive()) {
                 break;
@@ -88,13 +94,14 @@ std::vector<DemodulatorInstance *> DemodulatorMgr::getOrderedDemodulators(bool a
     return demods_ordered;
 }
 
-DemodulatorInstance *DemodulatorMgr::getPreviousDemodulator(DemodulatorInstance *demod, bool actives) {
+DemodulatorInstancePtr DemodulatorMgr::getPreviousDemodulator(DemodulatorInstancePtr demod, bool actives) {
     std::lock_guard < std::recursive_mutex > lock(demods_busy);
     if (!getLastActiveDemodulator()) {
         return nullptr;
     }
-    std::vector<DemodulatorInstance *> demods_ordered = getOrderedDemodulators(actives);
-    std::vector<DemodulatorInstance *>::iterator p = std::find(demods_ordered.begin(), demods_ordered.end(), demod);
+    auto demods_ordered = getOrderedDemodulators(actives);
+    auto p = std::find(demods_ordered.begin(), demods_ordered.end(), demod);
+
     if (p == demods_ordered.end()) {
         return nullptr;
     }
@@ -104,13 +111,14 @@ DemodulatorInstance *DemodulatorMgr::getPreviousDemodulator(DemodulatorInstance
     return *(--p);
 }
 
-DemodulatorInstance *DemodulatorMgr::getNextDemodulator(DemodulatorInstance *demod, bool actives) {
+DemodulatorInstancePtr DemodulatorMgr::getNextDemodulator(DemodulatorInstancePtr demod, bool actives) {
     std::lock_guard < std::recursive_mutex > lock(demods_busy);
     if (!getLastActiveDemodulator()) {
         return nullptr;
     }
-    std::vector<DemodulatorInstance *> demods_ordered = getOrderedDemodulators(actives);
-    std::vector<DemodulatorInstance *>::iterator p = std::find(demods_ordered.begin(), demods_ordered.end(), demod);
+    auto demods_ordered = getOrderedDemodulators(actives);
+    auto p = std::find(demods_ordered.begin(), demods_ordered.end(), demod);
+
     if (actives) {
         
     }
@@ -123,26 +131,25 @@ DemodulatorInstance *DemodulatorMgr::getNextDemodulator(DemodulatorInstance *dem
     return *(++p);
 }
 
-DemodulatorInstance *DemodulatorMgr::getLastDemodulator() {
+DemodulatorInstancePtr DemodulatorMgr::getLastDemodulator() {
     std::lock_guard < std::recursive_mutex > lock(demods_busy);
-    std::vector<DemodulatorInstance *> demods_ordered = getOrderedDemodulators();
-    return *(demods_ordered.end());
+    
+    return getOrderedDemodulators().back();
 }
 
-DemodulatorInstance *DemodulatorMgr::getFirstDemodulator() {
+DemodulatorInstancePtr DemodulatorMgr::getFirstDemodulator() {
     std::lock_guard < std::recursive_mutex > lock(demods_busy);
-    std::vector<DemodulatorInstance *> demods_ordered = getOrderedDemodulators();
-    return *(demods_ordered.begin());
+    
+    return getOrderedDemodulators().front();
 }
 
-void DemodulatorMgr::deleteThread(DemodulatorInstance *demod) {
+void DemodulatorMgr::deleteThread(DemodulatorInstancePtr demod) {
+    
     std::lock_guard < std::recursive_mutex > lock(demods_busy);
 
     wxGetApp().getBookmarkMgr().addRecent(demod);
-    
-    std::vector<DemodulatorInstance *>::iterator i;
-
-    i = std::find(demods.begin(), demods.end(), demod);
+  
+    auto i = std::find(demods.begin(), demods.end(), demod);
 
     if (activeDemodulator == demod) {
         activeDemodulator = nullptr;
@@ -161,18 +168,15 @@ void DemodulatorMgr::deleteThread(DemodulatorInstance *demod) {
     //Ask for termination
     demod->setActive(false);
     demod->terminate();
-
-    //Do not cleanup immediatly
-    demods_deleted.push_back(demod);
 }
 
-std::vector<DemodulatorInstance *> DemodulatorMgr::getDemodulatorsAt(long long freq, int bandwidth) {
+std::vector<DemodulatorInstancePtr> DemodulatorMgr::getDemodulatorsAt(long long freq, int bandwidth) {
     std::lock_guard < std::recursive_mutex > lock(demods_busy);
     
-    std::vector<DemodulatorInstance *> foundDemods;
+    std::vector<DemodulatorInstancePtr> foundDemods;
 
     for (int i = 0, iMax = demods.size(); i < iMax; i++) {
-        DemodulatorInstance *testDemod = demods[i];
+        DemodulatorInstancePtr testDemod = demods[i];
 
         long long freqTest = testDemod->getFrequency();
         long long bandwidthTest = testDemod->getBandwidth();
@@ -191,7 +195,7 @@ std::vector<DemodulatorInstance *> DemodulatorMgr::getDemodulatorsAt(long long f
 bool DemodulatorMgr::anyDemodulatorsAt(long long freq, int bandwidth) {
     std::lock_guard < std::recursive_mutex > lock(demods_busy);
     for (int i = 0, iMax = demods.size(); i < iMax; i++) {
-        DemodulatorInstance *testDemod = demods[i];
+        DemodulatorInstancePtr testDemod = demods[i];
 
         long long freqTest = testDemod->getFrequency();
         long long bandwidthTest = testDemod->getBandwidth();
@@ -209,36 +213,34 @@ bool DemodulatorMgr::anyDemodulatorsAt(long long freq, int bandwidth) {
 }
 
 
-void DemodulatorMgr::setActiveDemodulator(DemodulatorInstance *demod, bool temporary) {
+void DemodulatorMgr::setActiveDemodulator(DemodulatorInstancePtr demod, bool temporary) {
+    
+    std::lock_guard < std::recursive_mutex > lock(demods_busy);
     
     if (!temporary) {
-        if (activeDemodulator.load() != nullptr) {
-            lastActiveDemodulator = activeDemodulator.load();
+        if (activeDemodulator != nullptr) {
+            lastActiveDemodulator = activeDemodulator;
             updateLastState();
         } else {
             lastActiveDemodulator = demod;
         }
         updateLastState();
 #if USE_HAMLIB
-        if (wxGetApp().rigIsActive() && wxGetApp().getRigThread()->getFollowModem() && lastActiveDemodulator.load()) {
-            wxGetApp().getRigThread()->setFrequency(lastActiveDemodulator.load()->getFrequency(),true);
+        if (wxGetApp().rigIsActive() && wxGetApp().getRigThread()->getFollowModem() && lastActiveDemodulator) {
+            wxGetApp().getRigThread()->setFrequency(lastActiveDemodulator->getFrequency(),true);
         }
 #endif
         wxGetApp().getBookmarkMgr().updateActiveList();
-    } else {
-        std::lock_guard < std::recursive_mutex > lock(demods_busy);
-        garbageCollect();
-        ReBufferGC::garbageCollect();
-    }
+    } 
 
-    if (activeVisualDemodulator.load()) {
-        activeVisualDemodulator.load()->setVisualOutputQueue(nullptr);
+    if (activeVisualDemodulator) {
+        activeVisualDemodulator->setVisualOutputQueue(nullptr);
     }
     if (demod) {
         demod->setVisualOutputQueue(wxGetApp().getAudioVisualQueue());
         activeVisualDemodulator = demod;
     } else {
-        DemodulatorInstance *last = getLastActiveDemodulator();
+        DemodulatorInstancePtr last = getLastActiveDemodulator();
         if (last) {
             last->setVisualOutputQueue(wxGetApp().getAudioVisualQueue());
         }
@@ -249,25 +251,41 @@ void DemodulatorMgr::setActiveDemodulator(DemodulatorInstance *demod, bool tempo
 
 }
 
-DemodulatorInstance *DemodulatorMgr::getActiveDemodulator() {
-    if (activeDemodulator.load() && !activeDemodulator.load()->isActive()) {
+//Dangerous: this is only intended by some internal classes
+void DemodulatorMgr::setActiveDemodulatorByRawPointer(DemodulatorInstance* demod, bool temporary) {
+    std::lock_guard < std::recursive_mutex > lock(demods_busy);
+
+    for (auto existing_demod : demods) {
+
+        if (existing_demod.get() == demod) {
+
+            setActiveDemodulator(existing_demod, temporary);
+            break;
+        }
+    }
+}
+
+DemodulatorInstancePtr DemodulatorMgr::getActiveDemodulator() {
+    std::lock_guard < std::recursive_mutex > lock(demods_busy);
+
+    if (activeDemodulator && !activeDemodulator->isActive()) {
         activeDemodulator = getLastActiveDemodulator();
     }
     return activeDemodulator;
 }
 
-DemodulatorInstance *DemodulatorMgr::getLastActiveDemodulator() {
+DemodulatorInstancePtr DemodulatorMgr::getLastActiveDemodulator() {
     return lastActiveDemodulator;
 }
 
-DemodulatorInstance *DemodulatorMgr::getLastDemodulatorWith(const std::string& type,
+DemodulatorInstancePtr DemodulatorMgr::getLastDemodulatorWith(const std::string& type,
 															const std::wstring& userLabel,
 															long long frequency,
 															int bandwidth) {
 	std::lock_guard < std::recursive_mutex > lock(demods_busy);
 
 	//backwards search: 
-	for (std::vector<DemodulatorInstance *>::reverse_iterator it = demods.rbegin(); it != demods.rend(); it++) {
+	for (auto it = demods.rbegin(); it != demods.rend(); it++) {
 
 		if ((*it)->getDemodulatorType() == type &&
 			(*it)->getDemodulatorUserLabel() == userLabel &&
@@ -281,51 +299,31 @@ DemodulatorInstance *DemodulatorMgr::getLastDemodulatorWith(const std::string& t
 	return nullptr;
 }
 
-//Private internal method, no need to protect it with demods_busy
-void DemodulatorMgr::garbageCollect() {
-    if (demods_deleted.size()) {
-      
-        std::vector<DemodulatorInstance *>::iterator i;
-
-        for (i = demods_deleted.begin(); i != demods_deleted.end(); i++) {
-            if ((*i)->isTerminated()) {
-                DemodulatorInstance *deleted = (*i);
-                demods_deleted.erase(i);
-
-                std::cout << "Garbage collected demodulator instance " << deleted->getLabel() << std::endl;
-
-                delete deleted;
-                return;
-            }
-        }
-      
-    }
-}
 
 void DemodulatorMgr::updateLastState() {
     std::lock_guard < std::recursive_mutex > lock(demods_busy);
 
     if (std::find(demods.begin(), demods.end(), lastActiveDemodulator) == demods.end()) {
-        if (activeDemodulator.load() && activeDemodulator.load()->isActive()) {
-            lastActiveDemodulator = activeDemodulator.load();
-        } else if (activeDemodulator.load() && !activeDemodulator.load()->isActive()){
+        if (activeDemodulator && activeDemodulator->isActive()) {
+            lastActiveDemodulator = activeDemodulator;
+        } else if (activeDemodulator && !activeDemodulator->isActive()){
             activeDemodulator = nullptr;
             lastActiveDemodulator = nullptr;
         }
     }
 
-    if (lastActiveDemodulator.load() && !lastActiveDemodulator.load()->isActive()) {
+    if (lastActiveDemodulator && !lastActiveDemodulator->isActive()) {
         lastActiveDemodulator = nullptr;
     }
 
-    if (lastActiveDemodulator.load()) {
-        lastBandwidth = lastActiveDemodulator.load()->getBandwidth();
-        lastDemodType = lastActiveDemodulator.load()->getDemodulatorType();
-        lastDemodLock = lastActiveDemodulator.load()->getDemodulatorLock()?true:false;
-        lastSquelchEnabled = lastActiveDemodulator.load()->isSquelchEnabled();
-        lastSquelch = lastActiveDemodulator.load()->getSquelchLevel();
-        lastGain = lastActiveDemodulator.load()->getGain();
-        lastModemSettings[lastDemodType] = lastActiveDemodulator.load()->readModemSettings();
+    if (lastActiveDemodulator) {
+        lastBandwidth = lastActiveDemodulator->getBandwidth();
+        lastDemodType = lastActiveDemodulator->getDemodulatorType();
+        lastDemodLock = lastActiveDemodulator->getDemodulatorLock()?true:false;
+        lastSquelchEnabled = lastActiveDemodulator->isSquelchEnabled();
+        lastSquelch = lastActiveDemodulator->getSquelchLevel();
+        lastGain = lastActiveDemodulator->getGain();
+        lastModemSettings[lastDemodType] = lastActiveDemodulator->readModemSettings();
     }
 
 }
@@ -404,7 +402,8 @@ void DemodulatorMgr::setOutputDevices(std::map<int,RtAudio::DeviceInfo> devs) {
     outputDevices = devs;
 }
 
-void DemodulatorMgr::saveInstance(DataNode *node, DemodulatorInstance *inst) {
+void DemodulatorMgr::saveInstance(DataNode *node, DemodulatorInstancePtr inst) {
+
     *node->newChild("bandwidth") = inst->getBandwidth();
     *node->newChild("frequency") = inst->getFrequency();  
     *node->newChild("type") = inst->getDemodulatorType();
@@ -431,14 +430,13 @@ void DemodulatorMgr::saveInstance(DataNode *node, DemodulatorInstance *inst) {
             *settingsNode->newChild(msi->first.c_str()) = msi->second;
         }
     }
-
 }
 
-DemodulatorInstance *DemodulatorMgr::loadInstance(DataNode *node) {
+DemodulatorInstancePtr DemodulatorMgr::loadInstance(DataNode *node) {
 
 	std::lock_guard < std::recursive_mutex > lock(demods_busy);
 
-    DemodulatorInstance *newDemod = nullptr;
+    DemodulatorInstancePtr newDemod = nullptr;
 	 
     node->rewindAll();
     
@@ -526,15 +524,21 @@ DemodulatorInstance *DemodulatorMgr::loadInstance(DataNode *node) {
     }
     
 	//Attach to sound output:
-    bool found_device = false;
     std::map<int, RtAudio::DeviceInfo>::iterator i;
+
+	bool matching_device_found = false;
+
     for (i = outputDevices.begin(); i != outputDevices.end(); i++) {
         if (i->second.name == output_device) {
             newDemod->setOutputDevice(i->first);
-            found_device = true;
+			matching_device_found = true;
 			break;
         }
     }
+	//if no device is found, choose the first of the list anyway.
+	if (!matching_device_found) {
+		newDemod->setOutputDevice(outputDevices.begin()->first);
+	}
     
     return newDemod;
 }
diff --git a/src/demod/DemodulatorMgr.h b/src/demod/DemodulatorMgr.h
index ca65c22..b080e5f 100644
--- a/src/demod/DemodulatorMgr.h
+++ b/src/demod/DemodulatorMgr.h
@@ -16,23 +16,32 @@ public:
     DemodulatorMgr();
     ~DemodulatorMgr();
 
-    DemodulatorInstance *newThread();
-    std::vector<DemodulatorInstance *> &getDemodulators();
-    std::vector<DemodulatorInstance *> getOrderedDemodulators(bool actives = true);
-    std::vector<DemodulatorInstance *> getDemodulatorsAt(long long freq, int bandwidth);
-    DemodulatorInstance *getPreviousDemodulator(DemodulatorInstance *demod, bool actives = true);
-    DemodulatorInstance *getNextDemodulator(DemodulatorInstance *demod, bool actives = true);
-    DemodulatorInstance *getLastDemodulator();
-    DemodulatorInstance *getFirstDemodulator();
+    DemodulatorInstancePtr newThread();
+   
+    //return snapshot-copy of the list purposefully
+    std::vector<DemodulatorInstancePtr> getDemodulators();
+
+    std::vector<DemodulatorInstancePtr> getOrderedDemodulators(bool actives = true);
+    std::vector<DemodulatorInstancePtr> getDemodulatorsAt(long long freq, int bandwidth);
+    
+    DemodulatorInstancePtr getPreviousDemodulator(DemodulatorInstancePtr demod, bool actives = true);
+    DemodulatorInstancePtr getNextDemodulator(DemodulatorInstancePtr demod, bool actives = true);
+    DemodulatorInstancePtr getLastDemodulator();
+    DemodulatorInstancePtr getFirstDemodulator();
     bool anyDemodulatorsAt(long long freq, int bandwidth);
-    void deleteThread(DemodulatorInstance *);
+    void deleteThread(DemodulatorInstancePtr);
 
     void terminateAll();
 
-    void setActiveDemodulator(DemodulatorInstance *demod, bool temporary = true);
-    DemodulatorInstance *getActiveDemodulator();
-    DemodulatorInstance *getLastActiveDemodulator();
-	DemodulatorInstance *getLastDemodulatorWith(const std::string& type,
+    void setActiveDemodulator(DemodulatorInstancePtr demod, bool temporary = true);
+
+    //Dangerous: this is only intended by some internal classes,
+    // and only set a pre-existing demod
+    void setActiveDemodulatorByRawPointer(DemodulatorInstance* demod, bool temporary = true);
+
+    DemodulatorInstancePtr getActiveDemodulator();
+    DemodulatorInstancePtr getLastActiveDemodulator();
+    DemodulatorInstancePtr getLastDemodulatorWith(const std::string& type,
 												const std::wstring& userLabel,
 												long long frequency,
 												int bandwidth);
@@ -64,20 +73,17 @@ public:
     void updateLastState();
     
     void setOutputDevices(std::map<int,RtAudio::DeviceInfo> devs);
-    void saveInstance(DataNode *node, DemodulatorInstance *inst);
+    void saveInstance(DataNode *node, DemodulatorInstancePtr inst);
 	
-    DemodulatorInstance *loadInstance(DataNode *node);
-    
+    DemodulatorInstancePtr loadInstance(DataNode *node);
+
 private:
-    
-    void garbageCollect();
 
-    std::vector<DemodulatorInstance *> demods;
-    std::vector<DemodulatorInstance *> demods_deleted;
+    std::vector<DemodulatorInstancePtr> demods;
     
-    std::atomic<DemodulatorInstance *> activeDemodulator;
-    std::atomic<DemodulatorInstance *> lastActiveDemodulator;
-    std::atomic<DemodulatorInstance *> activeVisualDemodulator;
+    DemodulatorInstancePtr activeDemodulator;
+    DemodulatorInstancePtr lastActiveDemodulator;
+    DemodulatorInstancePtr activeVisualDemodulator;
 
     int lastBandwidth;
     std::string lastDemodType;
@@ -91,7 +97,7 @@ private:
     //protects access to demods lists and such, need to be recursive
     //because of the usage of public re-entrant methods 
     std::recursive_mutex demods_busy;
-    
+   
     std::map<std::string, ModemSettings> lastModemSettings;
     std::map<int,RtAudio::DeviceInfo> outputDevices;
 };
diff --git a/src/demod/DemodulatorPreThread.cpp b/src/demod/DemodulatorPreThread.cpp
index 574c7fa..049014b 100644
--- a/src/demod/DemodulatorPreThread.cpp
+++ b/src/demod/DemodulatorPreThread.cpp
@@ -12,7 +12,10 @@
 #include "CubicSDR.h"
 #include "DemodulatorInstance.h"
 
-DemodulatorPreThread::DemodulatorPreThread(DemodulatorInstance *parent) : IOThread(), iqResampler(NULL), iqResampleRatio(1), cModem(nullptr), cModemKit(nullptr), iqInputQueue(NULL), iqOutputQueue(NULL)
+//50 ms
+#define HEARTBEAT_CHECK_PERIOD_MICROS (50 * 1000) 
+
+DemodulatorPreThread::DemodulatorPreThread(DemodulatorInstance* parent) : IOThread(), iqResampler(NULL), iqResampleRatio(1), cModem(nullptr), cModemKit(nullptr)
  {
 	initialized.store(false);
     this->parent = parent;
@@ -20,10 +23,10 @@ DemodulatorPreThread::DemodulatorPreThread(DemodulatorInstance *parent) : IOThre
     freqShifter = nco_crcf_create(LIQUID_VCO);
     shiftFrequency = 0;
 
-    workerQueue = new DemodulatorThreadWorkerCommandQueue;
+    workerQueue = std::make_shared<DemodulatorThreadWorkerCommandQueue>();
     workerQueue->set_max_num_items(2);
 
-    workerResults = new DemodulatorThreadWorkerResultQueue;
+    workerResults = std::make_shared<DemodulatorThreadWorkerResultQueue>();
     workerResults->set_max_num_items(100);
      
     workerThread = new DemodulatorWorkerThread();
@@ -62,8 +65,8 @@ void DemodulatorPreThread::run() {
 
     ReBuffer<DemodulatorThreadPostIQData> buffers("DemodulatorPreThreadBuffers");
 
-    iqInputQueue = static_cast<DemodulatorThreadInputQueue*>(getInputQueue("IQDataInput"));
-    iqOutputQueue = static_cast<DemodulatorThreadPostInputQueue*>(getOutputQueue("IQDataOutput"));
+    iqInputQueue = std::static_pointer_cast<DemodulatorThreadInputQueue>(getInputQueue("IQDataInput"));
+    iqOutputQueue = std::static_pointer_cast<DemodulatorThreadPostInputQueue>(getOutputQueue("IQDataOutput"));
     
     std::vector<liquid_float_complex> in_buf_data;
     std::vector<liquid_float_complex> out_buf_data;
@@ -71,9 +74,11 @@ void DemodulatorPreThread::run() {
     t_Worker = new std::thread(&DemodulatorWorkerThread::threadMain, workerThread);
     
     while (!stopping) {
-        DemodulatorThreadIQData *inp;
+        DemodulatorThreadIQDataPtr inp;
 
-        iqInputQueue->pop(inp);
+        if (!iqInputQueue->pop(inp, HEARTBEAT_CHECK_PERIOD_MICROS)) {
+            continue;
+        }
         
         if (frequencyChanged.load()) {
             currentFrequency.store(newFrequency);
@@ -157,7 +162,7 @@ void DemodulatorPreThread::run() {
         }
 
         if (cModem && cModemKit && abs(shiftFrequency) > (int) ((double) (inp->sampleRate / 2) * 1.5)) {
-            inp->decRefCount();
+          
             continue;
         }
 
@@ -192,7 +197,7 @@ void DemodulatorPreThread::run() {
                 out_buf = temp_buf;
             }
 
-            DemodulatorThreadPostIQData *resamp = buffers.getBuffer();
+            DemodulatorThreadPostIQDataPtr resamp = buffers.getBuffer();
 
             size_t out_size = ceil((double) (bufSize) * iqResampleRatio) + 512;
 
@@ -218,8 +223,6 @@ void DemodulatorPreThread::run() {
             iqOutputQueue->push(resamp);   
         }
 
-        inp->decRefCount();
-
         DemodulatorWorkerThreadResult result;
         //process all worker results until 
         while (!stopping && workerResults->try_pop(result)) {
@@ -277,12 +280,9 @@ void DemodulatorPreThread::run() {
         }
     } //end while stopping
 
-    DemodulatorThreadPostIQData *tmp;
-    while (iqOutputQueue->try_pop(tmp)) {
-        
-        tmp->decRefCount();
-    }
-    buffers.purge();
+   
+    iqOutputQueue->flush();
+    iqInputQueue->flush();
 }
 
 void DemodulatorPreThread::setDemodType(std::string demodType) {
@@ -347,18 +347,18 @@ int DemodulatorPreThread::getAudioSampleRate() {
 }
 
 void DemodulatorPreThread::terminate() {
+
+    //make non-blocking calls to be sure threads are flagged for termination.
     IOThread::terminate();
-    DemodulatorThreadIQData *inp = new DemodulatorThreadIQData;    // push dummy to nudge queue
-    
-    //VSO: blocking push :
-    iqInputQueue->push(inp);
- 
-    DemodulatorWorkerThreadCommand command(DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_NULL);
-    
-    workerQueue->push(command);
-    
     workerThread->terminate();
-    workerThread->isTerminated(1000);
+
+    //unblock the push()
+    iqOutputQueue->flush();
+    iqInputQueue->flush();
+
+    //wait blocking for termination here, it could be long with lots of modems and we MUST terminate properly,
+    //else better kill the whole application...
+    workerThread->isTerminated(5000);
 
     t_Worker->join();
     delete t_Worker;
@@ -366,12 +366,6 @@ void DemodulatorPreThread::terminate() {
 
     delete workerThread;
     workerThread = nullptr;
-
-    delete workerResults;
-    workerResults = nullptr;
-
-    delete workerQueue;
-    workerQueue = nullptr;
 }
 
 Modem *DemodulatorPreThread::getModem() {
diff --git a/src/demod/DemodulatorPreThread.h b/src/demod/DemodulatorPreThread.h
index 55bdfcd..3913d11 100644
--- a/src/demod/DemodulatorPreThread.h
+++ b/src/demod/DemodulatorPreThread.h
@@ -6,6 +6,7 @@
 #include <queue>
 #include <vector>
 #include <atomic>
+#include <memory>
 
 #include "CubicSDRDefs.h"
 #include "DemodDefs.h"
@@ -16,8 +17,8 @@ class DemodulatorInstance;
 class DemodulatorPreThread : public IOThread {
 public:
 
-    DemodulatorPreThread(DemodulatorInstance *parent);
-    ~DemodulatorPreThread();
+    DemodulatorPreThread(DemodulatorInstance* parent);
+    virtual ~DemodulatorPreThread();
 
     virtual void run();
     
@@ -49,7 +50,9 @@ public:
     void writeModemSettings(ModemSettings settings);
 
 protected:
-    DemodulatorInstance *parent;
+  
+    DemodulatorInstance* parent;
+
     msresamp_crcf iqResampler;
     double iqResampleRatio;
     std::vector<liquid_float_complex> resampledData;
@@ -78,9 +81,9 @@ protected:
     DemodulatorWorkerThread *workerThread;
     std::thread *t_Worker;
 
-    DemodulatorThreadWorkerCommandQueue *workerQueue;
-    DemodulatorThreadWorkerResultQueue *workerResults;
+    DemodulatorThreadWorkerCommandQueuePtr workerQueue;
+    DemodulatorThreadWorkerResultQueuePtr  workerResults;
 
-    DemodulatorThreadInputQueue* iqInputQueue;
-    DemodulatorThreadPostInputQueue* iqOutputQueue;
+    DemodulatorThreadInputQueuePtr iqInputQueue;
+    DemodulatorThreadPostInputQueuePtr iqOutputQueue;
 };
diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorThread.cpp
index a186404..d828d26 100644
--- a/src/demod/DemodulatorThread.cpp
+++ b/src/demod/DemodulatorThread.cpp
@@ -12,14 +12,17 @@
 #define M_PI        3.14159265358979323846
 #endif
 
+//50 ms
+#define HEARTBEAT_CHECK_PERIOD_MICROS (50 * 1000) 
+
 #ifdef __APPLE__
 #include <pthread.h>
 #endif
 
-std::atomic<DemodulatorInstance *> DemodulatorThread::squelchLock(nullptr);
+DemodulatorInstance* DemodulatorThread::squelchLock(nullptr);
 std::mutex DemodulatorThread::squelchLockMutex;
 
-DemodulatorThread::DemodulatorThread(DemodulatorInstance *parent)
+DemodulatorThread::DemodulatorThread(DemodulatorInstance* parent)
     : IOThread(), outputBuffers("DemodulatorThreadBuffers"), squelchLevel(-100), 
       signalLevel(-100), signalFloor(-30), signalCeil(30), squelchEnabled(false) {
     
@@ -32,13 +35,19 @@ DemodulatorThread::~DemodulatorThread() {
     releaseSquelchLock(demodInstance);
 }
 
-void DemodulatorThread::onBindOutput(std::string name, ThreadQueueBase *threadQueue) {
+void DemodulatorThread::onBindOutput(std::string name, ThreadQueueBasePtr threadQueue) {
     if (name == "AudioVisualOutput") {
         
         //protects because it may be changed at runtime
         std::lock_guard < std::mutex > lock(m_mutexAudioVisOutputQueue);
 
-        audioVisOutputQueue = static_cast<DemodulatorThreadOutputQueue*>(threadQueue);
+        audioVisOutputQueue = std::static_pointer_cast<DemodulatorThreadOutputQueue>(threadQueue);
+    }
+
+    if (name == "AudioSink") {
+        std::lock_guard < std::mutex > lock(m_mutexAudioVisOutputQueue);
+
+        audioSinkOutputQueue = std::static_pointer_cast<AudioThreadInputQueue>(threadQueue);
     }
 }
 
@@ -72,22 +81,23 @@ void DemodulatorThread::run() {
     
 //    std::cout << "Demodulator thread started.." << std::endl;
     
-    iqInputQueue = static_cast<DemodulatorThreadPostInputQueue*>(getInputQueue("IQDataInput"));
-    audioOutputQueue = static_cast<AudioThreadInputQueue*>(getOutputQueue("AudioDataOutput"));
-    threadQueueControl = static_cast<DemodulatorThreadControlCommandQueue *>(getInputQueue("ControlQueue"));
+    iqInputQueue = std::static_pointer_cast<DemodulatorThreadPostInputQueue>(getInputQueue("IQDataInput"));
+    audioOutputQueue = std::static_pointer_cast<AudioThreadInputQueue>(getOutputQueue("AudioDataOutput"));
+    threadQueueControl = std::static_pointer_cast<DemodulatorThreadControlCommandQueue>(getInputQueue("ControlQueue"));
      
     ModemIQData modemData;
     
     while (!stopping) {
-        DemodulatorThreadPostIQData *inp;
-        
-        iqInputQueue->pop(inp);
-        //        std::lock_guard < std::mutex > lock(inp->m_mutex);
+        DemodulatorThreadPostIQDataPtr inp;
         
+        if (!iqInputQueue->pop(inp, HEARTBEAT_CHECK_PERIOD_MICROS)) {
+            continue;
+        }
+         
         size_t bufSize = inp->data.size();
         
         if (!bufSize) {
-            inp->decRefCount();
+           
             continue;
         }
         
@@ -104,7 +114,7 @@ void DemodulatorThread::run() {
         }
         
         if (!cModem || !cModemKit) {
-            inp->decRefCount();
+           
             continue;
         }
         
@@ -115,7 +125,7 @@ void DemodulatorThread::run() {
         modemData.sampleRate = inp->sampleRate;
         modemData.data.assign(inputData->begin(), inputData->end());
         
-        AudioThreadInput *ati = nullptr;
+        AudioThreadInputPtr ati = nullptr;
         
         ModemAnalog *modemAnalog = (cModem->getType() == "analog")?((ModemAnalog *)cModem):nullptr;
         ModemDigital *modemDigital = (cModem->getType() == "digital")?((ModemDigital *)cModem):nullptr;
@@ -133,7 +143,7 @@ void DemodulatorThread::run() {
             ati->data.resize(0);
         }
 
-        cModem->demodulate(cModemKit, &modemData, ati);
+        cModem->demodulate(cModemKit, &modemData, ati.get());
 
         double currentSignalLevel = 0;
         double sampleTime = double(inp->data.size()) / double(inp->sampleRate);
@@ -191,16 +201,16 @@ void DemodulatorThread::run() {
             signalLevel = signalLevel + (currentSignalLevel - signalLevel) * 0.05 * sampleTime * 30.0;
         }
         
-        bool squelched = (muted.load() || (squelchEnabled && (signalLevel < squelchLevel)));
+        bool squelched = squelchEnabled && (signalLevel < squelchLevel);
         
         if (squelchEnabled) {
             if (!squelched && !squelchBreak) {
                     if (wxGetApp().getSoloMode() && !wxGetApp().getAppFrame()->isUserDemodBusy()) {
                         std::lock_guard < std::mutex > lock(squelchLockMutex);
-                        if (squelchLock.load() == nullptr) {
-                            squelchLock.store(demodInstance);
+                        if (squelchLock == nullptr) {
+                            squelchLock = demodInstance;
                             wxGetApp().getDemodMgr().setActiveDemodulator(nullptr);
-                            wxGetApp().getDemodMgr().setActiveDemodulator(demodInstance, false);
+                            wxGetApp().getDemodMgr().setActiveDemodulatorByRawPointer(demodInstance, false);
                             squelchBreak = true;
                             demodInstance->getVisualCue()->triggerSquelchBreak(120);
                         }
@@ -214,31 +224,36 @@ void DemodulatorThread::run() {
                 squelchBreak = false;
             }
         }
-        
-        if (audioOutputQueue != nullptr && ati && ati->data.size() && !squelched) {
-            std::vector<float>::iterator data_i;
-            ati->peak = 0;
-            for (auto data_i : ati->data) {
-                float p = fabs(data_i);
-                if (p > ati->peak) {
-                    ati->peak = p;
-                }
-            }
-        } else if (ati) {
-            ati->setRefCount(0);
-            ati = nullptr;
-        }
-        
+
+		//compute audio peak:
+		if (audioOutputQueue != nullptr && ati) {
+
+			ati->peak = 0;
+
+			for (auto data_i : ati->data) {
+				float p = fabs(data_i);
+				if (p > ati->peak) {
+					ati->peak = p;
+				}
+			}
+		}
+
+		//attach squelch flag to samples, to be used by audio sink.
+		if (ati) {
+			ati->is_squelch_active = squelched;
+		}
+
         //At that point, capture the current state of audioVisOutputQueue in a local 
         //variable, and works with it with now on until the next while-turn.
-        DemodulatorThreadOutputQueue* localAudioVisOutputQueue = nullptr;
+        DemodulatorThreadOutputQueuePtr localAudioVisOutputQueue = nullptr;
         {
             std::lock_guard < std::mutex > lock(m_mutexAudioVisOutputQueue);
             localAudioVisOutputQueue = audioVisOutputQueue;
         }
 
-        if ((ati || modemDigital) && localAudioVisOutputQueue != nullptr && localAudioVisOutputQueue->empty()) {
-            AudioThreadInput *ati_vis = new AudioThreadInput;
+        if (!squelched && (ati || modemDigital) && localAudioVisOutputQueue != nullptr && localAudioVisOutputQueue->empty()) {
+
+            AudioThreadInputPtr ati_vis = std::make_shared<AudioThreadInput>();
 
             ati_vis->sampleRate = inp->sampleRate;
             ati_vis->inputRate = inp->sampleRate;
@@ -246,7 +261,7 @@ void DemodulatorThread::run() {
             size_t num_vis = DEMOD_VIS_SIZE;
             if (modemDigital) {
                 if (ati) {  // TODO: handle digital modems with audio output
-                    ati->setRefCount(0);
+                   
                     ati = nullptr;
                 }
                 ati_vis->data.resize(inputData->size());
@@ -300,25 +315,40 @@ void DemodulatorThread::run() {
             
             if (!localAudioVisOutputQueue->try_push(ati_vis)) {
                 //non-blocking push needed for audio vis out
-                ati_vis->setRefCount(0);
+            
                 std::cout << "DemodulatorThread::run() cannot push ati_vis into localAudioVisOutputQueue, is full !" << std::endl;
                 std::this_thread::yield();
             }
         }
 
-        if (ati != nullptr) {
-            if (!muted.load() && (!wxGetApp().getSoloMode() || (demodInstance == wxGetApp().getDemodMgr().getLastActiveDemodulator()))) {
+        if (!squelched && ati != nullptr) {
+            if (!muted.load() && (!wxGetApp().getSoloMode() || (demodInstance == wxGetApp().getDemodMgr().getLastActiveDemodulator().get()))) {
                 //non-blocking push needed for audio out
                 if (!audioOutputQueue->try_push(ati)) {
-                    ati->decRefCount();
+                  
                     std::cout << "DemodulatorThread::run() cannot push ati into audioOutputQueue, is full !" << std::endl;
                     std::this_thread::yield();
                 }
-            } else {
-                ati->setRefCount(0);
             }
         }
         
+        
+        // Capture audioSinkOutputQueue state in a local variable
+        DemodulatorThreadOutputQueuePtr localAudioSinkOutputQueue = nullptr;
+        {
+            std::lock_guard < std::mutex > lock(m_mutexAudioVisOutputQueue);
+            localAudioSinkOutputQueue = audioSinkOutputQueue;
+        }
+
+        //Push to audio sink, if any:
+        if (ati && localAudioSinkOutputQueue != nullptr) {
+            
+            if (!localAudioSinkOutputQueue->try_push(ati)) {
+                std::cout << "DemodulatorThread::run() cannot push ati into audioSinkOutputQueue, is full !" << std::endl;
+                std::this_thread::yield();
+            }
+        }
+
         DemodulatorThreadControlCommand command;
         
         //empty command queue, execute commands
@@ -335,40 +365,23 @@ void DemodulatorThread::run() {
                     break;
             }
         }
-        
-        
-        inp->decRefCount();
     }
     // end while !stopping
     
     // Purge any unused inputs, with a non-blocking pop
-    DemodulatorThreadPostIQData *ref;
-    while (iqInputQueue->try_pop(ref)) {
-        
-        if (ref) {  // May have other consumers; just decrement
-            ref->decRefCount();
-        }
-    }
-
-    AudioThreadInput *ref_audio;
-    while (audioOutputQueue->try_pop(ref_audio)) {
-      
-        if (ref_audio) { // Originated here; set RefCount to 0
-            ref_audio->setRefCount(0);
-        }
-    }
-
-    outputBuffers.purge();
+    iqInputQueue->flush();
+    audioOutputQueue->flush();
     
 //    std::cout << "Demodulator thread done." << std::endl;
 }
 
 void DemodulatorThread::terminate() {
     IOThread::terminate();
-    DemodulatorThreadPostIQData *inp = new DemodulatorThreadPostIQData;    // push dummy to nudge queue
-    
-    //VSO: blocking push
-    iqInputQueue->push(inp);
+
+    //unblock the curretly blocked push()
+    iqInputQueue->flush();
+    audioOutputQueue->flush();
+    threadQueueControl->flush();
 }
 
 bool DemodulatorThread::isMuted() {
@@ -406,9 +419,11 @@ bool DemodulatorThread::getSquelchBreak() {
     return squelchBreak;
 }
 
-void DemodulatorThread::releaseSquelchLock(DemodulatorInstance *inst) {
+void DemodulatorThread::releaseSquelchLock(DemodulatorInstance* inst) {
+    
     std::lock_guard < std::mutex > lock(squelchLockMutex);
-    if (inst == nullptr || squelchLock.load() == inst) {
-        squelchLock.store(nullptr);
+
+    if (inst == nullptr || squelchLock == inst) {
+        squelchLock = nullptr;
     }
-}
\ No newline at end of file
+}
diff --git a/src/demod/DemodulatorThread.h b/src/demod/DemodulatorThread.h
index 1df889c..45607bb 100644
--- a/src/demod/DemodulatorThread.h
+++ b/src/demod/DemodulatorThread.h
@@ -5,13 +5,12 @@
 
 #include <queue>
 #include <vector>
+#include <memory>
 
 #include "DemodDefs.h"
 #include "AudioThread.h"
 #include "Modem.h"
 
-typedef ThreadBlockingQueue<AudioThreadInput *> DemodulatorThreadOutputQueue;
-
 #define DEMOD_VIS_SIZE 2048
 #define DEMOD_SIGNAL_MIN -30
 #define DEMOD_SIGNAL_MAX 30
@@ -21,13 +20,13 @@ class DemodulatorInstance;
 class DemodulatorThread : public IOThread {
 public:
 
-    DemodulatorThread(DemodulatorInstance *parent);
-    ~DemodulatorThread();
+    DemodulatorThread(DemodulatorInstance* parent);
+    virtual ~DemodulatorThread();
 
-    void onBindOutput(std::string name, ThreadQueueBase *threadQueue);
+    void onBindOutput(std::string name, ThreadQueueBasePtr threadQueue);
     
-    void run();
-    void terminate();
+    virtual void run();
+    virtual void terminate();
     
     void setMuted(bool state);
     bool isMuted();
@@ -40,13 +39,14 @@ public:
    
     bool getSquelchBreak();
 
-    static void releaseSquelchLock(DemodulatorInstance *inst);
+
+    static void releaseSquelchLock(DemodulatorInstance* inst);
 protected:
     
     double abMagnitude(float inphase, float quadrature);
     double linearToDb(double linear);
 
-    DemodulatorInstance *demodInstance = nullptr;
+    DemodulatorInstance* demodInstance;
     ReBuffer<AudioThreadInput> outputBuffers;
 
     std::atomic_bool muted;
@@ -55,18 +55,20 @@ protected:
     std::atomic<float> signalLevel, signalFloor, signalCeil;
     bool squelchEnabled, squelchBreak;
     
-    static std::atomic<DemodulatorInstance *> squelchLock;
+    static DemodulatorInstance* squelchLock;
     static std::mutex squelchLockMutex;
     
     
     Modem *cModem = nullptr;
     ModemKit *cModemKit = nullptr;
     
-    DemodulatorThreadPostInputQueue* iqInputQueue = nullptr;
-    AudioThreadInputQueue *audioOutputQueue = nullptr;
-    DemodulatorThreadOutputQueue* audioVisOutputQueue = nullptr;
-    DemodulatorThreadControlCommandQueue *threadQueueControl = nullptr;
+    DemodulatorThreadPostInputQueuePtr iqInputQueue;
+    AudioThreadInputQueuePtr audioOutputQueue;
+    DemodulatorThreadOutputQueuePtr audioVisOutputQueue;
+    DemodulatorThreadControlCommandQueuePtr threadQueueControl;
+
+    DemodulatorThreadOutputQueuePtr audioSinkOutputQueue = nullptr;
 
     //protects the audioVisOutputQueue dynamic binding change at runtime (in DemodulatorMgr)
-    mutable std::mutex m_mutexAudioVisOutputQueue;
+    std::mutex m_mutexAudioVisOutputQueue;
 };
diff --git a/src/demod/DemodulatorWorkerThread.cpp b/src/demod/DemodulatorWorkerThread.cpp
index b1304a7..c736368 100644
--- a/src/demod/DemodulatorWorkerThread.cpp
+++ b/src/demod/DemodulatorWorkerThread.cpp
@@ -6,8 +6,11 @@
 #include "CubicSDR.h"
 #include <vector>
 
+//50 ms
+#define HEARTBEAT_CHECK_PERIOD_MICROS (50 * 1000) 
+
 DemodulatorWorkerThread::DemodulatorWorkerThread() : IOThread(),
-        commandQueue(NULL), resultQueue(NULL), cModem(nullptr), cModemKit(nullptr) {
+         cModem(nullptr), cModemKit(nullptr) {
 }
 
 DemodulatorWorkerThread::~DemodulatorWorkerThread() {
@@ -17,8 +20,8 @@ void DemodulatorWorkerThread::run() {
 
 //    std::cout << "Demodulator worker thread started.." << std::endl;
     
-    commandQueue = static_cast<DemodulatorThreadWorkerCommandQueue *>(getInputQueue("WorkerCommandQueue"));
-    resultQueue = static_cast<DemodulatorThreadWorkerResultQueue *>(getOutputQueue("WorkerResultQueue"));
+    commandQueue = std::static_pointer_cast<DemodulatorThreadWorkerCommandQueue>(getInputQueue("WorkerCommandQueue"));
+    resultQueue = std::static_pointer_cast<DemodulatorThreadWorkerResultQueue>(getOutputQueue("WorkerResultQueue"));
     
     while (!stopping) {
         bool filterChanged = false;
@@ -30,8 +33,11 @@ void DemodulatorWorkerThread::run() {
         //Beware of the subtility here,
         //we are waiting for the first command to show up (blocking!)
         //then consuming the commands until done. 
-        while (!done) {
-            commandQueue->pop(command);
+        while (!done && !stopping) {
+
+            if (!commandQueue->pop(command, HEARTBEAT_CHECK_PERIOD_MICROS)) {
+                continue;
+            }
 
             switch (command.cmd) {
                 case DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS:
@@ -46,7 +52,7 @@ void DemodulatorWorkerThread::run() {
                     break;
             }
             done = commandQueue->empty();
-        }
+        } //end while done.
 
         if ((makeDemod || filterChanged) && !stopping) {
             DemodulatorWorkerThreadResult result(DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS);
@@ -110,6 +116,7 @@ void DemodulatorWorkerThread::run() {
 
 void DemodulatorWorkerThread::terminate() {
     IOThread::terminate();
-    DemodulatorWorkerThreadCommand inp;    // push dummy to nudge queue
-    commandQueue->push(inp);
+    //unblock the push()
+    resultQueue->flush();
+    commandQueue->flush();
 }
diff --git a/src/demod/DemodulatorWorkerThread.h b/src/demod/DemodulatorWorkerThread.h
index cb56176..a4c3488 100644
--- a/src/demod/DemodulatorWorkerThread.h
+++ b/src/demod/DemodulatorWorkerThread.h
@@ -5,7 +5,7 @@
 
 #include <queue>
 #include <vector>
-
+#include <memory>
 #include "liquid/liquid.h"
 #include "AudioThread.h"
 #include "ThreadBlockingQueue.h"
@@ -32,8 +32,6 @@ public:
 
     msresamp_crcf iqResampler;
     double iqResampleRatio;
-    
-    DemodulatorThread *demodThread;
 
     long long sampleRate;
     unsigned int bandwidth;
@@ -72,19 +70,22 @@ public:
 typedef ThreadBlockingQueue<DemodulatorWorkerThreadCommand> DemodulatorThreadWorkerCommandQueue;
 typedef ThreadBlockingQueue<DemodulatorWorkerThreadResult> DemodulatorThreadWorkerResultQueue;
 
+typedef std::shared_ptr<DemodulatorThreadWorkerCommandQueue> DemodulatorThreadWorkerCommandQueuePtr;
+typedef std::shared_ptr<DemodulatorThreadWorkerResultQueue> DemodulatorThreadWorkerResultQueuePtr;
+
 class DemodulatorWorkerThread : public IOThread {
 public:
 
     DemodulatorWorkerThread();
-    ~DemodulatorWorkerThread();
+    virtual ~DemodulatorWorkerThread();
 
     virtual void run();
 
-    void setCommandQueue(DemodulatorThreadWorkerCommandQueue *tQueue) {
+    void setCommandQueue(DemodulatorThreadWorkerCommandQueuePtr tQueue) {
         commandQueue = tQueue;
     }
 
-    void setResultQueue(DemodulatorThreadWorkerResultQueue *tQueue) {
+    void setResultQueue(DemodulatorThreadWorkerResultQueuePtr tQueue) {
         resultQueue = tQueue;
     }
 
@@ -92,8 +93,8 @@ public:
 
 protected:
 
-    DemodulatorThreadWorkerCommandQueue *commandQueue;
-    DemodulatorThreadWorkerResultQueue *resultQueue;
+    DemodulatorThreadWorkerCommandQueuePtr commandQueue;
+    DemodulatorThreadWorkerResultQueuePtr resultQueue;
     Modem *cModem;
     ModemKit *cModemKit;
     std::string cModemType;
diff --git a/src/forms/Bookmark/BookmarkPanel.cpp b/src/forms/Bookmark/BookmarkPanel.cpp
index cb3efd4..73b1fb2 100644
--- a/src/forms/Bookmark/BookmarkPanel.cpp
+++ b/src/forms/Bookmark/BookmarkPanel.cpp
@@ -1,136 +1,136 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Jun 17 2015)
+// C++ code generated with wxFormBuilder (version Oct 27 2017)
 // http://www.wxformbuilder.org/
 //
-// PLEASE DO "NOT" EDIT THIS FILE!
+// PLEASE DO *NOT* EDIT THIS FILE!
 ///////////////////////////////////////////////////////////////////////////
 
 #include "BookmarkPanel.h"
 
 ///////////////////////////////////////////////////////////////////////////
 
-BookmarkPanel::BookmarkPanel( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style )
+BookmarkPanel::BookmarkPanel(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) : wxPanel(parent, id, pos, size, style)
 {
 	wxBoxSizer* bSizer1;
-	bSizer1 = new wxBoxSizer( wxVERTICAL );
-	
-	m_searchText = new wxTextCtrl( this, wxID_ANY, wxT("Search.."), wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
-	bSizer1->Add( m_searchText, 0, wxALL|wxEXPAND, 5 );
-	
-	m_clearSearchButton = new wxButton( this, wxID_ANY, wxT("Clear Search"), wxDefaultPosition, wxDefaultSize, 0 );
-	bSizer1->Add( m_clearSearchButton, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 );
-	
-	m_treeView = new wxTreeCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_DEFAULT_STYLE|wxTR_HAS_VARIABLE_ROW_HEIGHT|wxTR_HIDE_ROOT|wxTR_SINGLE );
-	bSizer1->Add( m_treeView, 1, wxEXPAND, 5 );
-	
-	m_propPanel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+	bSizer1 = new wxBoxSizer(wxVERTICAL);
+
+	m_searchText = new wxTextCtrl(this, wxID_ANY, wxT("Search.."), wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
+	bSizer1->Add(m_searchText, 0, wxALL | wxEXPAND, 5);
+
+	m_clearSearchButton = new wxButton(this, wxID_ANY, wxT("Clear Search"), wxDefaultPosition, wxDefaultSize, 0);
+	bSizer1->Add(m_clearSearchButton, 0, wxBOTTOM | wxEXPAND | wxLEFT | wxRIGHT, 5);
+
+	m_treeView = new wxTreeCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_DEFAULT_STYLE | wxTR_HAS_VARIABLE_ROW_HEIGHT | wxTR_HIDE_ROOT | wxTR_SINGLE);
+	bSizer1->Add(m_treeView, 1, wxEXPAND, 5);
+
+	m_propPanel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
 	wxFlexGridSizer* fgPropSizer;
-	fgPropSizer = new wxFlexGridSizer( 0, 2, 0, 0 );
-	fgPropSizer->AddGrowableCol( 1 );
-	fgPropSizer->SetFlexibleDirection( wxBOTH );
-	fgPropSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
-	
-	m_labelLabel = new wxStaticText( m_propPanel, wxID_ANY, wxT("Label"), wxDefaultPosition, wxDefaultSize, 0 );
-	m_labelLabel->Wrap( -1 );
-	fgPropSizer->Add( m_labelLabel, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT, 5 );
-	
-	m_labelText = new wxTextCtrl( m_propPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
-	fgPropSizer->Add( m_labelText, 0, wxALL|wxEXPAND, 5 );
-	
-	m_frequencyLabel = new wxStaticText( m_propPanel, wxID_ANY, wxT("Freq"), wxDefaultPosition, wxDefaultSize, 0 );
-	m_frequencyLabel->Wrap( -1 );
-	fgPropSizer->Add( m_frequencyLabel, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT, 5 );
-	
-	m_frequencyVal = new wxStaticText( m_propPanel, wxID_ANY, wxT("FrequencyVal"), wxDefaultPosition, wxDefaultSize, 0 );
-	m_frequencyVal->Wrap( -1 );
-	fgPropSizer->Add( m_frequencyVal, 0, wxALL, 5 );
-	
-	m_bandwidthLabel = new wxStaticText( m_propPanel, wxID_ANY, wxT("BW"), wxDefaultPosition, wxDefaultSize, 0 );
-	m_bandwidthLabel->Wrap( -1 );
-	fgPropSizer->Add( m_bandwidthLabel, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT, 5 );
-	
-	m_bandwidthVal = new wxStaticText( m_propPanel, wxID_ANY, wxT("BandwidthVal"), wxDefaultPosition, wxDefaultSize, 0 );
-	m_bandwidthVal->Wrap( -1 );
-	fgPropSizer->Add( m_bandwidthVal, 0, wxALL, 5 );
-	
-	m_modulationLabel = new wxStaticText( m_propPanel, wxID_ANY, wxT("Type"), wxDefaultPosition, wxDefaultSize, 0 );
-	m_modulationLabel->Wrap( -1 );
-	fgPropSizer->Add( m_modulationLabel, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT, 5 );
-	
-	m_modulationVal = new wxStaticText( m_propPanel, wxID_ANY, wxT("TypeVal"), wxDefaultPosition, wxDefaultSize, 0 );
-	m_modulationVal->Wrap( -1 );
-	fgPropSizer->Add( m_modulationVal, 0, wxALL, 5 );
-	
-	
-	m_propPanel->SetSizer( fgPropSizer );
+	fgPropSizer = new wxFlexGridSizer(0, 2, 0, 0);
+	fgPropSizer->AddGrowableCol(1);
+	fgPropSizer->SetFlexibleDirection(wxBOTH);
+	fgPropSizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
+
+	m_labelLabel = new wxStaticText(m_propPanel, wxID_ANY, wxT("Label"), wxDefaultPosition, wxDefaultSize, 0);
+	m_labelLabel->Wrap(-1);
+	fgPropSizer->Add(m_labelLabel, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT, 5);
+
+	m_labelText = new wxTextCtrl(m_propPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
+	fgPropSizer->Add(m_labelText, 0, wxALL | wxEXPAND, 5);
+
+	m_frequencyLabel = new wxStaticText(m_propPanel, wxID_ANY, wxT("Freq"), wxDefaultPosition, wxDefaultSize, 0);
+	m_frequencyLabel->Wrap(-1);
+	fgPropSizer->Add(m_frequencyLabel, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT, 5);
+
+	m_frequencyVal = new wxStaticText(m_propPanel, wxID_ANY, wxT("FrequencyVal"), wxDefaultPosition, wxDefaultSize, 0);
+	m_frequencyVal->Wrap(-1);
+	fgPropSizer->Add(m_frequencyVal, 0, wxALL, 5);
+
+	m_bandwidthLabel = new wxStaticText(m_propPanel, wxID_ANY, wxT("BW"), wxDefaultPosition, wxDefaultSize, 0);
+	m_bandwidthLabel->Wrap(-1);
+	fgPropSizer->Add(m_bandwidthLabel, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT, 5);
+
+	m_bandwidthVal = new wxStaticText(m_propPanel, wxID_ANY, wxT("BandwidthVal"), wxDefaultPosition, wxDefaultSize, 0);
+	m_bandwidthVal->Wrap(-1);
+	fgPropSizer->Add(m_bandwidthVal, 0, wxALL, 5);
+
+	m_modulationLabel = new wxStaticText(m_propPanel, wxID_ANY, wxT("Type"), wxDefaultPosition, wxDefaultSize, 0);
+	m_modulationLabel->Wrap(-1);
+	fgPropSizer->Add(m_modulationLabel, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT, 5);
+
+	m_modulationVal = new wxStaticText(m_propPanel, wxID_ANY, wxT("TypeVal"), wxDefaultPosition, wxDefaultSize, 0);
+	m_modulationVal->Wrap(-1);
+	fgPropSizer->Add(m_modulationVal, 0, wxALL, 5);
+
+
+	m_propPanel->SetSizer(fgPropSizer);
 	m_propPanel->Layout();
-	fgPropSizer->Fit( m_propPanel );
-	bSizer1->Add( m_propPanel, 0, wxALL|wxBOTTOM|wxEXPAND|wxTOP, 5 );
-	
-	m_buttonPanel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+	fgPropSizer->Fit(m_propPanel);
+	bSizer1->Add(m_propPanel, 0, wxALL | wxBOTTOM | wxEXPAND | wxTOP, 5);
+
+	m_buttonPanel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
 	wxBoxSizer* m_buttonPanelSizer;
-	m_buttonPanelSizer = new wxBoxSizer( wxVERTICAL );
-	
-	
-	m_buttonPanel->SetSizer( m_buttonPanelSizer );
+	m_buttonPanelSizer = new wxBoxSizer(wxVERTICAL);
+
+
+	m_buttonPanel->SetSizer(m_buttonPanelSizer);
 	m_buttonPanel->Layout();
-	m_buttonPanelSizer->Fit( m_buttonPanel );
-	bSizer1->Add( m_buttonPanel, 0, wxALL|wxEXPAND, 5 );
-	
-	
-	this->SetSizer( bSizer1 );
+	m_buttonPanelSizer->Fit(m_buttonPanel);
+	bSizer1->Add(m_buttonPanel, 0, wxALL | wxEXPAND, 5);
+
+
+	this->SetSizer(bSizer1);
 	this->Layout();
-	m_updateTimer.SetOwner( this, wxID_ANY );
-	
+	m_updateTimer.SetOwner(this, wxID_ANY);
+
 	// Connect Events
-	this->Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( BookmarkPanel::onEnterWindow ) );
-	this->Connect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler( BookmarkPanel::onLeaveWindow ) );
-	this->Connect( wxEVT_MOTION, wxMouseEventHandler( BookmarkPanel::onMotion ) );
-	m_searchText->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( BookmarkPanel::onSearchTextFocus ), NULL, this );
-	m_searchText->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( BookmarkPanel::onSearchText ), NULL, this );
-	m_clearSearchButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BookmarkPanel::onClearSearch ), NULL, this );
-	m_treeView->Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( BookmarkPanel::onEnterWindow ), NULL, this );
-	m_treeView->Connect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler( BookmarkPanel::onLeaveWindow ), NULL, this );
-	m_treeView->Connect( wxEVT_MOTION, wxMouseEventHandler( BookmarkPanel::onMotion ), NULL, this );
-	m_treeView->Connect( wxEVT_COMMAND_TREE_BEGIN_DRAG, wxTreeEventHandler( BookmarkPanel::onTreeBeginDrag ), NULL, this );
-	m_treeView->Connect( wxEVT_COMMAND_TREE_END_DRAG, wxTreeEventHandler( BookmarkPanel::onTreeEndDrag ), NULL, this );
-	m_treeView->Connect( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, wxTreeEventHandler( BookmarkPanel::onTreeActivate ), NULL, this );
-	m_treeView->Connect( wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxTreeEventHandler( BookmarkPanel::onTreeCollapse ), NULL, this );
-	m_treeView->Connect( wxEVT_COMMAND_TREE_ITEM_EXPANDED, wxTreeEventHandler( BookmarkPanel::onTreeExpanded ), NULL, this );
-	m_treeView->Connect( wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, wxTreeEventHandler( BookmarkPanel::onTreeItemGetTooltip ), NULL, this );
-	m_treeView->Connect( wxEVT_COMMAND_TREE_ITEM_MENU, wxTreeEventHandler( BookmarkPanel::onTreeItemMenu ), NULL, this );
-	m_treeView->Connect( wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler( BookmarkPanel::onTreeSelect ), NULL, this );
-	m_treeView->Connect( wxEVT_COMMAND_TREE_SEL_CHANGING, wxTreeEventHandler( BookmarkPanel::onTreeSelectChanging ), NULL, this );
-	m_labelText->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( BookmarkPanel::onLabelText ), NULL, this );
-	m_frequencyVal->Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( BookmarkPanel::onDoubleClickFreq ), NULL, this );
-	m_bandwidthVal->Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( BookmarkPanel::onDoubleClickBandwidth ), NULL, this );
-	this->Connect( wxID_ANY, wxEVT_TIMER, wxTimerEventHandler( BookmarkPanel::onUpdateTimer ) );
+	this->Connect(wxEVT_ENTER_WINDOW, wxMouseEventHandler(BookmarkPanel::onEnterWindow));
+	this->Connect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(BookmarkPanel::onLeaveWindow));
+	this->Connect(wxEVT_MOTION, wxMouseEventHandler(BookmarkPanel::onMotion));
+	m_searchText->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(BookmarkPanel::onSearchTextFocus), NULL, this);
+	m_searchText->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(BookmarkPanel::onSearchText), NULL, this);
+	m_clearSearchButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(BookmarkPanel::onClearSearch), NULL, this);
+	m_treeView->Connect(wxEVT_ENTER_WINDOW, wxMouseEventHandler(BookmarkPanel::onEnterWindow), NULL, this);
+	m_treeView->Connect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(BookmarkPanel::onLeaveWindow), NULL, this);
+	m_treeView->Connect(wxEVT_MOTION, wxMouseEventHandler(BookmarkPanel::onMotion), NULL, this);
+	m_treeView->Connect(wxEVT_COMMAND_TREE_BEGIN_DRAG, wxTreeEventHandler(BookmarkPanel::onTreeBeginDrag), NULL, this);
+	m_treeView->Connect(wxEVT_COMMAND_TREE_END_DRAG, wxTreeEventHandler(BookmarkPanel::onTreeEndDrag), NULL, this);
+	m_treeView->Connect(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, wxTreeEventHandler(BookmarkPanel::onTreeActivate), NULL, this);
+	m_treeView->Connect(wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxTreeEventHandler(BookmarkPanel::onTreeCollapse), NULL, this);
+	m_treeView->Connect(wxEVT_COMMAND_TREE_ITEM_EXPANDED, wxTreeEventHandler(BookmarkPanel::onTreeExpanded), NULL, this);
+	m_treeView->Connect(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, wxTreeEventHandler(BookmarkPanel::onTreeItemGetTooltip), NULL, this);
+	m_treeView->Connect(wxEVT_COMMAND_TREE_ITEM_MENU, wxTreeEventHandler(BookmarkPanel::onTreeItemMenu), NULL, this);
+	m_treeView->Connect(wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler(BookmarkPanel::onTreeSelect), NULL, this);
+	m_treeView->Connect(wxEVT_COMMAND_TREE_SEL_CHANGING, wxTreeEventHandler(BookmarkPanel::onTreeSelectChanging), NULL, this);
+	m_labelText->Connect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(BookmarkPanel::onLabelText), NULL, this);
+	m_frequencyVal->Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(BookmarkPanel::onDoubleClickFreq), NULL, this);
+	m_bandwidthVal->Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(BookmarkPanel::onDoubleClickBandwidth), NULL, this);
+	this->Connect(wxID_ANY, wxEVT_TIMER, wxTimerEventHandler(BookmarkPanel::onUpdateTimer));
 }
 
 BookmarkPanel::~BookmarkPanel()
 {
 	// Disconnect Events
-	this->Disconnect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( BookmarkPanel::onEnterWindow ) );
-	this->Disconnect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler( BookmarkPanel::onLeaveWindow ) );
-	this->Disconnect( wxEVT_MOTION, wxMouseEventHandler( BookmarkPanel::onMotion ) );
-	m_searchText->Disconnect( wxEVT_LEFT_DOWN, wxMouseEventHandler( BookmarkPanel::onSearchTextFocus ), NULL, this );
-	m_searchText->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( BookmarkPanel::onSearchText ), NULL, this );
-	m_clearSearchButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BookmarkPanel::onClearSearch ), NULL, this );
-	m_treeView->Disconnect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( BookmarkPanel::onEnterWindow ), NULL, this );
-	m_treeView->Disconnect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler( BookmarkPanel::onLeaveWindow ), NULL, this );
-	m_treeView->Disconnect( wxEVT_MOTION, wxMouseEventHandler( BookmarkPanel::onMotion ), NULL, this );
-	m_treeView->Disconnect( wxEVT_COMMAND_TREE_BEGIN_DRAG, wxTreeEventHandler( BookmarkPanel::onTreeBeginDrag ), NULL, this );
-	m_treeView->Disconnect( wxEVT_COMMAND_TREE_END_DRAG, wxTreeEventHandler( BookmarkPanel::onTreeEndDrag ), NULL, this );
-	m_treeView->Disconnect( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, wxTreeEventHandler( BookmarkPanel::onTreeActivate ), NULL, this );
-	m_treeView->Disconnect( wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxTreeEventHandler( BookmarkPanel::onTreeCollapse ), NULL, this );
-	m_treeView->Disconnect( wxEVT_COMMAND_TREE_ITEM_EXPANDED, wxTreeEventHandler( BookmarkPanel::onTreeExpanded ), NULL, this );
-	m_treeView->Disconnect( wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, wxTreeEventHandler( BookmarkPanel::onTreeItemGetTooltip ), NULL, this );
-	m_treeView->Disconnect( wxEVT_COMMAND_TREE_ITEM_MENU, wxTreeEventHandler( BookmarkPanel::onTreeItemMenu ), NULL, this );
-	m_treeView->Disconnect( wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler( BookmarkPanel::onTreeSelect ), NULL, this );
-	m_treeView->Disconnect( wxEVT_COMMAND_TREE_SEL_CHANGING, wxTreeEventHandler( BookmarkPanel::onTreeSelectChanging ), NULL, this );
-	m_labelText->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( BookmarkPanel::onLabelText ), NULL, this );
-	m_frequencyVal->Disconnect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( BookmarkPanel::onDoubleClickFreq ), NULL, this );
-	m_bandwidthVal->Disconnect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( BookmarkPanel::onDoubleClickBandwidth ), NULL, this );
-	this->Disconnect( wxID_ANY, wxEVT_TIMER, wxTimerEventHandler( BookmarkPanel::onUpdateTimer ) );
-	
+	this->Disconnect(wxEVT_ENTER_WINDOW, wxMouseEventHandler(BookmarkPanel::onEnterWindow));
+	this->Disconnect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(BookmarkPanel::onLeaveWindow));
+	this->Disconnect(wxEVT_MOTION, wxMouseEventHandler(BookmarkPanel::onMotion));
+	m_searchText->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(BookmarkPanel::onSearchTextFocus), NULL, this);
+	m_searchText->Disconnect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(BookmarkPanel::onSearchText), NULL, this);
+	m_clearSearchButton->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(BookmarkPanel::onClearSearch), NULL, this);
+	m_treeView->Disconnect(wxEVT_ENTER_WINDOW, wxMouseEventHandler(BookmarkPanel::onEnterWindow), NULL, this);
+	m_treeView->Disconnect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(BookmarkPanel::onLeaveWindow), NULL, this);
+	m_treeView->Disconnect(wxEVT_MOTION, wxMouseEventHandler(BookmarkPanel::onMotion), NULL, this);
+	m_treeView->Disconnect(wxEVT_COMMAND_TREE_BEGIN_DRAG, wxTreeEventHandler(BookmarkPanel::onTreeBeginDrag), NULL, this);
+	m_treeView->Disconnect(wxEVT_COMMAND_TREE_END_DRAG, wxTreeEventHandler(BookmarkPanel::onTreeEndDrag), NULL, this);
+	m_treeView->Disconnect(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, wxTreeEventHandler(BookmarkPanel::onTreeActivate), NULL, this);
+	m_treeView->Disconnect(wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxTreeEventHandler(BookmarkPanel::onTreeCollapse), NULL, this);
+	m_treeView->Disconnect(wxEVT_COMMAND_TREE_ITEM_EXPANDED, wxTreeEventHandler(BookmarkPanel::onTreeExpanded), NULL, this);
+	m_treeView->Disconnect(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, wxTreeEventHandler(BookmarkPanel::onTreeItemGetTooltip), NULL, this);
+	m_treeView->Disconnect(wxEVT_COMMAND_TREE_ITEM_MENU, wxTreeEventHandler(BookmarkPanel::onTreeItemMenu), NULL, this);
+	m_treeView->Disconnect(wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler(BookmarkPanel::onTreeSelect), NULL, this);
+	m_treeView->Disconnect(wxEVT_COMMAND_TREE_SEL_CHANGING, wxTreeEventHandler(BookmarkPanel::onTreeSelectChanging), NULL, this);
+	m_labelText->Disconnect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(BookmarkPanel::onLabelText), NULL, this);
+	m_frequencyVal->Disconnect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(BookmarkPanel::onDoubleClickFreq), NULL, this);
+	m_bandwidthVal->Disconnect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(BookmarkPanel::onDoubleClickBandwidth), NULL, this);
+	this->Disconnect(wxID_ANY, wxEVT_TIMER, wxTimerEventHandler(BookmarkPanel::onUpdateTimer));
+
 }
diff --git a/src/forms/Bookmark/BookmarkPanel.h b/src/forms/Bookmark/BookmarkPanel.h
index f6fd49f..2e1a4fb 100644
--- a/src/forms/Bookmark/BookmarkPanel.h
+++ b/src/forms/Bookmark/BookmarkPanel.h
@@ -1,8 +1,8 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Jun 17 2015)
+// C++ code generated with wxFormBuilder (version Oct 27 2017)
 // http://www.wxformbuilder.org/
 //
-// PLEASE DO "NOT" EDIT THIS FILE!
+// PLEASE DO *NOT* EDIT THIS FILE!
 ///////////////////////////////////////////////////////////////////////////
 
 #ifndef __BOOKMARKPANEL_H__
@@ -29,53 +29,53 @@
 ///////////////////////////////////////////////////////////////////////////////
 /// Class BookmarkPanel
 ///////////////////////////////////////////////////////////////////////////////
-class BookmarkPanel : public wxPanel 
+class BookmarkPanel : public wxPanel
 {
-	private:
-	
-	protected:
-		wxTextCtrl* m_searchText;
-		wxButton* m_clearSearchButton;
-		wxTreeCtrl* m_treeView;
-		wxPanel* m_propPanel;
-		wxStaticText* m_labelLabel;
-		wxTextCtrl* m_labelText;
-		wxStaticText* m_frequencyLabel;
-		wxStaticText* m_frequencyVal;
-		wxStaticText* m_bandwidthLabel;
-		wxStaticText* m_bandwidthVal;
-		wxStaticText* m_modulationLabel;
-		wxStaticText* m_modulationVal;
-		wxPanel* m_buttonPanel;
-		wxTimer m_updateTimer;
-		
-		// Virtual event handlers, overide them in your derived class
-		virtual void onEnterWindow( wxMouseEvent& event ) { event.Skip(); }
-		virtual void onLeaveWindow( wxMouseEvent& event ) { event.Skip(); }
-		virtual void onMotion( wxMouseEvent& event ) { event.Skip(); }
-		virtual void onSearchTextFocus( wxMouseEvent& event ) { event.Skip(); }
-		virtual void onSearchText( wxCommandEvent& event ) { event.Skip(); }
-		virtual void onClearSearch( wxCommandEvent& event ) { event.Skip(); }
-		virtual void onTreeBeginDrag( wxTreeEvent& event ) { event.Skip(); }
-		virtual void onTreeEndDrag( wxTreeEvent& event ) { event.Skip(); }
-		virtual void onTreeActivate( wxTreeEvent& event ) { event.Skip(); }
-		virtual void onTreeCollapse( wxTreeEvent& event ) { event.Skip(); }
-		virtual void onTreeExpanded( wxTreeEvent& event ) { event.Skip(); }
-		virtual void onTreeItemGetTooltip( wxTreeEvent& event ) { event.Skip(); }
-		virtual void onTreeItemMenu( wxTreeEvent& event ) { event.Skip(); }
-		virtual void onTreeSelect( wxTreeEvent& event ) { event.Skip(); }
-		virtual void onTreeSelectChanging( wxTreeEvent& event ) { event.Skip(); }
-		virtual void onLabelText( wxCommandEvent& event ) { event.Skip(); }
-		virtual void onDoubleClickFreq( wxMouseEvent& event ) { event.Skip(); }
-		virtual void onDoubleClickBandwidth( wxMouseEvent& event ) { event.Skip(); }
-		virtual void onUpdateTimer( wxTimerEvent& event ) { event.Skip(); }
-		
-	
-	public:
-		
-		BookmarkPanel( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 169,471 ), long style = wxTAB_TRAVERSAL ); 
-		~BookmarkPanel();
-	
+private:
+
+protected:
+	wxTextCtrl* m_searchText;
+	wxButton* m_clearSearchButton;
+	wxTreeCtrl* m_treeView;
+	wxPanel* m_propPanel;
+	wxStaticText* m_labelLabel;
+	wxTextCtrl* m_labelText;
+	wxStaticText* m_frequencyLabel;
+	wxStaticText* m_frequencyVal;
+	wxStaticText* m_bandwidthLabel;
+	wxStaticText* m_bandwidthVal;
+	wxStaticText* m_modulationLabel;
+	wxStaticText* m_modulationVal;
+	wxPanel* m_buttonPanel;
+	wxTimer m_updateTimer;
+
+	// Virtual event handlers, overide them in your derived class
+	virtual void onEnterWindow(wxMouseEvent& event) { event.Skip(); }
+	virtual void onLeaveWindow(wxMouseEvent& event) { event.Skip(); }
+	virtual void onMotion(wxMouseEvent& event) { event.Skip(); }
+	virtual void onSearchTextFocus(wxMouseEvent& event) { event.Skip(); }
+	virtual void onSearchText(wxCommandEvent& event) { event.Skip(); }
+	virtual void onClearSearch(wxCommandEvent& event) { event.Skip(); }
+	virtual void onTreeBeginDrag(wxTreeEvent& event) { event.Skip(); }
+	virtual void onTreeEndDrag(wxTreeEvent& event) { event.Skip(); }
+	virtual void onTreeActivate(wxTreeEvent& event) { event.Skip(); }
+	virtual void onTreeCollapse(wxTreeEvent& event) { event.Skip(); }
+	virtual void onTreeExpanded(wxTreeEvent& event) { event.Skip(); }
+	virtual void onTreeItemGetTooltip(wxTreeEvent& event) { event.Skip(); }
+	virtual void onTreeItemMenu(wxTreeEvent& event) { event.Skip(); }
+	virtual void onTreeSelect(wxTreeEvent& event) { event.Skip(); }
+	virtual void onTreeSelectChanging(wxTreeEvent& event) { event.Skip(); }
+	virtual void onLabelText(wxCommandEvent& event) { event.Skip(); }
+	virtual void onDoubleClickFreq(wxMouseEvent& event) { event.Skip(); }
+	virtual void onDoubleClickBandwidth(wxMouseEvent& event) { event.Skip(); }
+	virtual void onUpdateTimer(wxTimerEvent& event) { event.Skip(); }
+
+
+public:
+
+	BookmarkPanel(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(169, 471), long style = wxTAB_TRAVERSAL);
+	~BookmarkPanel();
+
 };
 
 #endif //__BOOKMARKPANEL_H__
diff --git a/src/forms/Bookmark/BookmarkView.cpp b/src/forms/Bookmark/BookmarkView.cpp
index 883b813..ee84b13 100644
--- a/src/forms/Bookmark/BookmarkView.cpp
+++ b/src/forms/Bookmark/BookmarkView.cpp
@@ -78,7 +78,8 @@ public:
         
         if (name.length() == 0) {
             std::string wstr = frequencyToStr(rangeEnt->startFreq) + " - " + frequencyToStr(rangeEnt->endFreq);
-            name = std::wstring(wstr.begin(),wstr.end());
+
+            name = wxString(wstr).ToStdWstring();
         }
         
         m_questionText->SetLabelText(L"Are you sure you want to remove the range\n '" + name + L"'?");
@@ -103,7 +104,8 @@ public:
         
         if (name.length() == 0) {
             std::string wstr = frequencyToStr(rangeEnt->startFreq) + " - " + frequencyToStr(rangeEnt->endFreq);
-            name = std::wstring(wstr.begin(),wstr.end());
+            
+			name = wxString(wstr).ToStdWstring();
         }
         
         m_questionText->SetLabelText(L"Are you sure you want to update the range\n '" + name + L"' to the active range?");
@@ -311,9 +313,9 @@ wxTreeItemId BookmarkView::refreshBookmarks() {
                 std::wstring fullText = labelVal +
                     L" " + bmEnt->label +
                     L" " + std::to_wstring(bmEnt->frequency) +
-                    L" " + std::wstring(freqStr.begin(),freqStr.end()) +
-                    L" " + std::wstring(bwStr.begin(),bwStr.end()) +
-                    L" " + std::wstring(bmEnt->type.begin(),bmEnt->type.end());
+                    L" " + wxString(freqStr).ToStdWstring() +
+                    L" " + wxString(bwStr).ToStdWstring() +
+                    L" " + wxString(bmEnt->type).ToStdWstring();
                 
                 if (!isKeywordMatch(fullText, searchKeywords)) {
                     continue;
@@ -348,10 +350,9 @@ wxTreeItemId BookmarkView::refreshBookmarks() {
 
 
 void BookmarkView::doUpdateActiveList() {
-    std::vector<DemodulatorInstance *> &demods = wxGetApp().getDemodMgr().getDemodulators();
-    
-//    DemodulatorInstance *activeDemodulator = wxGetApp().getDemodMgr().getActiveDemodulator();
-    DemodulatorInstance *lastActiveDemodulator = wxGetApp().getDemodMgr().getLastActiveDemodulator();
+
+    auto demods = wxGetApp().getDemodMgr().getDemodulators();
+    auto lastActiveDemodulator = wxGetApp().getDemodMgr().getLastActiveDemodulator();
 
     //capture the previously selected item info BY COPY (because the original will be destroyed together with the destroyed tree items) to restore it again after 
     //having rebuilding the whole tree.
@@ -380,9 +381,9 @@ void BookmarkView::doUpdateActiveList() {
             std::wstring fullText = activeLabel.ToStdWstring() +
             L" " + demod_i->getDemodulatorUserLabel() +
             L" " + std::to_wstring(demod_i->getFrequency()) +
-            L" " + std::wstring(freqStr.begin(),freqStr.end()) +
-            L" " + std::wstring(bwStr.begin(),bwStr.end()) +
-            L" " + std::wstring(mtype.begin(),mtype.end());
+            L" " + wxString(freqStr).ToStdWstring() +
+            L" " + wxString(bwStr).ToStdWstring() +
+            L" " + wxString(mtype).ToStdWstring();
             
             if (!isKeywordMatch(fullText, searchKeywords)) {
                 continue;
@@ -419,9 +420,10 @@ void BookmarkView::doUpdateActiveList() {
         
         std::wstring labelVal = re_i->label;
         
-        if (labelVal == "") {
+        if (labelVal == L"") {
             std::string wstr = frequencyToStr(re_i->startFreq) + " - " + frequencyToStr(re_i->endFreq);
-            labelVal = std::wstring(wstr.begin(),wstr.end());
+
+            labelVal = wxString(wstr).ToStdWstring();
         }
         
         wxTreeItemId itm = m_treeView->AppendItem(rangeBranch, labelVal);
@@ -449,9 +451,10 @@ void BookmarkView::doUpdateActiveList() {
         std::wstring labelVal;
         bmr_i->node->child("user_label")->element()->get(labelVal);
 
-        if (labelVal == "") {
-            std::string wstr = frequencyToStr(bmr_i->frequency) + " " + bmr_i->type;
-            labelVal = std::wstring(wstr.begin(),wstr.end());
+        if (labelVal == L"") {
+            std::string str = frequencyToStr(bmr_i->frequency) + " " + bmr_i->type;
+
+            labelVal = wxString(str).ToStdWstring();
         }
         
         if (searchKeywords.size()) {
@@ -461,9 +464,10 @@ void BookmarkView::doUpdateActiveList() {
             
             std::wstring fullText = labelVal +
                 L" " + std::to_wstring(bmr_i->frequency) +
-                L" " + std::wstring(freqStr.begin(),freqStr.end()) +
-                L" " + std::wstring(bwStr.begin(),bwStr.end()) +
-                L" " + std::wstring(bmr_i->type.begin(),tvi->bookmarkEnt->type.end());
+
+                L" " + wxString(freqStr).ToStdWstring() +
+                L" " + wxString(bwStr).ToStdWstring() +
+                L" " + wxString(bmr_i->type).ToStdWstring();
             
             if (!isKeywordMatch(fullText, searchKeywords)) {
                 continue;
@@ -693,7 +697,8 @@ wxButton *BookmarkView::addButton(wxWindow *parent, std::string labelVal, wxObje
 }
 
 
-void BookmarkView::doBookmarkActive(std::string group, DemodulatorInstance *demod) {
+void BookmarkView::doBookmarkActive(std::string group, DemodulatorInstancePtr demod) {
+
     wxGetApp().getBookmarkMgr().addBookmark(group, demod);
     wxGetApp().getBookmarkMgr().updateBookmarks();
 }
@@ -717,7 +722,7 @@ void BookmarkView::doMoveBookmark(BookmarkEntryPtr be, std::string group) {
 }
 
 
-void BookmarkView::doRemoveActive(DemodulatorInstance *demod) {
+void BookmarkView::doRemoveActive(DemodulatorInstancePtr demod) {
 
 	wxGetApp().getBookmarkMgr().removeActive(demod);
 	wxGetApp().getBookmarkMgr().updateActiveList();
@@ -792,7 +797,7 @@ void BookmarkView::onBookmarkChoice( wxCommandEvent & /* event */ ) {
 }
 
 
-void BookmarkView::activeSelection(DemodulatorInstance *dsel) {
+void BookmarkView::activeSelection(DemodulatorInstancePtr dsel) {
     
     m_frequencyVal->SetLabelText(frequencyToStr(dsel->getFrequency()));
     m_bandwidthVal->SetLabelText(frequencyToStr(dsel->getBandwidth()));
@@ -816,8 +821,16 @@ void BookmarkView::activeSelection(DemodulatorInstance *dsel) {
     clearButtons();
 
     addBookmarkChoice(m_buttonPanel);
-    addButton(m_buttonPanel, "Remove Active", wxCommandEventHandler( BookmarkView::onRemoveActive ));
+    
+    if (dsel->isActive() && !(dsel->isRecording())) {
+        addButton(m_buttonPanel, "Start Recording", wxCommandEventHandler( BookmarkView::onStartRecording ));
+    } else {
+        addButton(m_buttonPanel, "Stop Recording", wxCommandEventHandler( BookmarkView::onStopRecording ));
+    }
 
+    addButton(m_buttonPanel, "Remove Active", wxCommandEventHandler( BookmarkView::onRemoveActive ));
+    
+    
     showProps();
     showButtons();
     refreshLayout();
@@ -835,7 +848,7 @@ void BookmarkView::activateBookmark(BookmarkEntryPtr bmEnt) {
 	//the already existing one:
 	// we search among the list of existing demodulators the one matching 
 	//bmEnt and activate it. The search is made backwards, to select the most recently created one.
-	DemodulatorInstance *matchingDemod = wxGetApp().getDemodMgr().getLastDemodulatorWith(
+	DemodulatorInstancePtr matchingDemod = wxGetApp().getDemodMgr().getLastDemodulatorWith(
 																		bmEnt->type,
 																		bmEnt->label, 
 																		bmEnt->frequency, 
@@ -845,7 +858,7 @@ void BookmarkView::activateBookmark(BookmarkEntryPtr bmEnt) {
 
 		matchingDemod = wxGetApp().getDemodMgr().loadInstance(bmEnt->node);
 		matchingDemod->run();
-		wxGetApp().bindDemodulator(matchingDemod);
+		wxGetApp().notifyDemodulatorsChanged();
 	}
 
 	matchingDemod->setActive(true);
@@ -865,7 +878,11 @@ void BookmarkView::activateBookmark(BookmarkEntryPtr bmEnt) {
 
 
 void BookmarkView::activateRange(BookmarkRangeEntryPtr rangeEnt) {
-    wxGetApp().setFrequency(rangeEnt->freq);
+    
+	//the following oly works if rangeEnt->freq is the middle of [rangeEnt->startFreq ; rangeEnt->startFreq]
+	wxGetApp().setFrequency(rangeEnt->freq);
+	
+	// Change View limits to fit the range exactly.
     wxGetApp().getAppFrame()->setViewState(rangeEnt->startFreq + (rangeEnt->endFreq - rangeEnt->startFreq) / 2, rangeEnt->endFreq - rangeEnt->startFreq);
 }
 
@@ -971,7 +988,7 @@ void BookmarkView::rangeSelection(BookmarkRangeEntryPtr re) {
 
     std::string strFreq = frequencyToStr(re->startFreq) + "-" + frequencyToStr(re->endFreq);
     
-    m_frequencyVal->SetLabelText(std::wstring(strFreq.begin(),strFreq.end()));
+    m_frequencyVal->SetLabelText(wxString(strFreq));
     
     showProps();
 
@@ -1149,6 +1166,30 @@ void BookmarkView::onRemoveActive( wxCommandEvent& /* event */ ) {
     }
 }
 
+void BookmarkView::onStartRecording( wxCommandEvent& /* event */ ) {
+    TreeViewItem *curSel = itemToTVI(m_treeView->GetSelection());
+    
+    if (curSel && curSel->type == TreeViewItem::TREEVIEW_ITEM_TYPE_ACTIVE) {
+        if (!curSel->demod->isRecording() && wxGetApp().getConfig()->verifyRecordingPath()) {
+            curSel->demod->setRecording(true);
+            wxGetApp().getBookmarkMgr().updateActiveList();
+        }
+    }
+}
+
+
+void BookmarkView::onStopRecording( wxCommandEvent& /* event */ ) {
+    TreeViewItem *curSel = itemToTVI(m_treeView->GetSelection());
+    
+    if (curSel && curSel->type == TreeViewItem::TREEVIEW_ITEM_TYPE_ACTIVE) {
+        if (curSel->demod->isRecording()) {
+            curSel->demod->setRecording(false);
+            wxGetApp().getBookmarkMgr().updateActiveList();
+        }
+    }
+}
+
+
 
 void BookmarkView::onRemoveBookmark( wxCommandEvent& /* event */ ) {
     if (editingLabel) {
@@ -1411,7 +1452,7 @@ void BookmarkView::onEnterWindow( wxMouseEvent&  event ) {
     }
 #endif
 
-    setStatusText("You can mouse-drag a bookmark entry from one category to the next..etc. TODO: add more Bookmarks descriptions");
+    setStatusText("Drag & Drop to create / move bookmarks, Group and arrange bookmarks, quick Search by keywords.");
 }
 
 
@@ -1473,16 +1514,16 @@ void BookmarkView::onSearchTextFocus( wxMouseEvent&  event ) {
 
 
 void BookmarkView::onSearchText( wxCommandEvent& event ) {
-    wstring searchText = m_searchText->GetValue().Trim().Lower().ToStdWstring();
+    std::wstring searchText = m_searchText->GetValue().Trim().Lower().ToStdWstring();
     
    searchKeywords.clear();
     
    if (searchText.length() != 0) {
         std::wstringstream searchTextLo(searchText);
-        wstring tmp;
+        std::wstring tmp;
         
         while(std::getline(searchTextLo, tmp, L' ')) {
-            if (tmp.length() != 0 && tmp.find(L"search.") == wstring::npos) {
+            if (tmp.length() != 0 && tmp.find(L"search.") == std::wstring::npos) {
                 searchKeywords.push_back(tmp);
 //                std::wcout << L"Keyword: " << tmp << '\n';
             }
@@ -1531,10 +1572,13 @@ void BookmarkView::loadDefaultRanges() {
 
 BookmarkRangeEntryPtr BookmarkView::makeActiveRangeEntry() {
     BookmarkRangeEntryPtr re(new BookmarkRangeEntry);
-    re->freq = wxGetApp().getFrequency();
+   
     re->startFreq = wxGetApp().getAppFrame()->getViewCenterFreq() - (wxGetApp().getAppFrame()->getViewBandwidth()/2);
     re->endFreq = wxGetApp().getAppFrame()->getViewCenterFreq() + (wxGetApp().getAppFrame()->getViewBandwidth()/2);
     
+	//to prevent problems, always make the re->freq the middle of the interval.
+	re->freq = (re->startFreq + re->endFreq) / 2;
+
     return re;
 }
 
diff --git a/src/forms/Bookmark/BookmarkView.h b/src/forms/Bookmark/BookmarkView.h
index 6470bd5..820ece1 100644
--- a/src/forms/Bookmark/BookmarkView.h
+++ b/src/forms/Bookmark/BookmarkView.h
@@ -43,7 +43,7 @@ public:
     BookmarkEntryPtr bookmarkEnt; 
     BookmarkRangeEntryPtr rangeEnt;
     
-    DemodulatorInstance* demod;
+    DemodulatorInstancePtr demod;
     std::string groupName;
 };
 
@@ -84,7 +84,7 @@ public:
     static BookmarkRangeEntryPtr makeActiveRangeEntry();
 
 protected:
-    void activeSelection(DemodulatorInstance *dsel);
+    void activeSelection(DemodulatorInstancePtr dsel);
     void bookmarkSelection(BookmarkEntryPtr bmSel);
     void rangeSelection(BookmarkRangeEntryPtr re);
     
@@ -133,10 +133,10 @@ protected:
     wxButton *makeButton(wxWindow *parent, std::string labelVal, wxObjectEventFunction handler);
     wxButton *addButton(wxWindow *parent, std::string labelVal, wxObjectEventFunction handler);
 
-    void doBookmarkActive(std::string group, DemodulatorInstance *demod);
+    void doBookmarkActive(std::string group, DemodulatorInstancePtr demod);
     void doBookmarkRecent(std::string group, BookmarkEntryPtr be);
     void doMoveBookmark(BookmarkEntryPtr be, std::string group);
-    void doRemoveActive(DemodulatorInstance *demod);
+    void doRemoveActive(DemodulatorInstancePtr demod);
     void doRemoveRecent(BookmarkEntryPtr be);
     void doClearRecents();
     
@@ -145,6 +145,8 @@ protected:
     void onBookmarkChoice( wxCommandEvent &event );
     
     void onRemoveActive( wxCommandEvent& event );
+    void onStartRecording( wxCommandEvent& event );
+    void onStopRecording( wxCommandEvent& event );
     void onRemoveBookmark( wxCommandEvent& event );
     
     void onActivateBookmark( wxCommandEvent& event );
@@ -191,7 +193,7 @@ protected:
     // Focus
     BookmarkEntryPtr nextEnt;
     BookmarkRangeEntryPtr nextRange;
-    DemodulatorInstance *nextDemod;
+    DemodulatorInstancePtr nextDemod;
     std::string nextGroup;
     
     // Search
diff --git a/src/forms/Dialog/AboutDialog.fbp b/src/forms/Dialog/AboutDialog.fbp
index 9f9cb8a..3d91594 100644
--- a/src/forms/Dialog/AboutDialog.fbp
+++ b/src/forms/Dialog/AboutDialog.fbp
@@ -6534,6 +6534,421 @@
                                                     <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
+                                            <object class="sizeritem" expanded="1">
+                                                <property name="border">5</property>
+                                                <property name="flag">wxALL</property>
+                                                <property name="proportion">0</property>
+                                                <object class="wxStaticText" expanded="1">
+                                                    <property name="BottomDockable">1</property>
+                                                    <property name="LeftDockable">1</property>
+                                                    <property name="RightDockable">1</property>
+                                                    <property name="TopDockable">1</property>
+                                                    <property name="aui_layer"></property>
+                                                    <property name="aui_name"></property>
+                                                    <property name="aui_position"></property>
+                                                    <property name="aui_row"></property>
+                                                    <property name="best_size"></property>
+                                                    <property name="bg"></property>
+                                                    <property name="caption"></property>
+                                                    <property name="caption_visible">1</property>
+                                                    <property name="center_pane">0</property>
+                                                    <property name="close_button">1</property>
+                                                    <property name="context_help"></property>
+                                                    <property name="context_menu">1</property>
+                                                    <property name="default_pane">0</property>
+                                                    <property name="dock">Dock</property>
+                                                    <property name="dock_fixed">0</property>
+                                                    <property name="docking">Left</property>
+                                                    <property name="enabled">1</property>
+                                                    <property name="fg"></property>
+                                                    <property name="floatable">1</property>
+                                                    <property name="font"></property>
+                                                    <property name="gripper">0</property>
+                                                    <property name="hidden">0</property>
+                                                    <property name="id">wxID_ANY</property>
+                                                    <property name="label">Chad Myslinsky</property>
+                                                    <property name="max_size"></property>
+                                                    <property name="maximize_button">0</property>
+                                                    <property name="maximum_size"></property>
+                                                    <property name="min_size"></property>
+                                                    <property name="minimize_button">0</property>
+                                                    <property name="minimum_size"></property>
+                                                    <property name="moveable">1</property>
+                                                    <property name="name">m_dChadMyslinsky</property>
+                                                    <property name="pane_border">1</property>
+                                                    <property name="pane_position"></property>
+                                                    <property name="pane_size"></property>
+                                                    <property name="permission">protected</property>
+                                                    <property name="pin_button">1</property>
+                                                    <property name="pos"></property>
+                                                    <property name="resize">Resizable</property>
+                                                    <property name="show">1</property>
+                                                    <property name="size"></property>
+                                                    <property name="style"></property>
+                                                    <property name="subclass"></property>
+                                                    <property name="toolbar_pane">0</property>
+                                                    <property name="tooltip"></property>
+                                                    <property name="window_extra_style"></property>
+                                                    <property name="window_name"></property>
+                                                    <property name="window_style"></property>
+                                                    <property name="wrap">-1</property>
+                                                    <event name="OnChar"></event>
+                                                    <event name="OnEnterWindow"></event>
+                                                    <event name="OnEraseBackground"></event>
+                                                    <event name="OnKeyDown"></event>
+                                                    <event name="OnKeyUp"></event>
+                                                    <event name="OnKillFocus"></event>
+                                                    <event name="OnLeaveWindow"></event>
+                                                    <event name="OnLeftDClick"></event>
+                                                    <event name="OnLeftDown"></event>
+                                                    <event name="OnLeftUp"></event>
+                                                    <event name="OnMiddleDClick"></event>
+                                                    <event name="OnMiddleDown"></event>
+                                                    <event name="OnMiddleUp"></event>
+                                                    <event name="OnMotion"></event>
+                                                    <event name="OnMouseEvents"></event>
+                                                    <event name="OnMouseWheel"></event>
+                                                    <event name="OnPaint"></event>
+                                                    <event name="OnRightDClick"></event>
+                                                    <event name="OnRightDown"></event>
+                                                    <event name="OnRightUp"></event>
+                                                    <event name="OnSetFocus"></event>
+                                                    <event name="OnSize"></event>
+                                                    <event name="OnUpdateUI"></event>
+                                                </object>
+                                            </object>
+                                            <object class="sizeritem" expanded="1">
+                                                <property name="border">5</property>
+                                                <property name="flag">wxALL</property>
+                                                <property name="proportion">0</property>
+                                                <object class="wxStaticText" expanded="1">
+                                                    <property name="BottomDockable">1</property>
+                                                    <property name="LeftDockable">1</property>
+                                                    <property name="RightDockable">1</property>
+                                                    <property name="TopDockable">1</property>
+                                                    <property name="aui_layer"></property>
+                                                    <property name="aui_name"></property>
+                                                    <property name="aui_position"></property>
+                                                    <property name="aui_row"></property>
+                                                    <property name="best_size"></property>
+                                                    <property name="bg"></property>
+                                                    <property name="caption"></property>
+                                                    <property name="caption_visible">1</property>
+                                                    <property name="center_pane">0</property>
+                                                    <property name="close_button">1</property>
+                                                    <property name="context_help"></property>
+                                                    <property name="context_menu">1</property>
+                                                    <property name="default_pane">0</property>
+                                                    <property name="dock">Dock</property>
+                                                    <property name="dock_fixed">0</property>
+                                                    <property name="docking">Left</property>
+                                                    <property name="enabled">1</property>
+                                                    <property name="fg"></property>
+                                                    <property name="floatable">1</property>
+                                                    <property name="font"></property>
+                                                    <property name="gripper">0</property>
+                                                    <property name="hidden">0</property>
+                                                    <property name="id">wxID_ANY</property>
+                                                    <property name="label">Charlie Bruckner</property>
+                                                    <property name="max_size"></property>
+                                                    <property name="maximize_button">0</property>
+                                                    <property name="maximum_size"></property>
+                                                    <property name="min_size"></property>
+                                                    <property name="minimize_button">0</property>
+                                                    <property name="minimum_size"></property>
+                                                    <property name="moveable">1</property>
+                                                    <property name="name">m_dCharlieBruckner</property>
+                                                    <property name="pane_border">1</property>
+                                                    <property name="pane_position"></property>
+                                                    <property name="pane_size"></property>
+                                                    <property name="permission">protected</property>
+                                                    <property name="pin_button">1</property>
+                                                    <property name="pos"></property>
+                                                    <property name="resize">Resizable</property>
+                                                    <property name="show">1</property>
+                                                    <property name="size"></property>
+                                                    <property name="style"></property>
+                                                    <property name="subclass"></property>
+                                                    <property name="toolbar_pane">0</property>
+                                                    <property name="tooltip"></property>
+                                                    <property name="window_extra_style"></property>
+                                                    <property name="window_name"></property>
+                                                    <property name="window_style"></property>
+                                                    <property name="wrap">-1</property>
+                                                    <event name="OnChar"></event>
+                                                    <event name="OnEnterWindow"></event>
+                                                    <event name="OnEraseBackground"></event>
+                                                    <event name="OnKeyDown"></event>
+                                                    <event name="OnKeyUp"></event>
+                                                    <event name="OnKillFocus"></event>
+                                                    <event name="OnLeaveWindow"></event>
+                                                    <event name="OnLeftDClick"></event>
+                                                    <event name="OnLeftDown"></event>
+                                                    <event name="OnLeftUp"></event>
+                                                    <event name="OnMiddleDClick"></event>
+                                                    <event name="OnMiddleDown"></event>
+                                                    <event name="OnMiddleUp"></event>
+                                                    <event name="OnMotion"></event>
+                                                    <event name="OnMouseEvents"></event>
+                                                    <event name="OnMouseWheel"></event>
+                                                    <event name="OnPaint"></event>
+                                                    <event name="OnRightDClick"></event>
+                                                    <event name="OnRightDown"></event>
+                                                    <event name="OnRightUp"></event>
+                                                    <event name="OnSetFocus"></event>
+                                                    <event name="OnSize"></event>
+                                                    <event name="OnUpdateUI"></event>
+                                                </object>
+                                            </object>
+                                            <object class="sizeritem" expanded="1">
+                                                <property name="border">5</property>
+                                                <property name="flag">wxALL</property>
+                                                <property name="proportion">0</property>
+                                                <object class="wxStaticText" expanded="1">
+                                                    <property name="BottomDockable">1</property>
+                                                    <property name="LeftDockable">1</property>
+                                                    <property name="RightDockable">1</property>
+                                                    <property name="TopDockable">1</property>
+                                                    <property name="aui_layer"></property>
+                                                    <property name="aui_name"></property>
+                                                    <property name="aui_position"></property>
+                                                    <property name="aui_row"></property>
+                                                    <property name="best_size"></property>
+                                                    <property name="bg"></property>
+                                                    <property name="caption"></property>
+                                                    <property name="caption_visible">1</property>
+                                                    <property name="center_pane">0</property>
+                                                    <property name="close_button">1</property>
+                                                    <property name="context_help"></property>
+                                                    <property name="context_menu">1</property>
+                                                    <property name="default_pane">0</property>
+                                                    <property name="dock">Dock</property>
+                                                    <property name="dock_fixed">0</property>
+                                                    <property name="docking">Left</property>
+                                                    <property name="enabled">1</property>
+                                                    <property name="fg"></property>
+                                                    <property name="floatable">1</property>
+                                                    <property name="font"></property>
+                                                    <property name="gripper">0</property>
+                                                    <property name="hidden">0</property>
+                                                    <property name="id">wxID_ANY</property>
+                                                    <property name="label">Jordan Parker</property>
+                                                    <property name="max_size"></property>
+                                                    <property name="maximize_button">0</property>
+                                                    <property name="maximum_size"></property>
+                                                    <property name="min_size"></property>
+                                                    <property name="minimize_button">0</property>
+                                                    <property name="minimum_size"></property>
+                                                    <property name="moveable">1</property>
+                                                    <property name="name">m_dJordanParker</property>
+                                                    <property name="pane_border">1</property>
+                                                    <property name="pane_position"></property>
+                                                    <property name="pane_size"></property>
+                                                    <property name="permission">protected</property>
+                                                    <property name="pin_button">1</property>
+                                                    <property name="pos"></property>
+                                                    <property name="resize">Resizable</property>
+                                                    <property name="show">1</property>
+                                                    <property name="size"></property>
+                                                    <property name="style"></property>
+                                                    <property name="subclass"></property>
+                                                    <property name="toolbar_pane">0</property>
+                                                    <property name="tooltip"></property>
+                                                    <property name="window_extra_style"></property>
+                                                    <property name="window_name"></property>
+                                                    <property name="window_style"></property>
+                                                    <property name="wrap">-1</property>
+                                                    <event name="OnChar"></event>
+                                                    <event name="OnEnterWindow"></event>
+                                                    <event name="OnEraseBackground"></event>
+                                                    <event name="OnKeyDown"></event>
+                                                    <event name="OnKeyUp"></event>
+                                                    <event name="OnKillFocus"></event>
+                                                    <event name="OnLeaveWindow"></event>
+                                                    <event name="OnLeftDClick"></event>
+                                                    <event name="OnLeftDown"></event>
+                                                    <event name="OnLeftUp"></event>
+                                                    <event name="OnMiddleDClick"></event>
+                                                    <event name="OnMiddleDown"></event>
+                                                    <event name="OnMiddleUp"></event>
+                                                    <event name="OnMotion"></event>
+                                                    <event name="OnMouseEvents"></event>
+                                                    <event name="OnMouseWheel"></event>
+                                                    <event name="OnPaint"></event>
+                                                    <event name="OnRightDClick"></event>
+                                                    <event name="OnRightDown"></event>
+                                                    <event name="OnRightUp"></event>
+                                                    <event name="OnSetFocus"></event>
+                                                    <event name="OnSize"></event>
+                                                    <event name="OnUpdateUI"></event>
+                                                </object>
+                                            </object>
+                                            <object class="sizeritem" expanded="1">
+                                                <property name="border">5</property>
+                                                <property name="flag">wxALL</property>
+                                                <property name="proportion">0</property>
+                                                <object class="wxStaticText" expanded="1">
+                                                    <property name="BottomDockable">1</property>
+                                                    <property name="LeftDockable">1</property>
+                                                    <property name="RightDockable">1</property>
+                                                    <property name="TopDockable">1</property>
+                                                    <property name="aui_layer"></property>
+                                                    <property name="aui_name"></property>
+                                                    <property name="aui_position"></property>
+                                                    <property name="aui_row"></property>
+                                                    <property name="best_size"></property>
+                                                    <property name="bg"></property>
+                                                    <property name="caption"></property>
+                                                    <property name="caption_visible">1</property>
+                                                    <property name="center_pane">0</property>
+                                                    <property name="close_button">1</property>
+                                                    <property name="context_help"></property>
+                                                    <property name="context_menu">1</property>
+                                                    <property name="default_pane">0</property>
+                                                    <property name="dock">Dock</property>
+                                                    <property name="dock_fixed">0</property>
+                                                    <property name="docking">Left</property>
+                                                    <property name="enabled">1</property>
+                                                    <property name="fg"></property>
+                                                    <property name="floatable">1</property>
+                                                    <property name="font"></property>
+                                                    <property name="gripper">0</property>
+                                                    <property name="hidden">0</property>
+                                                    <property name="id">wxID_ANY</property>
+                                                    <property name="label">Robert Chave</property>
+                                                    <property name="max_size"></property>
+                                                    <property name="maximize_button">0</property>
+                                                    <property name="maximum_size"></property>
+                                                    <property name="min_size"></property>
+                                                    <property name="minimize_button">0</property>
+                                                    <property name="minimum_size"></property>
+                                                    <property name="moveable">1</property>
+                                                    <property name="name">m_dRobertChave</property>
+                                                    <property name="pane_border">1</property>
+                                                    <property name="pane_position"></property>
+                                                    <property name="pane_size"></property>
+                                                    <property name="permission">protected</property>
+                                                    <property name="pin_button">1</property>
+                                                    <property name="pos"></property>
+                                                    <property name="resize">Resizable</property>
+                                                    <property name="show">1</property>
+                                                    <property name="size"></property>
+                                                    <property name="style"></property>
+                                                    <property name="subclass"></property>
+                                                    <property name="toolbar_pane">0</property>
+                                                    <property name="tooltip"></property>
+                                                    <property name="window_extra_style"></property>
+                                                    <property name="window_name"></property>
+                                                    <property name="window_style"></property>
+                                                    <property name="wrap">-1</property>
+                                                    <event name="OnChar"></event>
+                                                    <event name="OnEnterWindow"></event>
+                                                    <event name="OnEraseBackground"></event>
+                                                    <event name="OnKeyDown"></event>
+                                                    <event name="OnKeyUp"></event>
+                                                    <event name="OnKillFocus"></event>
+                                                    <event name="OnLeaveWindow"></event>
+                                                    <event name="OnLeftDClick"></event>
+                                                    <event name="OnLeftDown"></event>
+                                                    <event name="OnLeftUp"></event>
+                                                    <event name="OnMiddleDClick"></event>
+                                                    <event name="OnMiddleDown"></event>
+                                                    <event name="OnMiddleUp"></event>
+                                                    <event name="OnMotion"></event>
+                                                    <event name="OnMouseEvents"></event>
+                                                    <event name="OnMouseWheel"></event>
+                                                    <event name="OnPaint"></event>
+                                                    <event name="OnRightDClick"></event>
+                                                    <event name="OnRightDown"></event>
+                                                    <event name="OnRightUp"></event>
+                                                    <event name="OnSetFocus"></event>
+                                                    <event name="OnSize"></event>
+                                                    <event name="OnUpdateUI"></event>
+                                                </object>
+                                            </object>
+                                            <object class="sizeritem" expanded="1">
+                                                <property name="border">5</property>
+                                                <property name="flag">wxALL</property>
+                                                <property name="proportion">0</property>
+                                                <object class="wxStaticText" expanded="1">
+                                                    <property name="BottomDockable">1</property>
+                                                    <property name="LeftDockable">1</property>
+                                                    <property name="RightDockable">1</property>
+                                                    <property name="TopDockable">1</property>
+                                                    <property name="aui_layer"></property>
+                                                    <property name="aui_name"></property>
+                                                    <property name="aui_position"></property>
+                                                    <property name="aui_row"></property>
+                                                    <property name="best_size"></property>
+                                                    <property name="bg"></property>
+                                                    <property name="caption"></property>
+                                                    <property name="caption_visible">1</property>
+                                                    <property name="center_pane">0</property>
+                                                    <property name="close_button">1</property>
+                                                    <property name="context_help"></property>
+                                                    <property name="context_menu">1</property>
+                                                    <property name="default_pane">0</property>
+                                                    <property name="dock">Dock</property>
+                                                    <property name="dock_fixed">0</property>
+                                                    <property name="docking">Left</property>
+                                                    <property name="enabled">1</property>
+                                                    <property name="fg"></property>
+                                                    <property name="floatable">1</property>
+                                                    <property name="font"></property>
+                                                    <property name="gripper">0</property>
+                                                    <property name="hidden">0</property>
+                                                    <property name="id">wxID_ANY</property>
+                                                    <property name="label">Marvin Calvert</property>
+                                                    <property name="max_size"></property>
+                                                    <property name="maximize_button">0</property>
+                                                    <property name="maximum_size"></property>
+                                                    <property name="min_size"></property>
+                                                    <property name="minimize_button">0</property>
+                                                    <property name="minimum_size"></property>
+                                                    <property name="moveable">1</property>
+                                                    <property name="name">m_dMarvinCalvert</property>
+                                                    <property name="pane_border">1</property>
+                                                    <property name="pane_position"></property>
+                                                    <property name="pane_size"></property>
+                                                    <property name="permission">protected</property>
+                                                    <property name="pin_button">1</property>
+                                                    <property name="pos"></property>
+                                                    <property name="resize">Resizable</property>
+                                                    <property name="show">1</property>
+                                                    <property name="size"></property>
+                                                    <property name="style"></property>
+                                                    <property name="subclass">; forward_declare</property>
+                                                    <property name="toolbar_pane">0</property>
+                                                    <property name="tooltip"></property>
+                                                    <property name="window_extra_style"></property>
+                                                    <property name="window_name"></property>
+                                                    <property name="window_style"></property>
+                                                    <property name="wrap">-1</property>
+                                                    <event name="OnChar"></event>
+                                                    <event name="OnEnterWindow"></event>
+                                                    <event name="OnEraseBackground"></event>
+                                                    <event name="OnKeyDown"></event>
+                                                    <event name="OnKeyUp"></event>
+                                                    <event name="OnKillFocus"></event>
+                                                    <event name="OnLeaveWindow"></event>
+                                                    <event name="OnLeftDClick"></event>
+                                                    <event name="OnLeftDown"></event>
+                                                    <event name="OnLeftUp"></event>
+                                                    <event name="OnMiddleDClick"></event>
+                                                    <event name="OnMiddleDown"></event>
+                                                    <event name="OnMiddleUp"></event>
+                                                    <event name="OnMotion"></event>
+                                                    <event name="OnMouseEvents"></event>
+                                                    <event name="OnMouseWheel"></event>
+                                                    <event name="OnPaint"></event>
+                                                    <event name="OnRightDClick"></event>
+                                                    <event name="OnRightDown"></event>
+                                                    <event name="OnRightUp"></event>
+                                                    <event name="OnSetFocus"></event>
+                                                    <event name="OnSize"></event>
+                                                    <event name="OnUpdateUI"></event>
+                                                </object>
+                                            </object>
                                         </object>
                                     </object>
                                 </object>
diff --git a/src/forms/Dialog/AboutDialogBase.cpp b/src/forms/Dialog/AboutDialogBase.cpp
index 12ac933..fd26f24 100644
--- a/src/forms/Dialog/AboutDialogBase.cpp
+++ b/src/forms/Dialog/AboutDialogBase.cpp
@@ -1,8 +1,8 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Aug 23 2015)
+// C++ code generated with wxFormBuilder (version Nov  6 2017)
 // http://www.wxformbuilder.org/
 //
-// PLEASE DO "NOT" EDIT THIS FILE!
+// PLEASE DO *NOT* EDIT THIS FILE!
 ///////////////////////////////////////////////////////////////////////////
 
 #include "AboutDialogBase.h"
@@ -22,7 +22,7 @@ AboutDialogBase::AboutDialogBase( wxWindow* parent, wxWindowID id, const wxStrin
 	
 	m_appName = new wxStaticText( m_hPanel, wxID_ANY, wxT("CubicSDR"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_appName->Wrap( -1 );
-	m_appName->SetFont( wxFont( 20, 70, 90, 90, false, wxEmptyString ) );
+	m_appName->SetFont( wxFont( 20, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
 	
 	m_hSizer->Add( m_appName, 0, wxALL, 6 );
 	
@@ -45,19 +45,19 @@ AboutDialogBase::AboutDialogBase( wxWindow* parent, wxWindowID id, const wxStrin
 	
 	m_dbHeader = new wxStaticText( m_dbScroll, wxID_ANY, wxT("Developed By"), wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE );
 	m_dbHeader->Wrap( -1 );
-	m_dbHeader->SetFont( wxFont( 15, 70, 90, 90, false, wxEmptyString ) );
+	m_dbHeader->SetFont( wxFont( 15, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
 	
 	m_dbSizer->Add( m_dbHeader, 0, wxALL, 5 );
 	
 	m_dbGHHeader = new wxStaticText( m_dbScroll, wxID_ANY, wxT("GitHub"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_dbGHHeader->Wrap( -1 );
-	m_dbGHHeader->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxEmptyString ) );
+	m_dbGHHeader->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
 	
 	m_dbSizer->Add( m_dbGHHeader, 0, wxALL, 5 );
 	
 	m_dbTwitter = new wxStaticText( m_dbScroll, wxID_ANY, wxT("Twitter"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_dbTwitter->Wrap( -1 );
-	m_dbTwitter->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxEmptyString ) );
+	m_dbTwitter->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
 	
 	m_dbSizer->Add( m_dbTwitter, 0, wxALL, 5 );
 	
@@ -98,13 +98,13 @@ AboutDialogBase::AboutDialogBase( wxWindow* parent, wxWindowID id, const wxStrin
 	
 	m_cContributorsHeader = new wxStaticText( m_dbScroll, wxID_ANY, wxT("Contributors"), wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE );
 	m_cContributorsHeader->Wrap( -1 );
-	m_cContributorsHeader->SetFont( wxFont( 15, 70, 90, 90, false, wxEmptyString ) );
+	m_cContributorsHeader->SetFont( wxFont( 15, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
 	
 	m_cSizer->Add( m_cContributorsHeader, 0, wxALL, 5 );
 	
 	m_cGitHub = new wxStaticText( m_dbScroll, wxID_ANY, wxT("GitHub"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_cGitHub->Wrap( -1 );
-	m_cGitHub->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxEmptyString ) );
+	m_cGitHub->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
 	
 	m_cSizer->Add( m_cGitHub, 0, wxALL, 5 );
 	
@@ -190,7 +190,7 @@ AboutDialogBase::AboutDialogBase( wxWindow* parent, wxWindowID id, const wxStrin
 	
 	m_dHeader = new wxStaticText( m_dScroll, wxID_ANY, wxT("Thanks to everyone who donated at cubicsdr.com!"), wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE );
 	m_dHeader->Wrap( -1 );
-	m_dHeader->SetFont( wxFont( 15, 70, 90, 90, false, wxEmptyString ) );
+	m_dHeader->SetFont( wxFont( 15, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
 	
 	m_dSizer->Add( m_dHeader, 0, wxALL, 5 );
 	
@@ -365,6 +365,26 @@ AboutDialogBase::AboutDialogBase( wxWindow* parent, wxWindowID id, const wxStrin
 	m_dPetrikaJaneku->Wrap( -1 );
 	m_dSizer->Add( m_dPetrikaJaneku, 0, wxALL, 5 );
 	
+	m_dChadMyslinsky = new wxStaticText( m_dScroll, wxID_ANY, wxT("Chad Myslinsky"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_dChadMyslinsky->Wrap( -1 );
+	m_dSizer->Add( m_dChadMyslinsky, 0, wxALL, 5 );
+	
+	m_dCharlieBruckner = new wxStaticText( m_dScroll, wxID_ANY, wxT("Charlie Bruckner"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_dCharlieBruckner->Wrap( -1 );
+	m_dSizer->Add( m_dCharlieBruckner, 0, wxALL, 5 );
+	
+	m_dJordanParker = new wxStaticText( m_dScroll, wxID_ANY, wxT("Jordan Parker"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_dJordanParker->Wrap( -1 );
+	m_dSizer->Add( m_dJordanParker, 0, wxALL, 5 );
+	
+	m_dRobertChave = new wxStaticText( m_dScroll, wxID_ANY, wxT("Robert Chave"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_dRobertChave->Wrap( -1 );
+	m_dSizer->Add( m_dRobertChave, 0, wxALL, 5 );
+	
+	m_dMarvinCalvert = new wxStaticText( m_dScroll, wxID_ANY, wxT("Marvin Calvert"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_dMarvinCalvert->Wrap( -1 );
+	m_dSizer->Add( m_dMarvinCalvert, 0, wxALL, 5 );
+	
 	
 	m_dBSizer->Add( m_dSizer, 1, wxALL|wxEXPAND, 5 );
 	
@@ -383,7 +403,7 @@ AboutDialogBase::AboutDialogBase( wxWindow* parent, wxWindowID id, const wxStrin
 	
 	m_stHeader = new wxStaticText( m_stScroll, wxID_ANY, wxT("Special Thanks To"), wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE );
 	m_stHeader->Wrap( -1 );
-	m_stHeader->SetFont( wxFont( 15, 70, 90, 90, false, wxEmptyString ) );
+	m_stHeader->SetFont( wxFont( 15, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
 	
 	m_stSizer->Add( m_stHeader, 0, wxALL, 5 );
 	
@@ -392,7 +412,7 @@ AboutDialogBase::AboutDialogBase( wxWindow* parent, wxWindowID id, const wxStrin
 	
 	m_stSoapyDevAssistHeader = new wxStaticText( m_stScroll, wxID_ANY, wxT("SoapySDR Development and Assistance:"), wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE );
 	m_stSoapyDevAssistHeader->Wrap( -1 );
-	m_stSoapyDevAssistHeader->SetFont( wxFont( 10, 70, 90, 92, false, wxEmptyString ) );
+	m_stSoapyDevAssistHeader->SetFont( wxFont( 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) );
 	
 	m_stSizer->Add( m_stSoapyDevAssistHeader, 0, wxALL, 5 );
 	
@@ -405,7 +425,7 @@ AboutDialogBase::AboutDialogBase( wxWindow* parent, wxWindowID id, const wxStrin
 	
 	m_stLiquidDSPHeader = new wxStaticText( m_stScroll, wxID_ANY, wxT("Liquid-DSP Development and Assistance:"), wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE );
 	m_stLiquidDSPHeader->Wrap( -1 );
-	m_stLiquidDSPHeader->SetFont( wxFont( 10, 70, 90, 92, false, wxEmptyString ) );
+	m_stLiquidDSPHeader->SetFont( wxFont( 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) );
 	
 	m_stSizer->Add( m_stLiquidDSPHeader, 0, wxALL, 5 );
 	
@@ -418,7 +438,7 @@ AboutDialogBase::AboutDialogBase( wxWindow* parent, wxWindowID id, const wxStrin
 	
 	m_stIdeasDirectionsHeader = new wxStaticText( m_stScroll, wxID_ANY, wxT("Ideas, Direction && Encouragement:"), wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE );
 	m_stIdeasDirectionsHeader->Wrap( -1 );
-	m_stIdeasDirectionsHeader->SetFont( wxFont( 10, 70, 90, 92, false, wxEmptyString ) );
+	m_stIdeasDirectionsHeader->SetFont( wxFont( 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) );
 	
 	m_stSizer->Add( m_stIdeasDirectionsHeader, 0, wxALL, 5 );
 	
diff --git a/src/forms/Dialog/AboutDialogBase.h b/src/forms/Dialog/AboutDialogBase.h
index 6029b1b..a6b9cbd 100644
--- a/src/forms/Dialog/AboutDialogBase.h
+++ b/src/forms/Dialog/AboutDialogBase.h
@@ -1,8 +1,8 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Aug 23 2015)
+// C++ code generated with wxFormBuilder (version Nov  6 2017)
 // http://www.wxformbuilder.org/
 //
-// PLEASE DO "NOT" EDIT THIS FILE!
+// PLEASE DO *NOT* EDIT THIS FILE!
 ///////////////////////////////////////////////////////////////////////////
 
 #ifndef __ABOUTDIALOGBASE_H__
@@ -114,6 +114,11 @@ class AboutDialogBase : public wxDialog
 		wxStaticText* m_dSergeVanderTorre;
 		wxStaticText* m_dDieterSchneider;
 		wxStaticText* m_dPetrikaJaneku;
+		wxStaticText* m_dChadMyslinsky;
+		wxStaticText* m_dCharlieBruckner;
+		wxStaticText* m_dJordanParker;
+		wxStaticText* m_dRobertChave;
+		wxStaticText* m_dMarvinCalvert;
 		wxScrolledWindow* m_stScroll;
 		wxStaticText* m_stHeader;
 		wxStaticLine* m_stDivider1;
diff --git a/src/forms/Dialog/ActionDialogBase.cpp b/src/forms/Dialog/ActionDialogBase.cpp
index aaf21d3..eb61f13 100644
--- a/src/forms/Dialog/ActionDialogBase.cpp
+++ b/src/forms/Dialog/ActionDialogBase.cpp
@@ -1,53 +1,53 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Aug 23 2015)
+// C++ code generated with wxFormBuilder (version Oct 27 2017)
 // http://www.wxformbuilder.org/
 //
-// PLEASE DO "NOT" EDIT THIS FILE!
+// PLEASE DO *NOT* EDIT THIS FILE!
 ///////////////////////////////////////////////////////////////////////////
 
 #include "ActionDialogBase.h"
 
 ///////////////////////////////////////////////////////////////////////////
 
-ActionDialogBase::ActionDialogBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
+ActionDialogBase::ActionDialogBase(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style)
 {
-	this->SetSizeHints( wxDefaultSize, wxDefaultSize );
-	
+	this->SetSizeHints(wxDefaultSize, wxDefaultSize);
+
 	wxBoxSizer* mainSizer;
-	mainSizer = new wxBoxSizer( wxVERTICAL );
-	
-	m_questionText = new wxStaticText( this, wxID_ANY, wxT("Question"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE );
-	m_questionText->Wrap( -1 );
-	mainSizer->Add( m_questionText, 1, wxALL|wxEXPAND, 5 );
-	
+	mainSizer = new wxBoxSizer(wxVERTICAL);
+
+	m_questionText = new wxStaticText(this, wxID_ANY, wxT("Question"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
+	m_questionText->Wrap(-1);
+	mainSizer->Add(m_questionText, 1, wxALL | wxEXPAND, 5);
+
 	wxBoxSizer* buttonSizer;
-	buttonSizer = new wxBoxSizer( wxHORIZONTAL );
-	
-	m_cancelButton = new wxButton( this, wxID_ANY, wxT("Cancel"), wxDefaultPosition, wxDefaultSize, 0 );
-	buttonSizer->Add( m_cancelButton, 1, wxALL|wxEXPAND, 5 );
-	
-	m_okButton = new wxButton( this, wxID_ANY, wxT("OK"), wxDefaultPosition, wxDefaultSize, 0 );
-	buttonSizer->Add( m_okButton, 1, wxALL|wxEXPAND, 5 );
-	
-	
-	mainSizer->Add( buttonSizer, 1, wxEXPAND, 5 );
-	
-	
-	this->SetSizer( mainSizer );
+	buttonSizer = new wxBoxSizer(wxHORIZONTAL);
+
+	m_cancelButton = new wxButton(this, wxID_ANY, wxT("Cancel"), wxDefaultPosition, wxDefaultSize, 0);
+	buttonSizer->Add(m_cancelButton, 1, wxALL | wxEXPAND, 5);
+
+	m_okButton = new wxButton(this, wxID_ANY, wxT("OK"), wxDefaultPosition, wxDefaultSize, 0);
+	buttonSizer->Add(m_okButton, 1, wxALL | wxEXPAND, 5);
+
+
+	mainSizer->Add(buttonSizer, 1, wxEXPAND, 5);
+
+
+	this->SetSizer(mainSizer);
 	this->Layout();
-	mainSizer->Fit( this );
-	
-	this->Centre( wxBOTH );
-	
+	mainSizer->Fit(this);
+
+	this->Centre(wxBOTH);
+
 	// Connect Events
-	m_cancelButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ActionDialogBase::onClickCancel ), NULL, this );
-	m_okButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ActionDialogBase::onClickOK ), NULL, this );
+	m_cancelButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ActionDialogBase::onClickCancel), NULL, this);
+	m_okButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ActionDialogBase::onClickOK), NULL, this);
 }
 
 ActionDialogBase::~ActionDialogBase()
 {
 	// Disconnect Events
-	m_cancelButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ActionDialogBase::onClickCancel ), NULL, this );
-	m_okButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ActionDialogBase::onClickOK ), NULL, this );
-	
+	m_cancelButton->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ActionDialogBase::onClickCancel), NULL, this);
+	m_okButton->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ActionDialogBase::onClickOK), NULL, this);
+
 }
diff --git a/src/forms/Dialog/ActionDialogBase.h b/src/forms/Dialog/ActionDialogBase.h
index 72b0b85..b3f3a86 100644
--- a/src/forms/Dialog/ActionDialogBase.h
+++ b/src/forms/Dialog/ActionDialogBase.h
@@ -1,8 +1,8 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Aug 23 2015)
+// C++ code generated with wxFormBuilder (version Oct 27 2017)
 // http://www.wxformbuilder.org/
 //
-// PLEASE DO "NOT" EDIT THIS FILE!
+// PLEASE DO *NOT* EDIT THIS FILE!
 ///////////////////////////////////////////////////////////////////////////
 
 #ifndef __ACTIONDIALOGBASE_H__
@@ -26,25 +26,25 @@
 ///////////////////////////////////////////////////////////////////////////////
 /// Class ActionDialogBase
 ///////////////////////////////////////////////////////////////////////////////
-class ActionDialogBase : public wxDialog 
+class ActionDialogBase : public wxDialog
 {
-	private:
-	
-	protected:
-		wxStaticText* m_questionText;
-		wxButton* m_cancelButton;
-		wxButton* m_okButton;
-		
-		// Virtual event handlers, overide them in your derived class
-		virtual void onClickCancel( wxCommandEvent& event ) { event.Skip(); }
-		virtual void onClickOK( wxCommandEvent& event ) { event.Skip(); }
-		
-	
-	public:
-		
-		ActionDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("QuestionTitle"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE ); 
-		~ActionDialogBase();
-	
+private:
+
+protected:
+	wxStaticText* m_questionText;
+	wxButton* m_cancelButton;
+	wxButton* m_okButton;
+
+	// Virtual event handlers, overide them in your derived class
+	virtual void onClickCancel(wxCommandEvent& event) { event.Skip(); }
+	virtual void onClickOK(wxCommandEvent& event) { event.Skip(); }
+
+
+public:
+
+	ActionDialogBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("QuestionTitle"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE);
+	~ActionDialogBase();
+
 };
 
 #endif //__ACTIONDIALOGBASE_H__
diff --git a/src/forms/Dialog/PortSelectorDialogBase.cpp b/src/forms/Dialog/PortSelectorDialogBase.cpp
index a8d5bf2..ea4e561 100644
--- a/src/forms/Dialog/PortSelectorDialogBase.cpp
+++ b/src/forms/Dialog/PortSelectorDialogBase.cpp
@@ -1,78 +1,78 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Aug 23 2015)
+// C++ code generated with wxFormBuilder (version Oct 27 2017)
 // http://www.wxformbuilder.org/
 //
-// PLEASE DO "NOT" EDIT THIS FILE!
+// PLEASE DO *NOT* EDIT THIS FILE!
 ///////////////////////////////////////////////////////////////////////////
 
 #include "PortSelectorDialogBase.h"
 
 ///////////////////////////////////////////////////////////////////////////
 
-PortSelectorDialogBase::PortSelectorDialogBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
+PortSelectorDialogBase::PortSelectorDialogBase(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style)
 {
-	this->SetSizeHints( wxDefaultSize, wxDefaultSize );
-	
+	this->SetSizeHints(wxDefaultSize, wxDefaultSize);
+
 	wxBoxSizer* dlgSizer;
-	dlgSizer = new wxBoxSizer( wxVERTICAL );
-	
-	m_staticText1 = new wxStaticText( this, wxID_ANY, wxT("Select a detected port or enter your own"), wxDefaultPosition, wxDefaultSize, 0 );
-	m_staticText1->Wrap( -1 );
-	dlgSizer->Add( m_staticText1, 0, wxEXPAND|wxALL, 5 );
-	
-	m_portList = new wxListBox( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); 
-	dlgSizer->Add( m_portList, 1, wxALL|wxEXPAND, 5 );
-	
+	dlgSizer = new wxBoxSizer(wxVERTICAL);
+
+	m_staticText1 = new wxStaticText(this, wxID_ANY, wxT("Select a detected port or enter your own"), wxDefaultPosition, wxDefaultSize, 0);
+	m_staticText1->Wrap(-1);
+	dlgSizer->Add(m_staticText1, 0, wxEXPAND | wxALL, 5);
+
+	m_portList = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, 0);
+	dlgSizer->Add(m_portList, 1, wxALL | wxEXPAND, 5);
+
 	wxBoxSizer* bSizer3;
-	bSizer3 = new wxBoxSizer( wxHORIZONTAL );
-	
-	bSizer3->SetMinSize( wxSize( -1,30 ) ); 
-	m_staticText2 = new wxStaticText( this, wxID_ANY, wxT("Port"), wxDefaultPosition, wxDefaultSize, 0 );
-	m_staticText2->Wrap( -1 );
-	bSizer3->Add( m_staticText2, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
-	
-	m_portSelection = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	bSizer3->Add( m_portSelection, 1, wxEXPAND|wxRIGHT, 5 );
-	
-	
-	dlgSizer->Add( bSizer3, 1, wxEXPAND, 5 );
-	
-	m_buttonPanel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+	bSizer3 = new wxBoxSizer(wxHORIZONTAL);
+
+	bSizer3->SetMinSize(wxSize(-1, 30));
+	m_staticText2 = new wxStaticText(this, wxID_ANY, wxT("Port"), wxDefaultPosition, wxDefaultSize, 0);
+	m_staticText2->Wrap(-1);
+	bSizer3->Add(m_staticText2, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
+
+	m_portSelection = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0);
+	bSizer3->Add(m_portSelection, 1, wxEXPAND | wxRIGHT, 5);
+
+
+	dlgSizer->Add(bSizer3, 1, wxEXPAND, 5);
+
+	m_buttonPanel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
 	wxBoxSizer* bSizer2;
-	bSizer2 = new wxBoxSizer( wxHORIZONTAL );
-	
-	m_cancelButton = new wxButton( m_buttonPanel, wxID_ANY, wxT("Cancel"), wxDefaultPosition, wxDefaultSize, 0 );
-	bSizer2->Add( m_cancelButton, 0, wxALL|wxALIGN_BOTTOM, 5 );
-	
-	
-	bSizer2->Add( 0, 0, 1, wxEXPAND, 5 );
-	
-	m_okButton = new wxButton( m_buttonPanel, wxID_ANY, wxT("OK"), wxDefaultPosition, wxDefaultSize, 0 );
-	bSizer2->Add( m_okButton, 0, wxALL|wxALIGN_BOTTOM, 5 );
-	
-	
-	m_buttonPanel->SetSizer( bSizer2 );
+	bSizer2 = new wxBoxSizer(wxHORIZONTAL);
+
+	m_cancelButton = new wxButton(m_buttonPanel, wxID_ANY, wxT("Cancel"), wxDefaultPosition, wxDefaultSize, 0);
+	bSizer2->Add(m_cancelButton, 0, wxALL | wxALIGN_BOTTOM, 5);
+
+
+	bSizer2->Add(0, 0, 1, wxEXPAND, 5);
+
+	m_okButton = new wxButton(m_buttonPanel, wxID_ANY, wxT("OK"), wxDefaultPosition, wxDefaultSize, 0);
+	bSizer2->Add(m_okButton, 0, wxALL | wxALIGN_BOTTOM, 5);
+
+
+	m_buttonPanel->SetSizer(bSizer2);
 	m_buttonPanel->Layout();
-	bSizer2->Fit( m_buttonPanel );
-	dlgSizer->Add( m_buttonPanel, 0, wxEXPAND | wxALL, 5 );
-	
-	
-	this->SetSizer( dlgSizer );
+	bSizer2->Fit(m_buttonPanel);
+	dlgSizer->Add(m_buttonPanel, 0, wxEXPAND | wxALL, 5);
+
+
+	this->SetSizer(dlgSizer);
 	this->Layout();
-	
-	this->Centre( wxBOTH );
-	
+
+	this->Centre(wxBOTH);
+
 	// Connect Events
-	m_portList->Connect( wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler( PortSelectorDialogBase::onListSelect ), NULL, this );
-	m_cancelButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PortSelectorDialogBase::onCancelButton ), NULL, this );
-	m_okButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PortSelectorDialogBase::onOKButton ), NULL, this );
+	m_portList->Connect(wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler(PortSelectorDialogBase::onListSelect), NULL, this);
+	m_cancelButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(PortSelectorDialogBase::onCancelButton), NULL, this);
+	m_okButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(PortSelectorDialogBase::onOKButton), NULL, this);
 }
 
 PortSelectorDialogBase::~PortSelectorDialogBase()
 {
 	// Disconnect Events
-	m_portList->Disconnect( wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler( PortSelectorDialogBase::onListSelect ), NULL, this );
-	m_cancelButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PortSelectorDialogBase::onCancelButton ), NULL, this );
-	m_okButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PortSelectorDialogBase::onOKButton ), NULL, this );
-	
+	m_portList->Disconnect(wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler(PortSelectorDialogBase::onListSelect), NULL, this);
+	m_cancelButton->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(PortSelectorDialogBase::onCancelButton), NULL, this);
+	m_okButton->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(PortSelectorDialogBase::onOKButton), NULL, this);
+
 }
diff --git a/src/forms/Dialog/PortSelectorDialogBase.h b/src/forms/Dialog/PortSelectorDialogBase.h
index 8e8c2af..50db428 100644
--- a/src/forms/Dialog/PortSelectorDialogBase.h
+++ b/src/forms/Dialog/PortSelectorDialogBase.h
@@ -1,8 +1,8 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Aug 23 2015)
+// C++ code generated with wxFormBuilder (version Oct 27 2017)
 // http://www.wxformbuilder.org/
 //
-// PLEASE DO "NOT" EDIT THIS FILE!
+// PLEASE DO *NOT* EDIT THIS FILE!
 ///////////////////////////////////////////////////////////////////////////
 
 #ifndef __PORTSELECTORDIALOGBASE_H__
@@ -29,30 +29,30 @@
 ///////////////////////////////////////////////////////////////////////////////
 /// Class PortSelectorDialogBase
 ///////////////////////////////////////////////////////////////////////////////
-class PortSelectorDialogBase : public wxDialog 
+class PortSelectorDialogBase : public wxDialog
 {
-	private:
-	
-	protected:
-		wxStaticText* m_staticText1;
-		wxListBox* m_portList;
-		wxStaticText* m_staticText2;
-		wxTextCtrl* m_portSelection;
-		wxPanel* m_buttonPanel;
-		wxButton* m_cancelButton;
-		wxButton* m_okButton;
-		
-		// Virtual event handlers, overide them in your derived class
-		virtual void onListSelect( wxCommandEvent& event ) { event.Skip(); }
-		virtual void onCancelButton( wxCommandEvent& event ) { event.Skip(); }
-		virtual void onOKButton( wxCommandEvent& event ) { event.Skip(); }
-		
-	
-	public:
-		
-		PortSelectorDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Select Port"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 304,197 ), long style = wxDEFAULT_DIALOG_STYLE ); 
-		~PortSelectorDialogBase();
-	
+private:
+
+protected:
+	wxStaticText* m_staticText1;
+	wxListBox* m_portList;
+	wxStaticText* m_staticText2;
+	wxTextCtrl* m_portSelection;
+	wxPanel* m_buttonPanel;
+	wxButton* m_cancelButton;
+	wxButton* m_okButton;
+
+	// Virtual event handlers, overide them in your derived class
+	virtual void onListSelect(wxCommandEvent& event) { event.Skip(); }
+	virtual void onCancelButton(wxCommandEvent& event) { event.Skip(); }
+	virtual void onOKButton(wxCommandEvent& event) { event.Skip(); }
+
+
+public:
+
+	PortSelectorDialogBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Select Port"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(304, 197), long style = wxDEFAULT_DIALOG_STYLE);
+	~PortSelectorDialogBase();
+
 };
 
 #endif //__PORTSELECTORDIALOGBASE_H__
diff --git a/src/forms/DigitalConsole/DigitalConsoleFrame.cpp b/src/forms/DigitalConsole/DigitalConsoleFrame.cpp
index b1e4885..16324db 100644
--- a/src/forms/DigitalConsole/DigitalConsoleFrame.cpp
+++ b/src/forms/DigitalConsole/DigitalConsoleFrame.cpp
@@ -1,73 +1,73 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Aug 23 2015)
+// C++ code generated with wxFormBuilder (version Oct 27 2017)
 // http://www.wxformbuilder.org/
 //
-// PLEASE DO "NOT" EDIT THIS FILE!
+// PLEASE DO *NOT* EDIT THIS FILE!
 ///////////////////////////////////////////////////////////////////////////
 
 #include "DigitalConsoleFrame.h"
 
 ///////////////////////////////////////////////////////////////////////////
 
-DigitalConsoleFrame::DigitalConsoleFrame( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style )
+DigitalConsoleFrame::DigitalConsoleFrame(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxFrame(parent, id, title, pos, size, style)
 {
-	this->SetSizeHints( wxDefaultSize, wxDefaultSize );
-	this->SetExtraStyle( wxWS_EX_PROCESS_UI_UPDATES );
-	
+	this->SetSizeHints(wxDefaultSize, wxDefaultSize);
+	this->SetExtraStyle(wxWS_EX_PROCESS_UI_UPDATES);
+
 	wxBoxSizer* mainSizer;
-	mainSizer = new wxBoxSizer( wxVERTICAL );
-	
+	mainSizer = new wxBoxSizer(wxVERTICAL);
+
 	wxBoxSizer* dataViewSizer;
-	dataViewSizer = new wxBoxSizer( wxVERTICAL );
-	
-	m_dataView = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_CHARWRAP|wxTE_MULTILINE|wxTE_NOHIDESEL|wxTE_READONLY|wxTE_WORDWRAP|wxALWAYS_SHOW_SB|wxFULL_REPAINT_ON_RESIZE|wxNO_BORDER|wxSIMPLE_BORDER|wxVSCROLL );
-	m_dataView->SetExtraStyle( wxWS_EX_PROCESS_UI_UPDATES );
-	m_dataView->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 76, 90, 90, false, wxEmptyString ) );
-	
-	dataViewSizer->Add( m_dataView, 1, wxEXPAND, 5 );
-	
-	
-	mainSizer->Add( dataViewSizer, 1, wxEXPAND, 5 );
-	
+	dataViewSizer = new wxBoxSizer(wxVERTICAL);
+
+	m_dataView = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_CHARWRAP | wxTE_MULTILINE | wxTE_NOHIDESEL | wxTE_READONLY | wxTE_WORDWRAP | wxALWAYS_SHOW_SB | wxFULL_REPAINT_ON_RESIZE | wxNO_BORDER | wxSIMPLE_BORDER | wxVSCROLL);
+	m_dataView->SetExtraStyle(wxWS_EX_PROCESS_UI_UPDATES);
+	m_dataView->SetFont(wxFont(wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString));
+
+	dataViewSizer->Add(m_dataView, 1, wxEXPAND, 5);
+
+
+	mainSizer->Add(dataViewSizer, 1, wxEXPAND, 5);
+
 	wxBoxSizer* buttonSizer;
-	buttonSizer = new wxBoxSizer( wxHORIZONTAL );
-	
-	m_clearButton = new wxButton( this, wxID_ANY, wxT("Clear"), wxDefaultPosition, wxDefaultSize, 0 );
-	buttonSizer->Add( m_clearButton, 1, wxEXPAND, 5 );
-	
-	m_copyButton = new wxButton( this, wxID_ANY, wxT("Copy"), wxDefaultPosition, wxDefaultSize, 0 );
-	buttonSizer->Add( m_copyButton, 1, wxEXPAND, 5 );
-	
-	m_pauseButton = new wxButton( this, wxID_ANY, wxT("Stop"), wxDefaultPosition, wxDefaultSize, 0 );
-	buttonSizer->Add( m_pauseButton, 1, wxEXPAND, 5 );
-	
-	
-	mainSizer->Add( buttonSizer, 0, wxALL|wxEXPAND, 5 );
-	
-	
-	this->SetSizer( mainSizer );
+	buttonSizer = new wxBoxSizer(wxHORIZONTAL);
+
+	m_clearButton = new wxButton(this, wxID_ANY, wxT("Clear"), wxDefaultPosition, wxDefaultSize, 0);
+	buttonSizer->Add(m_clearButton, 1, wxEXPAND, 5);
+
+	m_copyButton = new wxButton(this, wxID_ANY, wxT("Copy"), wxDefaultPosition, wxDefaultSize, 0);
+	buttonSizer->Add(m_copyButton, 1, wxEXPAND, 5);
+
+	m_pauseButton = new wxButton(this, wxID_ANY, wxT("Stop"), wxDefaultPosition, wxDefaultSize, 0);
+	buttonSizer->Add(m_pauseButton, 1, wxEXPAND, 5);
+
+
+	mainSizer->Add(buttonSizer, 0, wxALL | wxEXPAND, 5);
+
+
+	this->SetSizer(mainSizer);
 	this->Layout();
-	m_refreshTimer.SetOwner( this, wxID_ANY );
-	m_refreshTimer.Start( 250 );
-	
-	
-	this->Centre( wxBOTH );
-	
+	m_refreshTimer.SetOwner(this, wxID_ANY);
+	m_refreshTimer.Start(250);
+
+
+	this->Centre(wxBOTH);
+
 	// Connect Events
-	this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DigitalConsoleFrame::OnClose ) );
-	m_clearButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DigitalConsoleFrame::OnClear ), NULL, this );
-	m_copyButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DigitalConsoleFrame::OnCopy ), NULL, this );
-	m_pauseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DigitalConsoleFrame::OnPause ), NULL, this );
-	this->Connect( wxID_ANY, wxEVT_TIMER, wxTimerEventHandler( DigitalConsoleFrame::DoRefresh ) );
+	this->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(DigitalConsoleFrame::OnClose));
+	m_clearButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(DigitalConsoleFrame::OnClear), NULL, this);
+	m_copyButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(DigitalConsoleFrame::OnCopy), NULL, this);
+	m_pauseButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(DigitalConsoleFrame::OnPause), NULL, this);
+	this->Connect(wxID_ANY, wxEVT_TIMER, wxTimerEventHandler(DigitalConsoleFrame::DoRefresh));
 }
 
 DigitalConsoleFrame::~DigitalConsoleFrame()
 {
 	// Disconnect Events
-	this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DigitalConsoleFrame::OnClose ) );
-	m_clearButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DigitalConsoleFrame::OnClear ), NULL, this );
-	m_copyButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DigitalConsoleFrame::OnCopy ), NULL, this );
-	m_pauseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DigitalConsoleFrame::OnPause ), NULL, this );
-	this->Disconnect( wxID_ANY, wxEVT_TIMER, wxTimerEventHandler( DigitalConsoleFrame::DoRefresh ) );
-	
+	this->Disconnect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(DigitalConsoleFrame::OnClose));
+	m_clearButton->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(DigitalConsoleFrame::OnClear), NULL, this);
+	m_copyButton->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(DigitalConsoleFrame::OnCopy), NULL, this);
+	m_pauseButton->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(DigitalConsoleFrame::OnPause), NULL, this);
+	this->Disconnect(wxID_ANY, wxEVT_TIMER, wxTimerEventHandler(DigitalConsoleFrame::DoRefresh));
+
 }
diff --git a/src/forms/DigitalConsole/DigitalConsoleFrame.h b/src/forms/DigitalConsole/DigitalConsoleFrame.h
index 6665b66..76d7b9e 100644
--- a/src/forms/DigitalConsole/DigitalConsoleFrame.h
+++ b/src/forms/DigitalConsole/DigitalConsoleFrame.h
@@ -1,8 +1,8 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Aug 23 2015)
+// C++ code generated with wxFormBuilder (version Oct 27 2017)
 // http://www.wxformbuilder.org/
 //
-// PLEASE DO "NOT" EDIT THIS FILE!
+// PLEASE DO *NOT* EDIT THIS FILE!
 ///////////////////////////////////////////////////////////////////////////
 
 #ifndef __DIGITALCONSOLEFRAME_H__
@@ -27,31 +27,31 @@
 ///////////////////////////////////////////////////////////////////////////////
 /// Class DigitalConsoleFrame
 ///////////////////////////////////////////////////////////////////////////////
-class DigitalConsoleFrame : public wxFrame 
+class DigitalConsoleFrame : public wxFrame
 {
-	private:
-	
-	protected:
-		wxTextCtrl* m_dataView;
-		wxButton* m_clearButton;
-		wxButton* m_copyButton;
-		wxButton* m_pauseButton;
-		wxTimer m_refreshTimer;
-		
-		// Virtual event handlers, overide them in your derived class
-		virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
-		virtual void OnClear( wxCommandEvent& event ) { event.Skip(); }
-		virtual void OnCopy( wxCommandEvent& event ) { event.Skip(); }
-		virtual void OnPause( wxCommandEvent& event ) { event.Skip(); }
-		virtual void DoRefresh( wxTimerEvent& event ) { event.Skip(); }
-		
-	
-	public:
-		
-		DigitalConsoleFrame( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Digital Output"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 441,394 ), long style = wxCAPTION|wxFRAME_FLOAT_ON_PARENT|wxMAXIMIZE|wxMAXIMIZE_BOX|wxMINIMIZE|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxFULL_REPAINT_ON_RESIZE|wxTAB_TRAVERSAL );
-		
-		~DigitalConsoleFrame();
-	
+private:
+
+protected:
+	wxTextCtrl* m_dataView;
+	wxButton* m_clearButton;
+	wxButton* m_copyButton;
+	wxButton* m_pauseButton;
+	wxTimer m_refreshTimer;
+
+	// Virtual event handlers, overide them in your derived class
+	virtual void OnClose(wxCloseEvent& event) { event.Skip(); }
+	virtual void OnClear(wxCommandEvent& event) { event.Skip(); }
+	virtual void OnCopy(wxCommandEvent& event) { event.Skip(); }
+	virtual void OnPause(wxCommandEvent& event) { event.Skip(); }
+	virtual void DoRefresh(wxTimerEvent& event) { event.Skip(); }
+
+
+public:
+
+	DigitalConsoleFrame(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Digital Output"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(441, 394), long style = wxCAPTION | wxFRAME_FLOAT_ON_PARENT | wxMAXIMIZE | wxMAXIMIZE_BOX | wxMINIMIZE | wxMINIMIZE_BOX | wxRESIZE_BORDER | wxFULL_REPAINT_ON_RESIZE | wxTAB_TRAVERSAL);
+
+	~DigitalConsoleFrame();
+
 };
 
 #endif //__DIGITALCONSOLEFRAME_H__
diff --git a/src/forms/SDRDevices/SDRDeviceAddForm.cpp b/src/forms/SDRDevices/SDRDeviceAddForm.cpp
index 09afe15..d305a10 100644
--- a/src/forms/SDRDevices/SDRDeviceAddForm.cpp
+++ b/src/forms/SDRDevices/SDRDeviceAddForm.cpp
@@ -1,83 +1,83 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Aug 23 2015)
+// C++ code generated with wxFormBuilder (version Oct 27 2017)
 // http://www.wxformbuilder.org/
 //
-// PLEASE DO "NOT" EDIT THIS FILE!
+// PLEASE DO *NOT* EDIT THIS FILE!
 ///////////////////////////////////////////////////////////////////////////
 
 #include "SDRDeviceAddForm.h"
 
 ///////////////////////////////////////////////////////////////////////////
 
-SDRDeviceAddForm::SDRDeviceAddForm( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
+SDRDeviceAddForm::SDRDeviceAddForm(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style)
 {
-	this->SetSizeHints( wxDefaultSize, wxDefaultSize );
-	
+	this->SetSizeHints(wxDefaultSize, wxDefaultSize);
+
 	wxBoxSizer* bSizer6;
-	bSizer6 = new wxBoxSizer( wxVERTICAL );
-	
-	m_staticText4 = new wxStaticText( this, wxID_ANY, wxT("Manually add a SoapyRemote or SoapySDR device.  \n\nUseful for a device that is not detected automatically."), wxDefaultPosition, wxDefaultSize, 0 );
-	m_staticText4->Wrap( -1 );
-	bSizer6->Add( m_staticText4, 0, wxALL, 8 );
-	
-	
-	bSizer6->Add( 0, 0, 1, wxEXPAND, 5 );
-	
+	bSizer6 = new wxBoxSizer(wxVERTICAL);
+
+	m_staticText4 = new wxStaticText(this, wxID_ANY, wxT("Manually add a SoapyRemote or SoapySDR device.  \n\nUseful for a device that is not detected automatically."), wxDefaultPosition, wxDefaultSize, 0);
+	m_staticText4->Wrap(-1);
+	bSizer6->Add(m_staticText4, 0, wxALL, 8);
+
+
+	bSizer6->Add(0, 0, 1, wxEXPAND, 5);
+
 	wxArrayString m_soapyModuleChoices;
-	m_soapyModule = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_soapyModuleChoices, 0 );
-	m_soapyModule->SetSelection( 0 );
-	bSizer6->Add( m_soapyModule, 0, wxALL, 8 );
-	
-	
-	bSizer6->Add( 0, 0, 1, wxEXPAND, 5 );
-	
-	m_paramLabel = new wxStaticText( this, wxID_ANY, wxT("<Parameter>"), wxDefaultPosition, wxDefaultSize, 0 );
-	m_paramLabel->Wrap( -1 );
-	bSizer6->Add( m_paramLabel, 0, wxALL, 8 );
-	
-	m_paramText = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_DONTWRAP|wxHSCROLL );
-	m_paramText->SetMinSize( wxSize( -1,48 ) );
-	
-	bSizer6->Add( m_paramText, 1, wxALL|wxEXPAND, 8 );
-	
-	
-	bSizer6->Add( 0, 0, 1, wxEXPAND, 5 );
-	
+	m_soapyModule = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_soapyModuleChoices, 0);
+	m_soapyModule->SetSelection(0);
+	bSizer6->Add(m_soapyModule, 0, wxALL, 8);
+
+
+	bSizer6->Add(0, 0, 1, wxEXPAND, 5);
+
+	m_paramLabel = new wxStaticText(this, wxID_ANY, wxT("<Parameter>"), wxDefaultPosition, wxDefaultSize, 0);
+	m_paramLabel->Wrap(-1);
+	bSizer6->Add(m_paramLabel, 0, wxALL, 8);
+
+	m_paramText = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_DONTWRAP | wxHSCROLL);
+	m_paramText->SetMinSize(wxSize(-1, 48));
+
+	bSizer6->Add(m_paramText, 1, wxALL | wxEXPAND, 8);
+
+
+	bSizer6->Add(0, 0, 1, wxEXPAND, 5);
+
 	wxBoxSizer* bSizer7;
-	bSizer7 = new wxBoxSizer( wxHORIZONTAL );
-	
-	
-	bSizer7->Add( 0, 0, 1, wxEXPAND, 5 );
-	
-	m_cancelButton = new wxButton( this, wxID_ANY, wxT("Cancel"), wxDefaultPosition, wxDefaultSize, 0 );
-	bSizer7->Add( m_cancelButton, 0, wxALL, 2 );
-	
-	m_OkButton = new wxButton( this, wxID_ANY, wxT("Ok"), wxDefaultPosition, wxDefaultSize, 0 );
-	bSizer7->Add( m_OkButton, 0, wxALL, 2 );
-	
-	
-	bSizer6->Add( bSizer7, 1, wxEXPAND, 8 );
-	
-	
-	bSizer6->Add( 0, 0, 1, wxEXPAND, 5 );
-	
-	
-	this->SetSizer( bSizer6 );
+	bSizer7 = new wxBoxSizer(wxHORIZONTAL);
+
+
+	bSizer7->Add(0, 0, 1, wxEXPAND, 5);
+
+	m_cancelButton = new wxButton(this, wxID_ANY, wxT("Cancel"), wxDefaultPosition, wxDefaultSize, 0);
+	bSizer7->Add(m_cancelButton, 0, wxALL, 2);
+
+	m_OkButton = new wxButton(this, wxID_ANY, wxT("Ok"), wxDefaultPosition, wxDefaultSize, 0);
+	bSizer7->Add(m_OkButton, 0, wxALL, 2);
+
+
+	bSizer6->Add(bSizer7, 1, wxEXPAND, 8);
+
+
+	bSizer6->Add(0, 0, 1, wxEXPAND, 5);
+
+
+	this->SetSizer(bSizer6);
 	this->Layout();
-	
-	this->Centre( wxBOTH );
-	
+
+	this->Centre(wxBOTH);
+
 	// Connect Events
-	m_soapyModule->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( SDRDeviceAddForm::OnSoapyModuleChanged ), NULL, this );
-	m_cancelButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SDRDeviceAddForm::OnCancelButton ), NULL, this );
-	m_OkButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SDRDeviceAddForm::OnOkButton ), NULL, this );
+	m_soapyModule->Connect(wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler(SDRDeviceAddForm::OnSoapyModuleChanged), NULL, this);
+	m_cancelButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(SDRDeviceAddForm::OnCancelButton), NULL, this);
+	m_OkButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(SDRDeviceAddForm::OnOkButton), NULL, this);
 }
 
 SDRDeviceAddForm::~SDRDeviceAddForm()
 {
 	// Disconnect Events
-	m_soapyModule->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( SDRDeviceAddForm::OnSoapyModuleChanged ), NULL, this );
-	m_cancelButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SDRDeviceAddForm::OnCancelButton ), NULL, this );
-	m_OkButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SDRDeviceAddForm::OnOkButton ), NULL, this );
-	
+	m_soapyModule->Disconnect(wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler(SDRDeviceAddForm::OnSoapyModuleChanged), NULL, this);
+	m_cancelButton->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(SDRDeviceAddForm::OnCancelButton), NULL, this);
+	m_OkButton->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(SDRDeviceAddForm::OnOkButton), NULL, this);
+
 }
diff --git a/src/forms/SDRDevices/SDRDeviceAddForm.h b/src/forms/SDRDevices/SDRDeviceAddForm.h
index 58ffa20..3f60877 100644
--- a/src/forms/SDRDevices/SDRDeviceAddForm.h
+++ b/src/forms/SDRDevices/SDRDeviceAddForm.h
@@ -1,8 +1,8 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Aug 23 2015)
+// C++ code generated with wxFormBuilder (version Oct 27 2017)
 // http://www.wxformbuilder.org/
 //
-// PLEASE DO "NOT" EDIT THIS FILE!
+// PLEASE DO *NOT* EDIT THIS FILE!
 ///////////////////////////////////////////////////////////////////////////
 
 #ifndef __SDRDEVICEADDFORM_H__
@@ -28,29 +28,29 @@
 ///////////////////////////////////////////////////////////////////////////////
 /// Class SDRDeviceAddForm
 ///////////////////////////////////////////////////////////////////////////////
-class SDRDeviceAddForm : public wxDialog 
+class SDRDeviceAddForm : public wxDialog
 {
-	private:
-	
-	protected:
-		wxStaticText* m_staticText4;
-		wxChoice* m_soapyModule;
-		wxStaticText* m_paramLabel;
-		wxTextCtrl* m_paramText;
-		wxButton* m_cancelButton;
-		wxButton* m_OkButton;
-		
-		// Virtual event handlers, overide them in your derived class
-		virtual void OnSoapyModuleChanged( wxCommandEvent& event ) { event.Skip(); }
-		virtual void OnCancelButton( wxCommandEvent& event ) { event.Skip(); }
-		virtual void OnOkButton( wxCommandEvent& event ) { event.Skip(); }
-		
-	
-	public:
-		
-		SDRDeviceAddForm( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Add SoapySDR Device"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 395,293 ), long style = wxDEFAULT_DIALOG_STYLE ); 
-		~SDRDeviceAddForm();
-	
+private:
+
+protected:
+	wxStaticText* m_staticText4;
+	wxChoice* m_soapyModule;
+	wxStaticText* m_paramLabel;
+	wxTextCtrl* m_paramText;
+	wxButton* m_cancelButton;
+	wxButton* m_OkButton;
+
+	// Virtual event handlers, overide them in your derived class
+	virtual void OnSoapyModuleChanged(wxCommandEvent& event) { event.Skip(); }
+	virtual void OnCancelButton(wxCommandEvent& event) { event.Skip(); }
+	virtual void OnOkButton(wxCommandEvent& event) { event.Skip(); }
+
+
+public:
+
+	SDRDeviceAddForm(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Add SoapySDR Device"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(395, 293), long style = wxDEFAULT_DIALOG_STYLE);
+	~SDRDeviceAddForm();
+
 };
 
 #endif //__SDRDEVICEADDFORM_H__
diff --git a/src/forms/SDRDevices/SDRDevices.cpp b/src/forms/SDRDevices/SDRDevices.cpp
index e0bd51e..b5ae9e5 100644
--- a/src/forms/SDRDevices/SDRDevices.cpp
+++ b/src/forms/SDRDevices/SDRDevices.cpp
@@ -8,6 +8,8 @@
 
 #include "CubicSDR.h"
 
+#include <algorithm>
+
 #ifdef __linux__
 #include "CubicSDR.xpm"
 #endif
@@ -110,6 +112,7 @@ wxPGProperty *SDRDevicesDialog::addArgInfoProperty(wxPropertyGrid *pg, SoapySDR:
 }
 
 void SDRDevicesDialog::refreshDeviceProperties() {
+
     SDRDeviceInfo *selDev = getSelectedDevice(devTree->GetSelection());
     if (selDev && selDev->isAvailable()) {
         dev = selDev;
@@ -119,14 +122,62 @@ void SDRDevicesDialog::refreshDeviceProperties() {
         
         SoapySDR::Device *soapyDev = dev->getSoapyDevice();
         SoapySDR::ArgInfoList args = soapyDev->getSettingInfo();
-        SoapySDR::ArgInfoList::const_iterator args_i;
         
+        //A) General settings: name, offset, sample rate, agc, antennas (if > 1) 
         m_propertyGrid->Append(new wxPropertyCategory("General Settings"));
         
-        devSettings.erase(devSettings.begin(),devSettings.end());
+        devSettings.clear();
+
+        //A-1) Name
         devSettings["name"] = m_propertyGrid->Append( new wxStringProperty("Name", wxPG_LABEL, devConfig->getDeviceName()) );
-        devSettings["offset"] = m_propertyGrid->Append( new wxIntProperty("Offset (Hz)", wxPG_LABEL, devConfig->getOffset()) );
+        //A-2) Offset
+        devSettings["offset"] = m_propertyGrid->Append( new wxIntProperty("Offset (KHz)", wxPG_LABEL, devConfig->getOffset() / 1000) );
         
+        //A-3) Antennas, is there are more than 1 RX antenna, else do not expose the setting.
+        //get the saved setting
+        const std::string& currentSetAntenna = devConfig->getAntennaName();
+
+        //compare to the list of existing antennas
+        SoapySDR::ArgInfo antennasArg;
+        std::vector<std::string> antennaOpts = selDev->getAntennaNames(SOAPY_SDR_RX, 0);
+
+        //only do something if there is more than 1 antenna
+        if (antennaOpts.size() > 1) {
+
+            //by default, choose the first of the list.
+            std::string antennaToSelect = antennaOpts.front();
+
+            auto found_i = std::find(antennaOpts.begin(), antennaOpts.end(), currentSetAntenna);
+
+            if (found_i != antennaOpts.end()) {
+                antennaToSelect = currentSetAntenna;
+            }
+            else {
+                //erroneous antenna name, re-write device config with the first choice of teh list.
+                devConfig->setAntennaName(antennaToSelect);
+            }
+
+            //build device settings
+            for (std::string antenna : antennaOpts) {
+                antennasArg.options.push_back(antenna);
+                antennasArg.optionNames.push_back(antenna);
+            }
+
+            antennasArg.type = SoapySDR::ArgInfo::STRING;
+            antennasArg.units = "";
+            antennasArg.name = "Antenna";
+            antennasArg.key = "antenna";
+            antennasArg.value = antennaToSelect;
+
+            devSettings["antenna"] = addArgInfoProperty(m_propertyGrid, antennasArg);
+            deviceArgs["antenna"] = antennasArg;
+
+        } //end if more than 1 antenna
+        else {
+            devConfig->setAntennaName("");
+        }
+
+        //A-4) Sample_rate:
         long currentSampleRate = wxGetApp().getSampleRate();
         long deviceSampleRate = devConfig->getSampleRate();
         
@@ -137,9 +188,9 @@ void SDRDevicesDialog::refreshDeviceProperties() {
         SoapySDR::ArgInfo sampleRateArg;
         std::vector<long> rateOpts = selDev->getSampleRates(SOAPY_SDR_RX, 0);
 
-        for (std::vector<long>::iterator rate_i = rateOpts.begin(); rate_i != rateOpts.end(); rate_i++) {
-            sampleRateArg.options.push_back(std::to_string(*rate_i));
-            sampleRateArg.optionNames.push_back(frequencyToStr(*rate_i));
+        for (long rate : rateOpts) {
+            sampleRateArg.options.push_back(std::to_string(rate));
+            sampleRateArg.optionNames.push_back(frequencyToStr(rate));
         }
         
         sampleRateArg.type = SoapySDR::ArgInfo::STRING;
@@ -150,17 +201,30 @@ void SDRDevicesDialog::refreshDeviceProperties() {
         
         devSettings["sample_rate"] = addArgInfoProperty(m_propertyGrid, sampleRateArg);
         deviceArgs["sample_rate"] = sampleRateArg;
+
         
-        runtimeArgs.erase(runtimeArgs.begin(), runtimeArgs.end());
-        runtimeProps.erase(runtimeProps.begin(), runtimeProps.end());
-        streamProps.erase(streamProps.begin(), streamProps.end());
-        
+
+        //B) Runtime Settings:
+        runtimeArgs.clear();
+        runtimeProps.clear();
+        streamProps.clear();
+       
         if (args.size()) {
             m_propertyGrid->Append(new wxPropertyCategory("Run-time Settings"));
             
-            for (args_i = args.begin(); args_i != args.end(); args_i++) {
+            for (SoapySDR::ArgInfoList::const_iterator args_i = args.begin(); args_i != args.end(); args_i++) {
                 SoapySDR::ArgInfo arg = (*args_i);
-                arg.value = soapyDev->readSetting(arg.key);
+				//We-reread the Device configuration, else we use the user settings.
+				if (dev) {
+					//Apply saved settings
+					DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId());
+					arg.value = devConfig->getSetting(arg.key, soapyDev->readSetting(arg.key)); //use SoapyDevice data as fallback.
+				}
+				else {
+					//re-read the SoapyDevice
+					arg.value = soapyDev->readSetting(arg.key);
+				}
+               
                 runtimeProps[arg.key] = addArgInfoProperty(m_propertyGrid, arg);
                 runtimeArgs[arg.key] = arg;
             }
@@ -182,8 +246,8 @@ void SDRDevicesDialog::refreshDeviceProperties() {
             if (args.size()) {
                 m_propertyGrid->Append(new wxPropertyCategory("Stream Settings"));
                 
-                for (args_i = args.begin(); args_i != args.end(); args_i++) {
-                    SoapySDR::ArgInfo arg = (*args_i);
+                for (SoapySDR::ArgInfo arg : args) {
+                  
                     streamProps[arg.key] = addArgInfoProperty(m_propertyGrid, arg);
                 }
             }
@@ -199,10 +263,12 @@ void SDRDevicesDialog::refreshDeviceProperties() {
         
     } else if (selDev && !selDev->isAvailable() && selDev->isManual()) {
         m_propertyGrid->Clear();
-        devSettings.erase(devSettings.begin(),devSettings.end());
-        runtimeArgs.erase(runtimeArgs.begin(), runtimeArgs.end());
-        runtimeProps.erase(runtimeProps.begin(), runtimeProps.end());
-        streamProps.erase(streamProps.begin(), streamProps.end());
+
+        devSettings.clear();
+        runtimeArgs.clear();
+        runtimeProps.clear();
+        streamProps.clear();
+
         removeId = devTree->GetSelection();
         dev = nullptr;
         selId = nullptr;
@@ -227,10 +293,10 @@ void SDRDevicesDialog::OnAddRemote( wxMouseEvent& /* event */) {
         if (selDev) {
             SDREnumerator::removeManual(selDev->getDriver(),selDev->getManualParams());
             m_propertyGrid->Clear();
-            devSettings.erase(devSettings.begin(),devSettings.end());
-            runtimeArgs.erase(runtimeArgs.begin(), runtimeArgs.end());
-            runtimeProps.erase(runtimeProps.begin(), runtimeProps.end());
-            streamProps.erase(streamProps.begin(), streamProps.end());
+			devSettings.clear();
+			runtimeArgs.clear();
+			runtimeProps.clear();
+			streamProps.clear();
             dev = nullptr;
             selId = nullptr;
             editId = nullptr;
@@ -284,14 +350,14 @@ SDRDeviceInfo *SDRDevicesDialog::getSelectedDevice(wxTreeItemId selId) {
 
 void SDRDevicesDialog::OnUseSelected( wxMouseEvent& event) {
     if (dev != NULL) {
-        SoapySDR::ArgInfoList::const_iterator args_i;
+        
         SoapySDR::ArgInfoList args = dev->getSoapyDevice()->getSettingInfo();
         
         SoapySDR::Kwargs settingArgs;
         SoapySDR::Kwargs streamArgs;
         
-        for (args_i = args.begin(); args_i != args.end(); args_i++) {
-            SoapySDR::ArgInfo arg = (*args_i);
+        for (SoapySDR::ArgInfo arg : args) {
+           
             wxPGProperty *prop = runtimeProps[arg.key];
             
             if (arg.type == SoapySDR::ArgInfo::STRING && arg.options.size()) {
@@ -307,7 +373,7 @@ void SDRDevicesDialog::OnUseSelected( wxMouseEvent& event) {
             args = dev->getSoapyDevice()->getStreamArgsInfo(SOAPY_SDR_RX, 0);
             
             if (args.size()) {
-                for (args_i = args.begin(); args_i != args.end(); args_i++) {
+                for (SoapySDR::ArgInfoList::const_iterator args_i = args.begin(); args_i != args.end(); args_i++) {
                     SoapySDR::ArgInfo arg = (*args_i);
                     wxPGProperty *prop = streamProps[arg.key];
             
@@ -329,7 +395,6 @@ void SDRDevicesDialog::OnUseSelected( wxMouseEvent& event) {
         wxGetApp().setDeviceArgs(settingArgs);
         wxGetApp().setStreamArgs(streamArgs);
         wxGetApp().setDevice(dev,0);
-        wxGetApp().notifyMainUIOfDeviceChange();
         Close();
     }
     event.Skip();
@@ -392,18 +457,18 @@ void SDRDevicesDialog::OnDeviceTimer( wxTimerEvent& event ) {
         }
         
         std::vector<std::string> remotes = SDREnumerator::getRemotes();
-        std::vector<std::string>::iterator remotes_i;
+       
         std::vector<SDRDeviceInfo *>::iterator remoteDevs_i;
         
         if (remotes.size()) {
-            for (remotes_i = remotes.begin(); remotes_i != remotes.end(); remotes_i++) {
-                devs[*remotes_i] = SDREnumerator::enumerate_devices(*remotes_i, true);
-                DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(*remotes_i);
+            for (std::string remote : remotes) {
+                devs[remote] = SDREnumerator::enumerate_devices(remote, true);
+                DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(remote);
 
                 wxTreeItemId remoteNode = devTree->AppendItem(remoteBranch, devConfig->getDeviceName());
                 
-                if (devs[*remotes_i] != NULL) {
-                    for (remoteDevs_i = devs[*remotes_i]->begin(); remoteDevs_i != devs[*remotes_i]->end(); remoteDevs_i++) {
+                if (devs[remote] != NULL) {
+                    for (remoteDevs_i = devs[remote]->begin(); remoteDevs_i != devs[remote]->end(); remoteDevs_i++) {
                         devItems[devTree->AppendItem(remoteNode, (*remoteDevs_i)->getName())] = (*remoteDevs_i);
                     }
                 }
@@ -427,7 +492,8 @@ void SDRDevicesDialog::OnRefreshDevices( wxMouseEvent& /* event */) {
 }
 
 void SDRDevicesDialog::OnPropGridChanged( wxPropertyGridEvent& event ) {
-    if (editId && event.GetProperty() == devSettings["name"]) {
+
+    if (event.GetProperty() == devSettings["name"]) {
         DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId());
         
         wxString devName = event.GetPropertyValue().GetString();
@@ -445,7 +511,14 @@ void SDRDevicesDialog::OnPropGridChanged( wxPropertyGridEvent& event ) {
         long offset = event.GetPropertyValue().GetInteger();
         
         devConfig->setOffset(offset);
-    } else if (dev && event.GetProperty() == devSettings["sample_rate"]) {
+        if (dev->isActive() || !wxGetApp().getDevice()) {
+
+            wxGetApp().setOffset(offset);
+        }
+
+    } 
+    else if (dev && event.GetProperty() == devSettings["sample_rate"]) {
+
         DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId());
         
         std::string strRate = deviceArgs["sample_rate"].options[event.GetPropertyValue().GetInteger()];
@@ -453,17 +526,31 @@ void SDRDevicesDialog::OnPropGridChanged( wxPropertyGridEvent& event ) {
         try {
             srate = std::stol(strRate);
             devConfig->setSampleRate(srate);
-            
-            if (dev->isActive() || !wxGetApp().getDevice()) {
+             if (dev->isActive() || !wxGetApp().getDevice()) {
                 wxGetApp().setSampleRate(srate);
-                wxGetApp().notifyMainUIOfDeviceChange();
-            }            
+            }
         } catch (std::invalid_argument e) {
             // nop
         }
-    } else if (editId && dev) {
-        wxPGProperty *prop = event.GetProperty();
+    } else if (dev && event.GetProperty() == devSettings["antenna"]) {
+        DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId());
+
+        std::string strAntennaName = deviceArgs["antenna"].options[event.GetPropertyValue().GetInteger()];
         
+        try {
+            devConfig->setAntennaName(strAntennaName);
+
+            if (dev->isActive() || !wxGetApp().getDevice()) { 
+                wxGetApp().setAntennaName(strAntennaName);
+            }
+        }
+        catch (std::invalid_argument e) {
+            // nop
+        }
+    }
+    else if (dev) {
+        wxPGProperty *prop = event.GetProperty();
+        //change value of RuntimeProps
         for (std::map<std::string, wxPGProperty *>::iterator rtp = runtimeProps.begin(); rtp != runtimeProps.end(); rtp++) {
             if (rtp->second == prop) {
                 SoapySDR::Device *soapyDev = dev->getSoapyDevice();
@@ -481,7 +568,6 @@ void SDRDevicesDialog::OnPropGridChanged( wxPropertyGridEvent& event ) {
                 if (dev->isActive()) {
                     wxGetApp().getSDRThread()->writeSetting(rtp->first, settingValue);
                 }
-                refreshDeviceProperties();
                 return;
             }
         }
@@ -502,10 +588,11 @@ void SDRDevicesDialog::doRefreshDevices() {
     devTree->DeleteAllItems();
     devTree->Disable();
     m_propertyGrid->Clear();
-    runtimeArgs.erase(runtimeArgs.begin(), runtimeArgs.end());
-    runtimeProps.erase(runtimeProps.begin(), runtimeProps.end());
-    streamProps.erase(streamProps.begin(), streamProps.end());
-    devSettings.erase(devSettings.begin(), devSettings.end());
+	devSettings.clear();
+	runtimeArgs.clear();
+	runtimeProps.clear();
+	streamProps.clear();
+
     m_refreshButton->Disable();
     m_addRemoteButton->Disable();
     m_useSelectedButton->Disable();
diff --git a/src/forms/SDRDevices/SDRDevicesForm.cpp b/src/forms/SDRDevices/SDRDevicesForm.cpp
index cea3da8..d3f0fd5 100644
--- a/src/forms/SDRDevices/SDRDevicesForm.cpp
+++ b/src/forms/SDRDevices/SDRDevicesForm.cpp
@@ -1,115 +1,115 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Aug 23 2015)
+// C++ code generated with wxFormBuilder (version Oct 27 2017)
 // http://www.wxformbuilder.org/
 //
-// PLEASE DO "NOT" EDIT THIS FILE!
+// PLEASE DO *NOT* EDIT THIS FILE!
 ///////////////////////////////////////////////////////////////////////////
 
 #include "SDRDevicesForm.h"
 
 ///////////////////////////////////////////////////////////////////////////
 
-devFrame::devFrame( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style )
+devFrame::devFrame(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxFrame(parent, id, title, pos, size, style)
 {
-	this->SetSizeHints( wxDefaultSize, wxDefaultSize );
-	
-	devStatusBar = this->CreateStatusBar( 1, wxST_SIZEGRIP, wxID_ANY );
+	this->SetSizeHints(wxDefaultSize, wxDefaultSize);
+
+	devStatusBar = this->CreateStatusBar(1, wxST_SIZEGRIP, wxID_ANY);
 	wxBoxSizer* devFrameSizer;
-	devFrameSizer = new wxBoxSizer( wxVERTICAL );
-	
-	m_panel3 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+	devFrameSizer = new wxBoxSizer(wxVERTICAL);
+
+	m_panel3 = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
 	wxBoxSizer* bSizer4;
-	bSizer4 = new wxBoxSizer( wxHORIZONTAL );
-	
-	m_panel6 = new wxPanel( m_panel3, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+	bSizer4 = new wxBoxSizer(wxHORIZONTAL);
+
+	m_panel6 = new wxPanel(m_panel3, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
 	wxBoxSizer* bSizer6;
-	bSizer6 = new wxBoxSizer( wxVERTICAL );
-	
-	devTree = new wxTreeCtrl( m_panel6, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_DEFAULT_STYLE );
-	devTree->Enable( false );
-	
-	bSizer6->Add( devTree, 1, wxEXPAND, 5 );
-	
-	m_panel4 = new wxPanel( m_panel6, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+	bSizer6 = new wxBoxSizer(wxVERTICAL);
+
+	devTree = new wxTreeCtrl(m_panel6, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_DEFAULT_STYLE);
+	devTree->Enable(false);
+
+	bSizer6->Add(devTree, 1, wxEXPAND, 5);
+
+	m_panel4 = new wxPanel(m_panel6, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
 	wxBoxSizer* bSizer5;
-	bSizer5 = new wxBoxSizer( wxHORIZONTAL );
-	
-	m_refreshButton = new wxButton( m_panel4, wxID_ANY, wxT("Refresh"), wxDefaultPosition, wxDefaultSize, 0 );
-	bSizer5->Add( m_refreshButton, 1, wxALL, 5 );
-	
-	m_addRemoteButton = new wxButton( m_panel4, wxID_ANY, wxT("Add"), wxDefaultPosition, wxDefaultSize, 0 );
-	bSizer5->Add( m_addRemoteButton, 1, wxALL, 5 );
-	
-	m_useSelectedButton = new wxButton( m_panel4, wxID_ANY, wxT("Start"), wxDefaultPosition, wxDefaultSize, 0 );
-	bSizer5->Add( m_useSelectedButton, 1, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
-	
-	
-	m_panel4->SetSizer( bSizer5 );
+	bSizer5 = new wxBoxSizer(wxHORIZONTAL);
+
+	m_refreshButton = new wxButton(m_panel4, wxID_ANY, wxT("Refresh"), wxDefaultPosition, wxDefaultSize, 0);
+	bSizer5->Add(m_refreshButton, 1, wxALL, 5);
+
+	m_addRemoteButton = new wxButton(m_panel4, wxID_ANY, wxT("Add"), wxDefaultPosition, wxDefaultSize, 0);
+	bSizer5->Add(m_addRemoteButton, 1, wxALL, 5);
+
+	m_useSelectedButton = new wxButton(m_panel4, wxID_ANY, wxT("Start"), wxDefaultPosition, wxDefaultSize, 0);
+	bSizer5->Add(m_useSelectedButton, 1, wxALL | wxALIGN_CENTER_VERTICAL, 5);
+
+
+	m_panel4->SetSizer(bSizer5);
 	m_panel4->Layout();
-	bSizer5->Fit( m_panel4 );
-	bSizer6->Add( m_panel4, 0, wxEXPAND, 5 );
-	
-	
-	m_panel6->SetSizer( bSizer6 );
+	bSizer5->Fit(m_panel4);
+	bSizer6->Add(m_panel4, 0, wxEXPAND, 5);
+
+
+	m_panel6->SetSizer(bSizer6);
 	m_panel6->Layout();
-	bSizer6->Fit( m_panel6 );
-	bSizer4->Add( m_panel6, 1, wxEXPAND | wxALL, 5 );
-	
-	m_panel61 = new wxPanel( m_panel3, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+	bSizer6->Fit(m_panel6);
+	bSizer4->Add(m_panel6, 1, wxEXPAND | wxALL, 5);
+
+	m_panel61 = new wxPanel(m_panel3, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
 	wxBoxSizer* bSizer7;
-	bSizer7 = new wxBoxSizer( wxVERTICAL );
-	
-	m_staticText1 = new wxStaticText( m_panel61, wxID_ANY, wxT("SoapySDR Device Options"), wxDefaultPosition, wxDefaultSize, 0 );
-	m_staticText1->Wrap( -1 );
-	bSizer7->Add( m_staticText1, 0, wxALL, 5 );
-	
+	bSizer7 = new wxBoxSizer(wxVERTICAL);
+
+	m_staticText1 = new wxStaticText(m_panel61, wxID_ANY, wxT("SoapySDR Device Options"), wxDefaultPosition, wxDefaultSize, 0);
+	m_staticText1->Wrap(-1);
+	bSizer7->Add(m_staticText1, 0, wxALL, 5);
+
 	m_propertyGrid = new wxPropertyGrid(m_panel61, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxPG_DEFAULT_STYLE);
-	bSizer7->Add( m_propertyGrid, 1, wxALL|wxEXPAND, 5 );
-	
-	
-	m_panel61->SetSizer( bSizer7 );
+	bSizer7->Add(m_propertyGrid, 1, wxALL | wxEXPAND, 5);
+
+
+	m_panel61->SetSizer(bSizer7);
 	m_panel61->Layout();
-	bSizer7->Fit( m_panel61 );
-	bSizer4->Add( m_panel61, 1, wxEXPAND | wxALL, 5 );
-	
-	
-	m_panel3->SetSizer( bSizer4 );
+	bSizer7->Fit(m_panel61);
+	bSizer4->Add(m_panel61, 1, wxEXPAND | wxALL, 5);
+
+
+	m_panel3->SetSizer(bSizer4);
 	m_panel3->Layout();
-	bSizer4->Fit( m_panel3 );
-	devFrameSizer->Add( m_panel3, 1, wxEXPAND | wxALL, 5 );
-	
-	
-	this->SetSizer( devFrameSizer );
+	bSizer4->Fit(m_panel3);
+	devFrameSizer->Add(m_panel3, 1, wxEXPAND | wxALL, 5);
+
+
+	this->SetSizer(devFrameSizer);
 	this->Layout();
-	m_deviceTimer.SetOwner( this, wxID_ANY );
-	
-	this->Centre( wxBOTH );
-	
+	m_deviceTimer.SetOwner(this, wxID_ANY);
+
+	this->Centre(wxBOTH);
+
 	// Connect Events
-	this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( devFrame::OnClose ) );
-	devTree->Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( devFrame::OnTreeDoubleClick ), NULL, this );
-	devTree->Connect( wxEVT_COMMAND_TREE_DELETE_ITEM, wxTreeEventHandler( devFrame::OnDeleteItem ), NULL, this );
-	devTree->Connect( wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler( devFrame::OnSelectionChanged ), NULL, this );
-	m_refreshButton->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( devFrame::OnRefreshDevices ), NULL, this );
-	m_addRemoteButton->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( devFrame::OnAddRemote ), NULL, this );
-	m_useSelectedButton->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( devFrame::OnUseSelected ), NULL, this );
-	m_propertyGrid->Connect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( devFrame::OnPropGridChanged ), NULL, this );
-	m_propertyGrid->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( devFrame::OnPropGridFocus ), NULL, this );
-	this->Connect( wxID_ANY, wxEVT_TIMER, wxTimerEventHandler( devFrame::OnDeviceTimer ) );
+	this->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(devFrame::OnClose));
+	devTree->Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(devFrame::OnTreeDoubleClick), NULL, this);
+	devTree->Connect(wxEVT_COMMAND_TREE_DELETE_ITEM, wxTreeEventHandler(devFrame::OnDeleteItem), NULL, this);
+	devTree->Connect(wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler(devFrame::OnSelectionChanged), NULL, this);
+	m_refreshButton->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(devFrame::OnRefreshDevices), NULL, this);
+	m_addRemoteButton->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(devFrame::OnAddRemote), NULL, this);
+	m_useSelectedButton->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(devFrame::OnUseSelected), NULL, this);
+	m_propertyGrid->Connect(wxEVT_PG_CHANGED, wxPropertyGridEventHandler(devFrame::OnPropGridChanged), NULL, this);
+	m_propertyGrid->Connect(wxEVT_SET_FOCUS, wxFocusEventHandler(devFrame::OnPropGridFocus), NULL, this);
+	this->Connect(wxID_ANY, wxEVT_TIMER, wxTimerEventHandler(devFrame::OnDeviceTimer));
 }
 
 devFrame::~devFrame()
 {
 	// Disconnect Events
-	this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( devFrame::OnClose ) );
-	devTree->Disconnect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( devFrame::OnTreeDoubleClick ), NULL, this );
-	devTree->Disconnect( wxEVT_COMMAND_TREE_DELETE_ITEM, wxTreeEventHandler( devFrame::OnDeleteItem ), NULL, this );
-	devTree->Disconnect( wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler( devFrame::OnSelectionChanged ), NULL, this );
-	m_refreshButton->Disconnect( wxEVT_LEFT_UP, wxMouseEventHandler( devFrame::OnRefreshDevices ), NULL, this );
-	m_addRemoteButton->Disconnect( wxEVT_LEFT_UP, wxMouseEventHandler( devFrame::OnAddRemote ), NULL, this );
-	m_useSelectedButton->Disconnect( wxEVT_LEFT_UP, wxMouseEventHandler( devFrame::OnUseSelected ), NULL, this );
-	m_propertyGrid->Disconnect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( devFrame::OnPropGridChanged ), NULL, this );
-	m_propertyGrid->Disconnect( wxEVT_SET_FOCUS, wxFocusEventHandler( devFrame::OnPropGridFocus ), NULL, this );
-	this->Disconnect( wxID_ANY, wxEVT_TIMER, wxTimerEventHandler( devFrame::OnDeviceTimer ) );
-	
+	this->Disconnect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(devFrame::OnClose));
+	devTree->Disconnect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(devFrame::OnTreeDoubleClick), NULL, this);
+	devTree->Disconnect(wxEVT_COMMAND_TREE_DELETE_ITEM, wxTreeEventHandler(devFrame::OnDeleteItem), NULL, this);
+	devTree->Disconnect(wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler(devFrame::OnSelectionChanged), NULL, this);
+	m_refreshButton->Disconnect(wxEVT_LEFT_UP, wxMouseEventHandler(devFrame::OnRefreshDevices), NULL, this);
+	m_addRemoteButton->Disconnect(wxEVT_LEFT_UP, wxMouseEventHandler(devFrame::OnAddRemote), NULL, this);
+	m_useSelectedButton->Disconnect(wxEVT_LEFT_UP, wxMouseEventHandler(devFrame::OnUseSelected), NULL, this);
+	m_propertyGrid->Disconnect(wxEVT_PG_CHANGED, wxPropertyGridEventHandler(devFrame::OnPropGridChanged), NULL, this);
+	m_propertyGrid->Disconnect(wxEVT_SET_FOCUS, wxFocusEventHandler(devFrame::OnPropGridFocus), NULL, this);
+	this->Disconnect(wxID_ANY, wxEVT_TIMER, wxTimerEventHandler(devFrame::OnDeviceTimer));
+
 }
diff --git a/src/forms/SDRDevices/SDRDevicesForm.h b/src/forms/SDRDevices/SDRDevicesForm.h
index 74d8d6c..c4976f0 100644
--- a/src/forms/SDRDevices/SDRDevicesForm.h
+++ b/src/forms/SDRDevices/SDRDevicesForm.h
@@ -1,8 +1,8 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Aug 23 2015)
+// C++ code generated with wxFormBuilder (version Oct 27 2017)
 // http://www.wxformbuilder.org/
 //
-// PLEASE DO "NOT" EDIT THIS FILE!
+// PLEASE DO *NOT* EDIT THIS FILE!
 ///////////////////////////////////////////////////////////////////////////
 
 #ifndef __SDRDEVICESFORM_H__
@@ -35,43 +35,43 @@
 ///////////////////////////////////////////////////////////////////////////////
 /// Class devFrame
 ///////////////////////////////////////////////////////////////////////////////
-class devFrame : public wxFrame 
+class devFrame : public wxFrame
 {
-	private:
-	
-	protected:
-		wxStatusBar* devStatusBar;
-		wxPanel* m_panel3;
-		wxPanel* m_panel6;
-		wxTreeCtrl* devTree;
-		wxPanel* m_panel4;
-		wxButton* m_refreshButton;
-		wxButton* m_addRemoteButton;
-		wxButton* m_useSelectedButton;
-		wxPanel* m_panel61;
-		wxStaticText* m_staticText1;
-		wxPropertyGrid* m_propertyGrid;
-		wxTimer m_deviceTimer;
-		
-		// Virtual event handlers, overide them in your derived class
-		virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
-		virtual void OnTreeDoubleClick( wxMouseEvent& event ) { event.Skip(); }
-		virtual void OnDeleteItem( wxTreeEvent& event ) { event.Skip(); }
-		virtual void OnSelectionChanged( wxTreeEvent& event ) { event.Skip(); }
-		virtual void OnRefreshDevices( wxMouseEvent& event ) { event.Skip(); }
-		virtual void OnAddRemote( wxMouseEvent& event ) { event.Skip(); }
-		virtual void OnUseSelected( wxMouseEvent& event ) { event.Skip(); }
-		virtual void OnPropGridChanged( wxPropertyGridEvent& event ) { event.Skip(); }
-		virtual void OnPropGridFocus( wxFocusEvent& event ) { event.Skip(); }
-		virtual void OnDeviceTimer( wxTimerEvent& event ) { event.Skip(); }
-		
-	
-	public:
-		
-		devFrame( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("CubicSDR :: SDR Devices"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 700,467 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
-		
-		~devFrame();
-	
+private:
+
+protected:
+	wxStatusBar* devStatusBar;
+	wxPanel* m_panel3;
+	wxPanel* m_panel6;
+	wxTreeCtrl* devTree;
+	wxPanel* m_panel4;
+	wxButton* m_refreshButton;
+	wxButton* m_addRemoteButton;
+	wxButton* m_useSelectedButton;
+	wxPanel* m_panel61;
+	wxStaticText* m_staticText1;
+	wxPropertyGrid* m_propertyGrid;
+	wxTimer m_deviceTimer;
+
+	// Virtual event handlers, overide them in your derived class
+	virtual void OnClose(wxCloseEvent& event) { event.Skip(); }
+	virtual void OnTreeDoubleClick(wxMouseEvent& event) { event.Skip(); }
+	virtual void OnDeleteItem(wxTreeEvent& event) { event.Skip(); }
+	virtual void OnSelectionChanged(wxTreeEvent& event) { event.Skip(); }
+	virtual void OnRefreshDevices(wxMouseEvent& event) { event.Skip(); }
+	virtual void OnAddRemote(wxMouseEvent& event) { event.Skip(); }
+	virtual void OnUseSelected(wxMouseEvent& event) { event.Skip(); }
+	virtual void OnPropGridChanged(wxPropertyGridEvent& event) { event.Skip(); }
+	virtual void OnPropGridFocus(wxFocusEvent& event) { event.Skip(); }
+	virtual void OnDeviceTimer(wxTimerEvent& event) { event.Skip(); }
+
+
+public:
+
+	devFrame(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("CubicSDR :: SDR Devices"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(700, 467), long style = wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL);
+
+	~devFrame();
+
 };
 
 #endif //__SDRDEVICESFORM_H__
diff --git a/src/modules/modem/Modem.h b/src/modules/modem/Modem.h
index a22166d..355f492 100644
--- a/src/modules/modem/Modem.h
+++ b/src/modules/modem/Modem.h
@@ -8,6 +8,7 @@
 #include "AudioThread.h"
 #include <cmath>
 #include <atomic>
+#include <memory>
 
 #define MIN_BANDWIDTH 500
 
@@ -25,7 +26,7 @@ public:
     int audioSampleRate;
 };
 
-class ModemIQData: public ReferenceCounter {
+class ModemIQData {
 public:
     std::vector<liquid_float_complex> data;
     long long sampleRate;
@@ -34,11 +35,13 @@ public:
         
     }
     
-    ~ModemIQData() {
-        std::lock_guard < std::recursive_mutex > lock(m_mutex);
+    virtual ~ModemIQData() {
+        
     }
 };
 
+typedef std::shared_ptr<ModemIQData> ModemIQDataPtr;
+
 // Copy of SoapySDR::Range, original comments
 class ModemRange
 {
diff --git a/src/modules/modem/analog/ModemAM.cpp b/src/modules/modem/analog/ModemAM.cpp
index 03da7e8..5c3604f 100644
--- a/src/modules/modem/analog/ModemAM.cpp
+++ b/src/modules/modem/analog/ModemAM.cpp
@@ -24,13 +24,13 @@ int ModemAM::getDefaultSampleRate() {
     return 6000;
 }
 
-void ModemAM::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
+void ModemAM::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput* audioOut) {
     ModemKitAnalog *amkit = (ModemKitAnalog *)kit;
     
     initOutputBuffers(amkit,input);
     
     if (!bufSize) {
-        input->decRefCount();
+       
         return;
     }
     
diff --git a/src/modules/modem/analog/ModemDSB.cpp b/src/modules/modem/analog/ModemDSB.cpp
index 37f5b26..4c69c12 100644
--- a/src/modules/modem/analog/ModemDSB.cpp
+++ b/src/modules/modem/analog/ModemDSB.cpp
@@ -30,7 +30,7 @@ void ModemDSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *a
     initOutputBuffers(amkit, input);
     
     if (!bufSize) {
-        input->decRefCount();
+       
         return;
     }
     
diff --git a/src/modules/modem/analog/ModemFM.cpp b/src/modules/modem/analog/ModemFM.cpp
index da969b8..cf20709 100644
--- a/src/modules/modem/analog/ModemFM.cpp
+++ b/src/modules/modem/analog/ModemFM.cpp
@@ -29,7 +29,7 @@ void ModemFM::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *au
     initOutputBuffers(fmkit, input);
     
     if (!bufSize) {
-        input->decRefCount();
+      
         return;
     }
     
diff --git a/src/modules/modem/analog/ModemIQ.cpp b/src/modules/modem/analog/ModemIQ.cpp
index 9fa3ec7..81af37d 100644
--- a/src/modules/modem/analog/ModemIQ.cpp
+++ b/src/modules/modem/analog/ModemIQ.cpp
@@ -42,7 +42,7 @@ void ModemIQ::demodulate(ModemKit * /* kit */, ModemIQData *input, AudioThreadIn
     size_t bufSize = input->data.size();
     
     if (!bufSize) {
-        input->decRefCount();
+       
         return;
     }
     
diff --git a/src/modules/modem/analog/ModemLSB.cpp b/src/modules/modem/analog/ModemLSB.cpp
index 295a9c4..c3fb76d 100644
--- a/src/modules/modem/analog/ModemLSB.cpp
+++ b/src/modules/modem/analog/ModemLSB.cpp
@@ -46,7 +46,7 @@ void ModemLSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *a
     initOutputBuffers(akit,input);
     
     if (!bufSize) {
-        input->decRefCount();
+       
         return;
     }
     
diff --git a/src/modules/modem/analog/ModemNBFM.cpp b/src/modules/modem/analog/ModemNBFM.cpp
index fd1b255..84e3202 100644
--- a/src/modules/modem/analog/ModemNBFM.cpp
+++ b/src/modules/modem/analog/ModemNBFM.cpp
@@ -29,7 +29,7 @@ void ModemNBFM::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *
     initOutputBuffers(fmkit, input);
     
     if (!bufSize) {
-        input->decRefCount();
+       
         return;
     }
     
diff --git a/src/modules/modem/analog/ModemUSB.cpp b/src/modules/modem/analog/ModemUSB.cpp
index 775fadc..8b30761 100644
--- a/src/modules/modem/analog/ModemUSB.cpp
+++ b/src/modules/modem/analog/ModemUSB.cpp
@@ -46,7 +46,7 @@ void ModemUSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *a
     initOutputBuffers(akit,input);
     
     if (!bufSize) {
-        input->decRefCount();
+       
         return;
     }
     
diff --git a/src/panel/MeterPanel.cpp b/src/panel/MeterPanel.cpp
index c3d191f..ea74311 100644
--- a/src/panel/MeterPanel.cpp
+++ b/src/panel/MeterPanel.cpp
@@ -126,7 +126,7 @@ bool MeterPanel::isMeterHit(CubicVR::vec2 mousePoint) {
     return false;
 }
 
-float MeterPanel::getMeterHitValue(CubicVR::vec2 mousePoint, GLPanel &panel) {
+float MeterPanel::getMeterHitValue(CubicVR::vec2 mousePoint) {
     CubicVR::vec2 hitResult;
     
     if (bgPanel.hitTest(mousePoint, hitResult)) {
diff --git a/src/panel/MeterPanel.h b/src/panel/MeterPanel.h
index 21b4c58..86a737d 100644
--- a/src/panel/MeterPanel.h
+++ b/src/panel/MeterPanel.h
@@ -20,7 +20,7 @@ public:
     void setHighlightVisible(bool vis);
     float getValue();
     bool isMeterHit(CubicVR::vec2 mousePoint);
-    float getMeterHitValue(CubicVR::vec2 mousePoint, GLPanel &panel);
+    float getMeterHitValue(CubicVR::vec2 mousePoint);
     void setChanged(bool changed);
     bool getChanged();
     
@@ -32,7 +32,7 @@ protected:
 private:
     std::string name;
     float low, high, current;
-    bool changed;
+    bool changed = false;
     GLPanel bgPanel;
     GLPanel levelPanel;
     GLPanel highlightPanel;
diff --git a/src/panel/ScopePanel.cpp b/src/panel/ScopePanel.cpp
index bde35cd..c55d9f4 100644
--- a/src/panel/ScopePanel.cpp
+++ b/src/panel/ScopePanel.cpp
@@ -35,7 +35,7 @@ void ScopePanel::drawPanelContents() {
         bgPanel.draw();
         glLineWidth(1.0);
         glEnable(GL_LINE_SMOOTH);
-        glLoadMatrixf(transform);
+        glLoadMatrixf(transform.to_ptr());
         glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r * 0.35, ThemeMgr::mgr.currentTheme->scopeLine.g * 0.35,
                   ThemeMgr::mgr.currentTheme->scopeLine.b * 0.35);
         glBegin (GL_LINES);
@@ -52,7 +52,7 @@ void ScopePanel::drawPanelContents() {
         bgPanelStereo[1].draw();
 
         glLineWidth(1.0);
-        glLoadMatrixf(transform);
+        glLoadMatrixf(transform.to_ptr());
         glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r, ThemeMgr::mgr.currentTheme->scopeLine.g, ThemeMgr::mgr.currentTheme->scopeLine.b);
         glEnable(GL_LINE_SMOOTH);
         glBegin (GL_LINES);
@@ -76,7 +76,7 @@ void ScopePanel::drawPanelContents() {
         glLineWidth(1.0);
         glEnable(GL_POINT_SMOOTH);
         glPointSize(1.0);
-        glLoadMatrixf(transform);
+        glLoadMatrixf(transform.to_ptr());
         glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r * 0.15, ThemeMgr::mgr.currentTheme->scopeLine.g * 0.15,
                   ThemeMgr::mgr.currentTheme->scopeLine.b * 0.15);
     }
@@ -95,16 +95,16 @@ void ScopePanel::drawPanelContents() {
         glVertexPointer(2, GL_FLOAT, 0, &points[0]);
         glLineWidth(1.5);
         if (scopeMode == SCOPE_MODE_Y) {
-            glLoadMatrixf(bgPanel.transform);
+            glLoadMatrixf(bgPanel.transform.to_ptr());
             glDrawArrays(GL_LINE_STRIP, 0, points.size() / 2);
         } else if (scopeMode == SCOPE_MODE_2Y)  {
-            glLoadMatrixf(bgPanelStereo[0].transform);
+            glLoadMatrixf(bgPanelStereo[0].transform.to_ptr());
             glDrawArrays(GL_LINE_STRIP, 0, points.size() / 4);
 
-            glLoadMatrixf(bgPanelStereo[1].transform);
+            glLoadMatrixf(bgPanelStereo[1].transform.to_ptr());
             glDrawArrays(GL_LINE_STRIP, points.size() / 4, points.size() / 4);
         } else if (scopeMode == SCOPE_MODE_XY) {
-            glLoadMatrixf(bgPanel.transform);
+            glLoadMatrixf(bgPanel.transform.to_ptr());
             glDrawArrays(GL_POINTS, 0, points.size() / 2);
         }
         glLineWidth(1.0);
diff --git a/src/panel/SpectrumPanel.cpp b/src/panel/SpectrumPanel.cpp
index 780f442..a9ba1fb 100644
--- a/src/panel/SpectrumPanel.cpp
+++ b/src/panel/SpectrumPanel.cpp
@@ -113,7 +113,7 @@ void SpectrumPanel::drawPanelContents() {
     glEnable(GL_LINE_SMOOTH);
     glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
 
-    glLoadMatrixf(transform * (CubicVR::mat4::translate(-1.0f, -0.75f, 0.0f) * CubicVR::mat4::scale(2.0f, 1.5f, 1.0f)));
+    glLoadMatrixf((transform * (CubicVR::mat4::translate(-1.0f, -0.75f, 0.0f) * CubicVR::mat4::scale(2.0f, 1.5f, 1.0f))).to_ptr());
 
     if (points.size()) {
         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
@@ -166,7 +166,7 @@ void SpectrumPanel::drawPanelContents() {
     
     float viewHeight = (float) vp[3];
     float viewWidth = (float) vp[2];
-    glLoadMatrixf(transform);
+    glLoadMatrixf(transform.to_ptr());
 
     
     long long leftFreq = (double) freq - ((double) bandwidth / 2.0);
diff --git a/src/panel/WaterfallPanel.cpp b/src/panel/WaterfallPanel.cpp
index 20b6fa1..bdbc8d8 100644
--- a/src/panel/WaterfallPanel.cpp
+++ b/src/panel/WaterfallPanel.cpp
@@ -165,7 +165,7 @@ void WaterfallPanel::drawPanelContents() {
 
     int half_fft_size = fft_size / 2;
     
-    glLoadMatrixf(transform);
+    glLoadMatrixf(transform.to_ptr());
     
     glEnable (GL_TEXTURE_2D);
     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
diff --git a/src/process/FFTDataDistributor.cpp b/src/process/FFTDataDistributor.cpp
index 8636b70..07a6a3d 100644
--- a/src/process/FFTDataDistributor.cpp
+++ b/src/process/FFTDataDistributor.cpp
@@ -5,6 +5,9 @@
 #include <algorithm>
 #include <ThreadBlockingQueue.h>
 
+//50 ms
+#define HEARTBEAT_CHECK_PERIOD_MICROS (50 * 1000) 
+
 FFTDataDistributor::FFTDataDistributor() : outputBuffers("FFTDataDistributorBuffers"), fftSize(DEFAULT_FFT_SIZE), linesPerSecond(DEFAULT_WATERFALL_LPS), lineRateAccum(0.0) {
 
 }
@@ -28,8 +31,11 @@ void FFTDataDistributor::process() {
 		if (!isAnyOutputEmpty()) {
 			return;
 		}
-		DemodulatorThreadIQData *inp;
-		input->pop(inp);
+		DemodulatorThreadIQDataPtr inp;
+
+        if (!input->pop(inp, HEARTBEAT_CHECK_PERIOD_MICROS)) {
+            continue;
+        }
 
 		if (inp) {
             //Settings have changed, set new values and dump all previous samples stored in inputBuffer: 
@@ -73,7 +79,7 @@ void FFTDataDistributor::process() {
             memcpy(&inputBuffer.data[bufferOffset+bufferedItems],&inp->data[0], nbSamplesToAdd *sizeof(liquid_float_complex));
             bufferedItems += nbSamplesToAdd;
             //
-			inp->decRefCount();
+		
 		} else {
             //empty inp, wait for another.
 			continue;
@@ -105,7 +111,8 @@ void FFTDataDistributor::process() {
 
 					if (lineRateAccum >= 1.0) {
                         //each i represents a FFT computation
-						DemodulatorThreadIQData *outp = outputBuffers.getBuffer();
+                        DemodulatorThreadIQDataPtr outp = outputBuffers.getBuffer();
+
 						outp->frequency = inputBuffer.frequency;
 						outp->sampleRate = inputBuffer.sampleRate;
 						outp->data.assign(inputBuffer.data.begin()+bufferOffset+i,
diff --git a/src/process/FFTVisualDataThread.cpp b/src/process/FFTVisualDataThread.cpp
index c0c820e..0dd398e 100644
--- a/src/process/FFTVisualDataThread.cpp
+++ b/src/process/FFTVisualDataThread.cpp
@@ -27,11 +27,12 @@ SpectrumVisualProcessor *FFTVisualDataThread::getProcessor() {
 }
 
 void FFTVisualDataThread::run() {
-    DemodulatorThreadInputQueue *pipeIQDataIn = static_cast<DemodulatorThreadInputQueue *>(getInputQueue("IQDataInput"));
-    SpectrumVisualDataQueue *pipeFFTDataOut = static_cast<SpectrumVisualDataQueue *>(getOutputQueue("FFTDataOutput"));
+
+    DemodulatorThreadInputQueuePtr pipeIQDataIn = std::static_pointer_cast<DemodulatorThreadInputQueue>(getInputQueue("IQDataInput"));
+    SpectrumVisualDataQueuePtr pipeFFTDataOut = std::static_pointer_cast<SpectrumVisualDataQueue>(getOutputQueue("FFTDataOutput"));
     
 
-    fftQueue.set_max_num_items(100); 
+    fftQueue->set_max_num_items(100); 
     pipeFFTDataOut->set_max_num_items(100);
 
     //FFT distributor plumbing:
@@ -39,10 +40,10 @@ void FFTVisualDataThread::run() {
     fftDistrib.setInput(pipeIQDataIn);
 
     //The FFT distributor has actually 1 output only, so it doesn't distribute at all :) 
-    fftDistrib.attachOutput(&fftQueue);
+    fftDistrib.attachOutput(fftQueue);
     
     //FFT Distributor output is ==> SpectrumVisualProcessor input.
-    wproc.setInput(&fftQueue);
+    wproc.setInput(fftQueue);
     wproc.attachOutput(pipeFFTDataOut);
     wproc.setup(DEFAULT_FFT_SIZE);
 
@@ -72,11 +73,20 @@ void FFTVisualDataThread::run() {
         fftDistrib.run();
       
         // Make wproc do a FFT of each of the sample sets provided by fftDistrib: 
-        while (!wproc.isInputEmpty()) {
+        while (!stopping && !wproc.isInputEmpty()) {
             wproc.run();
         }
     }
+
+    pipeIQDataIn->flush();
+    pipeFFTDataOut->flush();
     
 //    std::cout << "FFT visual data thread done." << std::endl;
 }
 
+void FFTVisualDataThread::terminate() {
+    IOThread::terminate();
+    fftDistrib.flushQueues();
+    wproc.flushQueues();
+}
+
diff --git a/src/process/FFTVisualDataThread.h b/src/process/FFTVisualDataThread.h
index 55ff408..549950b 100644
--- a/src/process/FFTVisualDataThread.h
+++ b/src/process/FFTVisualDataThread.h
@@ -2,7 +2,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 
 #pragma once
-
+#include <memory>
 #include "IOThread.h"
 #include "SpectrumVisualProcessor.h"
 #include "FFTDataDistributor.h"
@@ -17,10 +17,12 @@ public:
     SpectrumVisualProcessor *getProcessor();
     
     virtual void run();
+
+    virtual void terminate();
     
 protected:
     FFTDataDistributor fftDistrib;
-    DemodulatorThreadInputQueue fftQueue;
+    DemodulatorThreadInputQueuePtr fftQueue = std::make_shared<DemodulatorThreadInputQueue>();
     SpectrumVisualProcessor wproc;
     
     std::atomic_int linesPerSecond;
diff --git a/src/process/ScopeVisualProcessor.cpp b/src/process/ScopeVisualProcessor.cpp
index 5b83b07..a1eefac 100644
--- a/src/process/ScopeVisualProcessor.cpp
+++ b/src/process/ScopeVisualProcessor.cpp
@@ -47,7 +47,7 @@ void ScopeVisualProcessor::process() {
     if (!isOutputEmpty()) {
         return;
     }
-    AudioThreadInput *audioInputData;
+    AudioThreadInputPtr audioInputData;
 
     if (input->try_pop(audioInputData)) {
           
@@ -56,11 +56,12 @@ void ScopeVisualProcessor::process() {
         }
         size_t i, iMax = audioInputData->data.size();
         if (!iMax) {
-            delete audioInputData; //->decRefCount();
+            //discard audioInputData.
+            audioInputData = nullptr;
             return;
         }
                 
-        ScopeRenderData *renderData = NULL;
+        ScopeRenderDataPtr renderData = nullptr;
         
         if (scopeEnabled) {
             iMax = audioInputData->data.size();
@@ -150,7 +151,7 @@ void ScopeVisualProcessor::process() {
             renderData->inputRate = audioInputData->inputRate;
             renderData->sampleRate = audioInputData->sampleRate;
             
-            delete audioInputData; //->decRefCount();
+            audioInputData = nullptr; //->decRefCount();
 
             double fft_ceil = 0, fft_floor = 1;
             
@@ -212,8 +213,6 @@ void ScopeVisualProcessor::process() {
             renderData->spectrum = true;
 
             distribute(renderData);
-        } else {
-            delete audioInputData; //->decRefCount();
-        }
+        } 
     } //end if try_pop()
 }
diff --git a/src/process/ScopeVisualProcessor.h b/src/process/ScopeVisualProcessor.h
index d5ba64c..0cd5a44 100644
--- a/src/process/ScopeVisualProcessor.h
+++ b/src/process/ScopeVisualProcessor.h
@@ -6,8 +6,9 @@
 #include "VisualProcessor.h"
 #include "AudioThread.h"
 #include "ScopePanel.h"
+#include <memory>
 
-class ScopeRenderData: public ReferenceCounter {
+class ScopeRenderData {
 public:
 	std::vector<float> waveform_points;
     ScopePanel::ScopeMode mode = ScopePanel::SCOPE_MODE_Y;
@@ -17,9 +18,17 @@ public:
     bool spectrum;
     int fft_size;
     double fft_floor, fft_ceil;
+
+    virtual ~ScopeRenderData() {
+
+    }
 };
 
-typedef ThreadBlockingQueue<ScopeRenderData *> ScopeRenderDataQueue;
+typedef std::shared_ptr<ScopeRenderData> ScopeRenderDataPtr;
+
+typedef ThreadBlockingQueue<ScopeRenderDataPtr> ScopeRenderDataQueue;
+
+typedef std::shared_ptr<ScopeRenderDataQueue> ScopeRenderDataQueuePtr;
 
 class ScopeVisualProcessor : public VisualProcessor<AudioThreadInput, ScopeRenderData> {
 public:
diff --git a/src/process/SpectrumVisualDataThread.cpp b/src/process/SpectrumVisualDataThread.cpp
index 1e954a2..5841f52 100644
--- a/src/process/SpectrumVisualDataThread.cpp
+++ b/src/process/SpectrumVisualDataThread.cpp
@@ -28,3 +28,7 @@ void SpectrumVisualDataThread::run() {
 //    std::cout << "Spectrum visual data thread done." << std::endl;
 }
 
+void SpectrumVisualDataThread::terminate() {
+    IOThread::terminate();
+    sproc.flushQueues();
+}
\ No newline at end of file
diff --git a/src/process/SpectrumVisualDataThread.h b/src/process/SpectrumVisualDataThread.h
index c6efc6c..0c3eccf 100644
--- a/src/process/SpectrumVisualDataThread.h
+++ b/src/process/SpectrumVisualDataThread.h
@@ -13,6 +13,8 @@ public:
     SpectrumVisualProcessor *getProcessor();
     
     virtual void run();
+
+    virtual void terminate();
     
 protected:
     SpectrumVisualProcessor sproc;
diff --git a/src/process/SpectrumVisualProcessor.cpp b/src/process/SpectrumVisualProcessor.cpp
index 7b02892..19f27a1 100644
--- a/src/process/SpectrumVisualProcessor.cpp
+++ b/src/process/SpectrumVisualProcessor.cpp
@@ -4,6 +4,8 @@
 #include "SpectrumVisualProcessor.h"
 #include "CubicSDR.h"
 
+//50 ms
+#define HEARTBEAT_CHECK_PERIOD_MICROS (50 * 1000) 
 
 SpectrumVisualProcessor::SpectrumVisualProcessor() : outputBuffers("SpectrumVisualProcessorBuffers") {
     lastInputBandwidth = 0;
@@ -18,11 +20,11 @@ SpectrumVisualProcessor::SpectrumVisualProcessor() : outputBuffers("SpectrumVisu
     fftLastData = nullptr;
     fftPlan = nullptr;
     
-    is_view.store(false);
-    fftSize.store(0);
-    centerFreq.store(0);
-    bandwidth.store(0);
-    hideDC.store(false);
+    is_view = false;
+    fftSize = 0;
+    centerFreq = 0;
+    bandwidth = 0;
+    hideDC = false;
     
     freqShifter = nco_crcf_create(LIQUID_NCO);
     shiftFrequency = 0;
@@ -30,14 +32,14 @@ SpectrumVisualProcessor::SpectrumVisualProcessor() : outputBuffers("SpectrumVisu
     fft_ceil_ma = fft_ceil_maa = 100.0;
     fft_floor_ma = fft_floor_maa = 0.0;
     fft_floor_peak = 0.0;
-    desiredInputSize.store(0);
+    desiredInputSize = 0;
     fft_average_rate = 0.65f;
-    scaleFactor.store(1.0);
-    fftSizeChanged.store(false);
-    newFFTSize.store(0);
+    scaleFactor = 1.0;
+    fftSizeChanged = false;
+    newFFTSize = 0;
     lastView = false;
-    peakHold.store(false);
-    peakReset.store(false);
+    peakHold = false;
+    peakReset = false;
     
 }
 
@@ -46,75 +48,93 @@ SpectrumVisualProcessor::~SpectrumVisualProcessor() {
 }
 
 bool SpectrumVisualProcessor::isView() {
-    return is_view.load();
+	
+	std::lock_guard < std::mutex > busy_lock(busy_run);
+    
+	return is_view;
 }
 
 void SpectrumVisualProcessor::setView(bool bView) {
-    
-    std::lock_guard < std::mutex > busy_lock(busy_run);    
-    is_view.store(bView);
-    
+	
+	std::lock_guard < std::mutex > busy_lock(busy_run);
+
+    is_view = bView;  
 }
 
 void SpectrumVisualProcessor::setView(bool bView, long long centerFreq_in, long bandwidth_in) {
     
     std::lock_guard < std::mutex > busy_lock(busy_run);    
-    is_view.store(bView);
-    bandwidth.store(bandwidth_in);
-    centerFreq.store(centerFreq_in);
-   
+    is_view = bView;
+    bandwidth = bandwidth_in;
+    centerFreq = centerFreq_in; 
 }
 
 
 void SpectrumVisualProcessor::setFFTAverageRate(float fftAverageRate) {
    
     std::lock_guard < std::mutex > busy_lock(busy_run);    
-    this->fft_average_rate.store(fftAverageRate);
-    
+
+    this->fft_average_rate = fftAverageRate;    
 }
 
 float SpectrumVisualProcessor::getFFTAverageRate() {
-    return this->fft_average_rate.load();
+
+	std::lock_guard < std::mutex > busy_lock(busy_run);
+
+    return this->fft_average_rate;
 }
 
 void SpectrumVisualProcessor::setCenterFrequency(long long centerFreq_in) {
    
-    std::lock_guard < std::mutex > busy_lock(busy_run);    
-    centerFreq.store(centerFreq_in);
-   
+    std::lock_guard < std::mutex > busy_lock(busy_run);  
+
+    centerFreq = centerFreq_in;  
 }
 
 long long SpectrumVisualProcessor::getCenterFrequency() {
-    return centerFreq.load();
+	
+	std::lock_guard < std::mutex > busy_lock(busy_run);
+
+    return centerFreq;
 }
 
 void SpectrumVisualProcessor::setBandwidth(long bandwidth_in) {
    
     std::lock_guard < std::mutex > busy_lock(busy_run);    
-    bandwidth.store(bandwidth_in);
-   
+
+	bandwidth = bandwidth_in;
 }
 
 long SpectrumVisualProcessor::getBandwidth() {
-    return bandwidth.load();
+
+	std::lock_guard < std::mutex > busy_lock(busy_run);
+
+    return bandwidth;
 }
 
 void SpectrumVisualProcessor::setPeakHold(bool peakHold_in) {
-   
-    if (peakHold.load() && peakHold_in) {
-        peakReset.store(PEAK_RESET_COUNT);
+	
+	std::lock_guard < std::mutex > busy_lock(busy_run);
+
+    if (peakHold && peakHold_in) {
+        peakReset = PEAK_RESET_COUNT;
     } else {
-        peakHold.store(peakHold_in);
-        peakReset.store(1);
+        peakHold = peakHold_in;
+        peakReset = 1;
     }
 }
 
 bool SpectrumVisualProcessor::getPeakHold() {
-    return peakHold.load();
+
+	std::lock_guard < std::mutex > busy_lock(busy_run);
+
+    return peakHold;
 }
 
 int SpectrumVisualProcessor::getDesiredInputSize() {
-    return desiredInputSize.load();
+	std::lock_guard < std::mutex > busy_lock(busy_run);
+
+    return desiredInputSize;
 }
 
 void SpectrumVisualProcessor::setup(unsigned int fftSize_in) {
@@ -155,27 +175,37 @@ void SpectrumVisualProcessor::setup(unsigned int fftSize_in) {
         fft_destroy_plan(fftPlan);
     }
     fftPlan = fft_create_plan(fftSizeInternal, fftInput, fftOutput, LIQUID_FFT_FORWARD, 0);
-    
 }
 
 void SpectrumVisualProcessor::setFFTSize(unsigned int fftSize_in) {
+
+	//then get the busy_lock
+	std::lock_guard < std::mutex > busy_lock(busy_run);
+
     if (fftSize_in == fftSize) {
         return;
     }
     newFFTSize = fftSize_in;
-    fftSizeChanged.store(true);
+    fftSizeChanged = true;
 }
 
 unsigned int SpectrumVisualProcessor::getFFTSize() {
-    if (fftSizeChanged.load()) {
+
+	//then get the busy_lock
+	std::lock_guard < std::mutex > busy_lock(busy_run);
+
+    if (fftSizeChanged) {
         return newFFTSize;
     }
-    return fftSize.load();
+    return fftSize;
 }
 
 
 void SpectrumVisualProcessor::setHideDC(bool hideDC) {
-    this->hideDC.store(hideDC);
+
+	std::lock_guard < std::mutex > busy_lock(busy_run);
+
+    this->hideDC = hideDC;
 }
 
 
@@ -187,31 +217,37 @@ void SpectrumVisualProcessor::process() {
         return;
     }
     
-    if (fftSizeChanged.load()) {
-        setup(newFFTSize);
-        fftSizeChanged.store(false);
-    }
-
-    DemodulatorThreadIQData *iqData;
+	bool executeSetup = false;
+
+	{ // scoped lock here
+		std::lock_guard < std::mutex > busy_lock(busy_run);
+		if (fftSizeChanged) {
+			executeSetup = true;
+			fftSizeChanged = false;
+		}
+	}
+
+	if (executeSetup) {
+		setup(newFFTSize);
+	}
+   
+    DemodulatorThreadIQDataPtr iqData;
     
-    input->pop(iqData);
+    if (!input->pop(iqData, HEARTBEAT_CHECK_PERIOD_MICROS)) {
+        return;
+    }
     
     if (!iqData) {
         return;
     }
 
-   
-    //Start by locking concurrent access to iqData
-    std::lock_guard < std::recursive_mutex > lock(iqData->getMonitor());
-
-    //then get the busy_lock
+    //then get the busy_lock for the rest of the processing.
     std::lock_guard < std::mutex > busy_lock(busy_run);    
-
-
    
-    bool doPeak = peakHold.load() && (peakReset.load() == 0);
+    bool doPeak = peakHold && (peakReset == 0);
     
     if (fft_result.size() != fftSizeInternal) {
+
         if (fft_result.capacity() < fftSizeInternal) {
             fft_result.reserve(fftSizeInternal);
             fft_result_ma.reserve(fftSizeInternal);
@@ -225,9 +261,9 @@ void SpectrumVisualProcessor::process() {
         fft_result_peak.resize(fftSizeInternal);
     }
     
-    if (peakReset.load() != 0) {
+    if (peakReset != 0) {
         peakReset--;
-        if (peakReset.load() == 0) {
+        if (peakReset == 0) {
             for (unsigned int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
                 fft_result_peak[i] = fft_floor_maa;
             }
@@ -242,11 +278,10 @@ void SpectrumVisualProcessor::process() {
         unsigned int num_written;
         long resampleBw = iqData->sampleRate;
         bool newResampler = false;
-        int bwDiff;
+        int bwDiff = 0;
         
-        if (is_view.load()) {
+        if (is_view) {
             if (!iqData->sampleRate) {
-                iqData->decRefCount();
                
                 return;
             }
@@ -259,7 +294,7 @@ void SpectrumVisualProcessor::process() {
             
             size_t desired_input_size = fftSizeInternal / resamplerRatio;
             
-            this->desiredInputSize.store(desired_input_size);
+            this->desiredInputSize = desired_input_size;
             
             if (iqData->data.size() < desired_input_size) {
                 //                std::cout << "fft underflow, desired: " << desired_input_size << " actual:" << input->data.size() << std::endl;
@@ -273,7 +308,7 @@ void SpectrumVisualProcessor::process() {
                         shiftFrequency = centerFreq - iqData->frequency;
                         nco_crcf_set_frequency(freqShifter, (2.0 * M_PI) * (((double) abs(shiftFrequency)) / ((double) iqData->sampleRate)));
                         
-                        if (is_view.load()) {
+                        if (is_view) {
                             long freqDiff = shiftFrequency - lastShiftFrequency;
                             
                             if (lastBandwidth!=0) {
@@ -297,7 +332,7 @@ void SpectrumVisualProcessor::process() {
                             }
                         }
                     }
-                    peakReset.store(PEAK_RESET_COUNT);
+                    peakReset = PEAK_RESET_COUNT;
                 }
                 
                 if (shiftBuffer.size() != desired_input_size) {
@@ -329,10 +364,9 @@ void SpectrumVisualProcessor::process() {
                 lastBandwidth = resampleBw;
                 lastInputBandwidth = iqData->sampleRate;
                 newResampler = true;
-                peakReset.store(PEAK_RESET_COUNT);
+                peakReset = PEAK_RESET_COUNT;
             }
-            
-            
+             
             unsigned int out_size = ceil((double) (desired_input_size) * resamplerRatio) + 512;
             
             if (resampleBuffer.size() != out_size) {
@@ -351,7 +385,7 @@ void SpectrumVisualProcessor::process() {
                 memcpy(fftInData, resampleBuffer.data(), fftSizeInternal * sizeof(liquid_float_complex));
             }
         } else {
-            this->desiredInputSize.store(fftSizeInternal);
+            this->desiredInputSize = fftSizeInternal;
 
             num_written = data->size();
             if (data->size() < fftSizeInternal) {
@@ -387,7 +421,7 @@ void SpectrumVisualProcessor::process() {
         }
         
         if (execute) {
-            SpectrumVisualData *output = outputBuffers.getBuffer();
+            SpectrumVisualDataPtr output = outputBuffers.getBuffer();
             
             if (output->spectrum_points.size() != fftSize * 2) {
                 output->spectrum_points.resize(fftSize * 2);
@@ -495,7 +529,7 @@ void SpectrumVisualProcessor::process() {
                 }
             }
             
-            float sf = scaleFactor.load();
+            float sf = scaleFactor;
  
             double visualRatio = (double(bandwidth) / double(resampleBw));
             double visualStart = (double(fftSizeInternal) / 2.0) - (double(fftSizeInternal) * (visualRatio / 2.0));
@@ -541,7 +575,7 @@ void SpectrumVisualProcessor::process() {
                 }
             }
             
-            if (hideDC.load()) { // DC-spike removal
+            if (hideDC) { // DC-spike removal
                 long long freqMin = centerFreq-(bandwidth/2);
                 long long freqMax = centerFreq+(bandwidth/2);
                 long long zeroPt = (iqData->frequency-freqMin);
@@ -597,21 +631,21 @@ void SpectrumVisualProcessor::process() {
 
             distribute(output);
         }
-    }
- 
-    iqData->decRefCount();
-   
+    }  
     
-    lastView = is_view.load();
+    lastView = is_view;
 }
 
 
 void SpectrumVisualProcessor::setScaleFactor(float sf) {
-    scaleFactor.store(sf);
+	std::lock_guard < std::mutex > busy_lock(busy_run);
+
+    scaleFactor = sf;
 }
 
 
 float SpectrumVisualProcessor::getScaleFactor() {
-    return scaleFactor.load();
+	std::lock_guard < std::mutex > busy_lock(busy_run);
+    return scaleFactor;
 }
 
diff --git a/src/process/SpectrumVisualProcessor.h b/src/process/SpectrumVisualProcessor.h
index bef6490..f40069c 100644
--- a/src/process/SpectrumVisualProcessor.h
+++ b/src/process/SpectrumVisualProcessor.h
@@ -6,20 +6,25 @@
 #include "VisualProcessor.h"
 #include "DemodDefs.h"
 #include <cmath>
+#include <memory>
 
 #define SPECTRUM_VZM 2
 #define PEAK_RESET_COUNT 30
 
-class SpectrumVisualData : public ReferenceCounter {
+class SpectrumVisualData {
 public:
     std::vector<float> spectrum_points;
     std::vector<float> spectrum_hold_points;
     double fft_ceiling, fft_floor;
     long long centerFreq;
     int bandwidth;
+
+    virtual ~SpectrumVisualData() {};
 };
 
-typedef ThreadBlockingQueue<SpectrumVisualData *> SpectrumVisualDataQueue;
+typedef std::shared_ptr<SpectrumVisualData> SpectrumVisualDataPtr;
+typedef ThreadBlockingQueue<SpectrumVisualDataPtr> SpectrumVisualDataQueue;
+typedef std::shared_ptr<SpectrumVisualDataQueue> SpectrumVisualDataQueuePtr;
 
 class SpectrumVisualProcessor : public VisualProcessor<DemodulatorThreadIQData, SpectrumVisualData> {
 public:
@@ -56,13 +61,19 @@ protected:
     virtual void process();
     
     ReBuffer<SpectrumVisualData> outputBuffers;
-    std::atomic_bool is_view;
-    std::atomic_uint fftSize, newFFTSize;
-    std::atomic_uint fftSizeInternal;
-    std::atomic_llong centerFreq;
-    std::atomic_long bandwidth;
+  
     
 private:
+	//protects all access to fields below
+	std::mutex busy_run;
+
+	bool is_view;
+	size_t fftSize, newFFTSize;
+	size_t fftSizeInternal;
+	long long centerFreq;
+	size_t bandwidth;
+
+
     long lastInputBandwidth;
     long lastBandwidth;
     bool lastView;
@@ -75,7 +86,7 @@ private:
     double fft_ceil_ma, fft_ceil_maa;
     double fft_floor_ma, fft_floor_maa;
     double fft_ceil_peak, fft_floor_peak;
-    std::atomic<float> fft_average_rate;
+    float fft_average_rate;
     
     std::vector<double> fft_result;
     std::vector<double> fft_result_ma;
@@ -90,11 +101,11 @@ private:
     
     std::vector<liquid_float_complex> shiftBuffer;
     std::vector<liquid_float_complex> resampleBuffer;
-    std::atomic_int desiredInputSize;
+    size_t desiredInputSize;
    
-    std::mutex busy_run;
-    std::atomic_bool hideDC, peakHold;
-    std::atomic_int peakReset;
-    std::atomic<float> scaleFactor;
-    std::atomic_bool fftSizeChanged;
+    
+    bool hideDC, peakHold;
+    int peakReset;
+    float scaleFactor;
+    bool fftSizeChanged;
 };
diff --git a/src/process/VisualProcessor.h b/src/process/VisualProcessor.h
index 7a9ee70..94bb9c7 100644
--- a/src/process/VisualProcessor.h
+++ b/src/process/VisualProcessor.h
@@ -8,29 +8,40 @@
 #include "IOThread.h"
 #include <algorithm>
 #include <vector>
+#include <typeinfo>
 
-template<typename InputDataType = ReferenceCounter, typename OutputDataType = ReferenceCounter>
+template<typename InputDataType, typename OutputDataType>
 class VisualProcessor {
-    //
-    typedef  ThreadBlockingQueue<InputDataType*> VisualInputQueueType;
-    typedef  ThreadBlockingQueue<OutputDataType*> VisualOutputQueueType;
-    typedef typename std::vector< VisualOutputQueueType *>::iterator outputs_i;
+
 public:
-	virtual ~VisualProcessor() {
+    //
+    typedef typename std::shared_ptr<InputDataType> InputDataTypePtr;
+    typedef typename std::shared_ptr<OutputDataType> OutputDataTypePtr;
+
+    typedef  ThreadBlockingQueue<InputDataTypePtr> VisualInputQueueType;
+    typedef  ThreadBlockingQueue<OutputDataTypePtr> VisualOutputQueueType;
 
+    typedef  std::shared_ptr<VisualInputQueueType> VisualInputQueueTypePtr;
+    typedef  std::shared_ptr<VisualOutputQueueType> VisualOutputQueueTypePtr;
+
+	virtual ~VisualProcessor() {
 	}
     
     bool isInputEmpty() {
-        std::lock_guard < std::recursive_mutex > busy_lock(busy_update);
+        std::lock_guard < std::mutex > busy_lock(busy_update);
+		
+		if (input) {
+			return input->empty();
+		}
 
-        return input->empty();
+		return true;
     }
     
     bool isOutputEmpty() {
-        std::lock_guard < std::recursive_mutex > busy_lock(busy_update);
+        std::lock_guard < std::mutex > busy_lock(busy_update);
 
-        for (outputs_i it = outputs.begin(); it != outputs.end(); it++) {
-            if ((*it)->full()) {
+        for (VisualOutputQueueTypePtr single_output :  outputs) {
+            if (single_output->full()) {
                 return false;
             }
         }
@@ -38,10 +49,10 @@ public:
     }
     
     bool isAnyOutputEmpty() {
-        std::lock_guard < std::recursive_mutex > busy_lock(busy_update);
+        std::lock_guard < std::mutex > busy_lock(busy_update);
 
-        for (outputs_i it = outputs.begin();  it != outputs.end(); it++) {
-            if (!(*it)->full()) {
+        for (VisualOutputQueueTypePtr single_output : outputs) {
+            if (!(single_output)->full()) {
                 return true;
             }
         }
@@ -49,45 +60,68 @@ public:
     }
 
     //Set a (new) 'input' queue for incoming data.
-    void setInput(VisualInputQueueType *vis_in) {
-        std::lock_guard < std::recursive_mutex > busy_lock(busy_update);
+    void setInput(VisualInputQueueTypePtr vis_in) {
+        std::lock_guard < std::mutex > busy_lock(busy_update);
         input = vis_in;
         
     }
     
     //Add a vis_out queue where to consumed 'input' data will be
     //dispatched by distribute(). 
-    void attachOutput(VisualOutputQueueType *vis_out) {
+    void attachOutput(VisualOutputQueueTypePtr vis_out) {
         // attach an output queue
-        std::lock_guard < std::recursive_mutex > busy_lock(busy_update);
+        std::lock_guard < std::mutex > busy_lock(busy_update);
         outputs.push_back(vis_out);
     }
     
     //reverse of attachOutput(), removed an existing attached vis_out.
-    void removeOutput(VisualOutputQueueType *vis_out) {
+    void removeOutput(VisualOutputQueueTypePtr vis_out) {
         // remove an output queue
-        std::lock_guard < std::recursive_mutex > busy_lock(busy_update);
+        std::lock_guard < std::mutex > busy_lock(busy_update);
 
-        outputs_i i = std::find(outputs.begin(), outputs.end(), vis_out);
-        if (i != outputs.end()) {
-            outputs.erase(i);
+        auto it = std::find(outputs.begin(), outputs.end(), vis_out);
+        if (it != outputs.end()) {
+            outputs.erase(it);
+        }
+    }
+    //Flush all queues, either input or outputs clearing their accumulated messages.
+    //this is purposefully (almost) non-blocking call.
+    void flushQueues() {
+       
+		//capture a local copy atomically, so we don't need to protect input.
+		VisualInputQueueTypePtr localInput = input;
+
+		if (localInput) {
+			localInput->flush();
+		}
+
+		//scoped-lock: create a local copy of outputs, and work with it.
+		std::vector<VisualOutputQueueTypePtr> local_outputs;
+		{
+			std::lock_guard < std::mutex > busy_lock(busy_update);
+			local_outputs = outputs;
+		}
+
+        for (auto single_output : local_outputs) {
+
+            single_output->flush();
         }
     }
     
     //Call process() repeateadly until all available 'input' data is consumed.
     void run() {
-        
-        std::lock_guard < std::recursive_mutex > busy_lock(busy_update);
+		
+		//capture a local copy atomically, so we don't need to protect input.
+		VisualInputQueueTypePtr localInput = input;
 
-        if (input && !input->empty()) {
+        if (localInput && !localInput->empty()) {
             process();
-        }
-       
+		}
     }
     
 protected:
     // derived class must implement a  process() interface
-    //where typically 'input' data is consummed, procerssed, and then dispatched
+    //where typically 'input' data is consummed, processed, and then dispatched
     //with distribute() to all 'outputs'.
     virtual void process() = 0;
 
@@ -96,58 +130,53 @@ protected:
     //available outputs, previously set by attachOutput().
     //* \param[in] timeout The number of microseconds to wait to push an item in each one of the outputs, 0(default) means indefinite wait.
     //* \param[in] errorMessage an error message written on std::cout in case pf push timeout.
-    void distribute(OutputDataType *item, std::uint64_t timeout = BLOCKING_INFINITE_TIMEOUT, const char* errorMessage = "") {
+    void distribute(OutputDataTypePtr item, std::uint64_t timeout = BLOCKING_INFINITE_TIMEOUT, const char* errorMessage = nullptr) {
       
-        std::lock_guard < std::recursive_mutex > busy_lock(busy_update);
+        std::lock_guard < std::mutex > busy_lock(busy_update);
         //We will try to distribute 'output' among all 'outputs',
-        //so 'output' will a-priori be shared among all 'outputs' so set its ref count to this 
-        //amount.
-        item->setRefCount((int)outputs.size());
-        for (outputs_i it = outputs.begin(); it != outputs.end(); it++) {
-            //if 'output' failed to be given to an outputs_i, dec its ref count accordingly.
-            //blocking push, with a timeout
-        	if (!(*it)->push(item, timeout, errorMessage)) {
-                item->decRefCount();
+        //so 'output' will a-priori be shared among all 'outputs'.
+        
+        for (VisualOutputQueueTypePtr single_output : outputs) {
+            //'output' can fail to be given to an single_output,
+            //using a blocking push, with a timeout
+        	if (!(single_output)->push(item, timeout, errorMessage)) {
+                //trace  will be std::output if timeout != 0 is set and errorMessage != null.
         	} 
         }
-        // Now 'item' refcount matches the times 'item' has been successfully distributed,
-        //i.e shared among the outputs.
     }
 
     //the incoming data queue 
-    VisualInputQueueType *input = nullptr;
+    VisualInputQueueTypePtr input;
     
     //the n-outputs where to process()-ed data is distribute()-ed.
-    std::vector<VisualOutputQueueType *> outputs;
+    std::vector<VisualOutputQueueTypePtr> outputs;
 
-    //protects input and outputs, must be recursive because of re-entrance
-    std::recursive_mutex busy_update;
+    //protects input and outputs
+    std::mutex busy_update;
 };
 
 //Specialization much like VisualDataReDistributor, except 
 //the input (pointer) is directly re-dispatched
 //to outputs, so that all output indeed SHARE the same instance. 
-template<typename OutputDataType = ReferenceCounter>
+template<typename OutputDataType>
 class VisualDataDistributor : public VisualProcessor<OutputDataType, OutputDataType> {
 protected:
+
     virtual void process() {
-        OutputDataType *inp;
+
+        typename VisualProcessor<OutputDataType, OutputDataType>::OutputDataTypePtr inp;
+
         while (VisualProcessor<OutputDataType, OutputDataType>::input->try_pop(inp)) {
             
+			//do not try to distribute if all outputs are already full.
             if (!VisualProcessor<OutputDataType, OutputDataType>::isAnyOutputEmpty()) {
-                if (inp) {
-            	    inp->decRefCount();
-                }
+               
                 return;
             }
       
             if (inp) {
-                int previousRefCount = inp->getRefCount();
             	VisualProcessor<OutputDataType, OutputDataType>::distribute(inp);
-                //inp is now shared through the distribute(), which overwrite the previous ref count,
-                //so increment it properly.
-                int distributeRefCount = inp->getRefCount();
-                inp->setRefCount(previousRefCount + distributeRefCount);
+                //inp is now shared through the distribute() call.
             }
         }
     }
@@ -155,27 +184,39 @@ protected:
 
 //specialization class which process() take an input item and re-dispatch
 //A COPY to every outputs, without further processing. This is a 1-to-n dispatcher. 
-template<typename OutputDataType = ReferenceCounter>
+template<typename OutputDataType>
 class VisualDataReDistributor : public VisualProcessor<OutputDataType, OutputDataType> {
+
 protected:
+
+    VisualDataReDistributor() : buffers (std::string(typeid(*this).name())) {
+
+    }
+
+    ReBuffer<OutputDataType> buffers;
+
     virtual void process() {
-        OutputDataType *inp;
+
+        typename VisualProcessor<OutputDataType, OutputDataType>::OutputDataTypePtr inp;
+
         while (VisualProcessor<OutputDataType, OutputDataType>::input->try_pop(inp)) {
             
+			//do not try to distribute if all outputs are already full.
             if (!VisualProcessor<OutputDataType, OutputDataType>::isAnyOutputEmpty()) {
-                if (inp) {
-            	    inp->decRefCount();
-                }
+               
                 return;
             }
             
             if (inp) {
-                OutputDataType *outp = buffers.getBuffer();
+
+                typename VisualProcessor<OutputDataType, OutputDataType>::OutputDataTypePtr outp = buffers.getBuffer();
+
+                //'deep copy' of the contents 
                 (*outp) = (*inp);
-                inp->decRefCount();
+  
                 VisualProcessor<OutputDataType, OutputDataType>::distribute(outp);
             }
         }
     }
-    ReBuffer<OutputDataType> buffers;
+    
 };
diff --git a/src/rig/RigThread.cpp b/src/rig/RigThread.cpp
index 7bdcf4b..29ba0aa 100644
--- a/src/rig/RigThread.cpp
+++ b/src/rig/RigThread.cpp
@@ -73,8 +73,8 @@ void RigThread::run() {
     while (!stopping) {
         std::this_thread::sleep_for(std::chrono::milliseconds(150));
         
-        DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getActiveDemodulator();
-        DemodulatorInstance *lastDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
+        auto activeDemod = wxGetApp().getDemodMgr().getActiveDemodulator();
+        auto lastDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
 
         if (freqChanged.load() && (controlMode.load() || setOneShot.load())) {
             status = rig_get_freq(rig, RIG_VFO_CURR, &freq);
diff --git a/src/sdr/SDRDeviceInfo.cpp b/src/sdr/SDRDeviceInfo.cpp
index e79b77d..2dbaf03 100644
--- a/src/sdr/SDRDeviceInfo.cpp
+++ b/src/sdr/SDRDeviceInfo.cpp
@@ -2,6 +2,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 
 #include "SDRDeviceInfo.h"
+#include "CubicSDRDefs.h"
 #include <cstdlib>
 #include <algorithm>
 
@@ -179,15 +180,64 @@ bool SDRDeviceInfo::hasCORR(int direction, size_t channel) {
 }
 
 std::vector<long> SDRDeviceInfo::getSampleRates(int direction, size_t channel) {
+
     SoapySDR::Device *dev = getSoapyDevice();
+
+	size_t nbMaxDifferentRates = DEVICE_SAMPLE_RATES_MAX_NB;
     
     std::vector<long> result;
+
+	//the original list returned from the driver:
     std::vector<double> sampleRates = dev->listSampleRates(direction, channel);
-    for (std::vector<double>::iterator si = sampleRates.begin(); si != sampleRates.end(); si++) {
-        result.push_back((long)(*si));
+
+	//be paranoid, sort by increasing rates...
+	std::sort(sampleRates.begin(), sampleRates.end(), [](double a, double b) -> bool { return a < b; });
+
+	//if sampleRates.size() > nbMaxDifferentRates, decimate this number to only return nbMaxDifferentRates sample 
+	//rates values.
+	size_t sampleRateSelectionStep = 1;
+
+	if (sampleRates.size() / nbMaxDifferentRates >= 2) {
+
+	   sampleRateSelectionStep = sampleRates.size() / nbMaxDifferentRates;
+	}
+	
+	for (size_t i = 0; sampleRateSelectionStep * i < sampleRates.size(); i++) {
+
+		//convert to longs...
+		result.push_back((long)sampleRates[sampleRateSelectionStep * i]);
+	}
+
+	//always include the biggest value:
+	if ((long)sampleRates.back() > result.back()) {
+
+		result.push_back((long)sampleRates.back());
+	}
+
+    return result;
+}
+
+std::vector<std::string> SDRDeviceInfo::getAntennaNames(int direction, size_t channel) {
+
+    SoapySDR::Device *dev = getSoapyDevice();
+
+    if (dev) {
+
+        return  dev->listAntennas(direction, channel);
     }
+
+    return std::vector<std::string>(); 
+}
+
+std::string SDRDeviceInfo::getAntennaName(int direction, size_t channel) {
+    SoapySDR::Device *dev = getSoapyDevice();
     
-    return result;
+    if (dev) {
+        return  dev->getAntenna(direction, channel);
+    }
+
+    return std::string("");
+
 }
 
 long SDRDeviceInfo::getSampleRateNear(int direction, size_t channel, long sampleRate_in) {
@@ -195,11 +245,11 @@ long SDRDeviceInfo::getSampleRateNear(int direction, size_t channel, long sample
     long returnRate = sampleRates[0];
     long sDelta = (long)sampleRate_in-sampleRates[0];
     long minDelta = std::abs(sDelta);
-    for (std::vector<long>::iterator i = sampleRates.begin(); i != sampleRates.end(); i++) {
-        long thisDelta = std::abs(sampleRate_in - (*i));
+    for (long i : sampleRates) {
+        long thisDelta = std::abs(sampleRate_in - i);
         if (thisDelta < minDelta) {
             minDelta = thisDelta;
-            returnRate = (*i);
+            returnRate = i;
         }
     }
     return returnRate;
@@ -207,12 +257,36 @@ long SDRDeviceInfo::getSampleRateNear(int direction, size_t channel, long sample
 
 SDRRangeMap SDRDeviceInfo::getGains(int direction, size_t channel) {
     SoapySDR::Device *dev = getSoapyDevice();
-    std::vector<std::string> gainNames = dev->listGains(direction, channel);
-    std::map<std::string, SoapySDR::Range> gainMap;
     
-    for (std::vector<std::string>::iterator gname = gainNames.begin(); gname!= gainNames.end(); gname++) {
-        gainMap[(*gname)] = dev->getGainRange(direction, channel, (*gname));
+	std::vector<std::string> gainNames = dev->listGains(direction, channel);
+    
+	std::map<std::string, SoapySDR::Range> gainMap;
+    
+    for (std::string gname : gainNames) {
+
+        gainMap[gname] = dev->getGainRange(direction, channel, gname);
     }
     
     return gainMap;
 }
+
+//read the current gain of name gainName (must exit in getGains(), else return 0)
+//in the device.
+double  SDRDeviceInfo::getCurrentGain(int direction, size_t channel, const std::string& gainName) {
+
+	SoapySDR::Device *dev = getSoapyDevice();
+
+	if (dev) {
+
+		std::vector<std::string> gainNames = dev->listGains(direction, channel);
+
+		auto itFoundName = std::find(gainNames.begin(), gainNames.end(), gainName);
+
+		if (itFoundName != gainNames.end()) {
+
+			return  dev->getGain(direction, channel, gainName);
+		}
+	}
+
+	return 0.0;
+}
diff --git a/src/sdr/SDRDeviceInfo.h b/src/sdr/SDRDeviceInfo.h
index cc903c1..622d56f 100644
--- a/src/sdr/SDRDeviceInfo.h
+++ b/src/sdr/SDRDeviceInfo.h
@@ -83,11 +83,19 @@ public:
     bool hasCORR(int direction, size_t channel);
     
     std::vector<long> getSampleRates(int direction, size_t channel);
+
+    std::vector<std::string> getAntennaNames(int direction, size_t channel);
+
+    std::string getAntennaName(int direction, size_t channel);
     
     long getSampleRateNear(int direction, size_t channel, long sampleRate_in);
 
     SDRRangeMap getGains(int direction, size_t channel);
 
+	//read the current gain of name gainName (must exist in getGains(), else return 0)
+	//in the device.
+	double getCurrentGain(int direction, size_t channel, const std::string& gainName);
+
 private:
     int index = 0;
     std::string name, serial, product, manufacturer, tuner;
diff --git a/src/sdr/SDREnumerator.cpp b/src/sdr/SDREnumerator.cpp
index a7680c0..2feff22 100644
--- a/src/sdr/SDREnumerator.cpp
+++ b/src/sdr/SDREnumerator.cpp
@@ -90,22 +90,22 @@ std::vector<SDRDeviceInfo *> *SDREnumerator::enumerate_devices(std::string remot
     }
     
     if (!soapy_initialized) {
-        std::cout << "SoapySDR init.." << std::endl;
-        std::cout << "\tAPI Version: v" << SoapySDR::getAPIVersion() << std::endl;
-        std::cout << "\tABI Version: v" << SoapySDR::getABIVersion() << std::endl;
-        std::cout << "\tInstall root: " << SoapySDR::getRootPath() << std::endl;
+        std::cout << "SoapySDR init.." << std::endl << std::flush;
+        std::cout << "\tAPI Version: v" << SoapySDR::getAPIVersion() << std::endl << std::flush;
+        std::cout << "\tABI Version: v" << SoapySDR::getABIVersion() << std::endl << std::flush;
+        std::cout << "\tInstall root: " << SoapySDR::getRootPath() << std::endl << std::flush;
         
-        std::cout << "\tLoading modules... " << std::endl;
+        std::cout << "\tLoading modules... " << std::endl << std::flush;
         
         std::string userModPath = wxGetApp().getModulePath();
         
         if (userModPath != "") {
             wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "Loading SoapySDR modules from " + userModPath + "..");
             std::vector<std::string> localMods = SoapySDR::listModules(userModPath);
-            for (std::vector<std::string>::iterator mods_i = localMods.begin(); mods_i != localMods.end(); mods_i++) {
-                wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "Initializing user specified SoapySDR module " + (*mods_i) + "..");
-                std::cout << "Initializing user specified SoapySDR module " << (*mods_i) <<  ".." << std::endl;
-                SoapySDR::loadModule(*mods_i);
+            for (std::string mod : localMods) {
+                wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "Initializing user specified SoapySDR module " + (mod) + "..");
+                std::cout << "Initializing user specified SoapySDR module " << (mod) <<  ".." << std::endl << std::flush;
+                SoapySDR::loadModule(mod);
             }
         } else {
             #ifdef BUNDLE_SOAPY_MODS
@@ -114,28 +114,28 @@ std::vector<SDRDeviceInfo *> *SDREnumerator::enumerate_devices(std::string remot
 			std::vector<std::string> localMods = SoapySDR::listModules(exePath.GetPath().ToStdString() + "/modules/");
 			for (std::vector<std::string>::iterator mods_i = localMods.begin(); mods_i != localMods.end(); mods_i++) {
 				wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "Initializing bundled SoapySDR module " + (*mods_i) + "..");
-				std::cout << "Loading bundled SoapySDR module " << (*mods_i) << ".." << std::endl;
+				std::cout << "Loading bundled SoapySDR module " << (*mods_i) << ".." << std::endl << std::flush;
 				SoapySDR::loadModule(*mods_i);
 			}
 			#else
             bool localModPref = wxGetApp().getUseLocalMod();
             if (localModPref) {
                 wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "Loading SoapySDR modules..");
-                std::cout << "Checking local system SoapySDR modules.." << std::flush;
+                std::cout << "Checking local system SoapySDR modules.." << std::endl << std::flush;
                 SoapySDR::loadModules();
             }
 
             wxFileName exePath = wxFileName(wxStandardPaths::Get().GetExecutablePath());
             std::vector<std::string> localMods = SoapySDR::listModules(exePath.GetPath().ToStdString() + "/modules/");
-            for (std::vector<std::string>::iterator mods_i = localMods.begin(); mods_i != localMods.end(); mods_i++) {
-                wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "Initializing bundled SoapySDR module " + (*mods_i) + "..");
-                std::cout << "Loading bundled SoapySDR module " << (*mods_i) <<  ".." << std::endl;
-                SoapySDR::loadModule(*mods_i);
+            for (std::string mod : localMods) {
+                wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "Initializing bundled SoapySDR module " + (mod) + "..");
+                std::cout << "Loading bundled SoapySDR module " << (mod) <<  ".." << std::endl << std::flush;
+                SoapySDR::loadModule(mod);
             }
         
             if (!localModPref) {
                 wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "Loading SoapySDR modules..");
-                std::cout << "Checking system SoapySDR modules.." << std::flush;
+                std::cout << "Checking system SoapySDR modules.."  << std::endl << std::flush;
                 SoapySDR::loadModules();
             }
 			#endif
@@ -146,9 +146,8 @@ std::vector<SDRDeviceInfo *> *SDREnumerator::enumerate_devices(std::string remot
 
         }
         
-        if (SDREnumerator::factories.size()) {
-            SDREnumerator::factories.erase(SDREnumerator::factories.begin(), SDREnumerator::factories.end());
-        }
+		SDREnumerator::factories.clear();
+       
         
         std::cout << "\tAvailable factories...";
         SoapySDR::FindFunctions factories = SoapySDR::Registry::listFindFunctions();
@@ -275,6 +274,7 @@ std::vector<SDRDeviceInfo *> *SDREnumerator::enumerate_devices(std::string remot
 
             ConfigSettings devSettings = cfg->getSettings();
             if (devSettings.size()) {
+				// Load the saved device settings to deviceArgs, and back to settingsInfo.
                 for (ConfigSettings::const_iterator set_i = devSettings.begin(); set_i != devSettings.end(); set_i++) {
                     deviceArgs[set_i->first] = set_i->second;
                 }
@@ -318,10 +318,10 @@ void SDREnumerator::run() {
     SDREnumerator::enumerate_devices("");
 
     if (remotes.size()) {
-        std::vector<std::string>::iterator remote_i;
-        for (remote_i = remotes.begin(); remote_i != remotes.end(); remote_i++) {
-            wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "Scanning devices at " + (*remote_i) + ", please wait..");
-            SDREnumerator::enumerate_devices(*remote_i);
+      
+        for (std::string remote : remotes) {
+            wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "Scanning devices at " + (remote) + ", please wait..");
+            SDREnumerator::enumerate_devices(remote);
         }
     }
     
@@ -400,15 +400,17 @@ bool SDREnumerator::hasRemoteModule() {
 
 void SDREnumerator::reset() {
     soapy_initialized = false;
-    factories.erase(factories.begin(), factories.end());
-    modules.erase(modules.begin(), modules.end());
+	factories.clear(); 
+    modules.clear();
+
     for (std::map< std::string, std::vector<SDRDeviceInfo *> >::iterator di = devs.begin(); di != devs.end(); di++) {
+
         for (std::vector<SDRDeviceInfo *>::iterator i = di->second.begin(); i != di->second.end(); i++) {
             (*i)->setSoapyDevice(nullptr);
         }
         
     }
-    devs.erase(devs.begin(), devs.end());
+    devs.clear();
 }
 
 std::vector<std::string> &SDREnumerator::getFactories() {
diff --git a/src/sdr/SDRPostThread.cpp b/src/sdr/SDRPostThread.cpp
index afefd60..42919b2 100644
--- a/src/sdr/SDRPostThread.cpp
+++ b/src/sdr/SDRPostThread.cpp
@@ -7,17 +7,20 @@
 
 #include <vector>
 #include <deque>
+#include <memory>
+
+//50 ms
+#define HEARTBEAT_CHECK_PERIOD_MICROS (50 * 1000) 
 
 SDRPostThread::SDRPostThread() : IOThread(), buffers("SDRPostThreadBuffers"), visualDataBuffers("SDRPostThreadVisualDataBuffers"), frequency(0) {
-    iqDataInQueue = NULL;
-    iqDataOutQueue = NULL;
-    iqVisualQueue = NULL;
+    iqDataInQueue = nullptr;
+    iqDataOutQueue = nullptr;
+    iqVisualQueue = nullptr;
 
     numChannels = 0;
-    channelizer = NULL;
+    channelizer = nullptr;
     
     sampleRate = 0;
-    nRunDemods = 0;
     
     visFrequency.store(0);
     visBandwidth.store(0);
@@ -29,44 +32,12 @@ SDRPostThread::SDRPostThread() : IOThread(), buffers("SDRPostThreadBuffers"), vi
 SDRPostThread::~SDRPostThread() {
 }
 
-void SDRPostThread::bindDemodulator(DemodulatorInstance *demod) {
-    
-    std::lock_guard < std::mutex > lock(busy_demod);
-
-    demodulators.push_back(demod);
+void SDRPostThread::notifyDemodulatorsChanged() {
+  
     doRefresh.store(true);
    
 }
 
-void SDRPostThread::bindDemodulators(std::vector<DemodulatorInstance *> *demods) {
-    if (!demods) {
-        return;
-    }
-    std::lock_guard < std::mutex > lock(busy_demod);
-
-    for (std::vector<DemodulatorInstance *>::iterator di = demods->begin(); di != demods->end(); di++) {
-        demodulators.push_back(*di);
-        doRefresh.store(true);
-    }
-   
-}
-
-void SDRPostThread::removeDemodulator(DemodulatorInstance *demod) {
-    if (!demod) {
-        return;
-    }
-
-    std::lock_guard < std::mutex > lock(busy_demod);
-
-    std::vector<DemodulatorInstance *>::iterator i = std::find(demodulators.begin(), demodulators.end(), demod);
-    
-    if (i != demodulators.end()) {
-        demodulators.erase(i);
-        doRefresh.store(true);
-    }
-  
-}
-
 void SDRPostThread::initPFBChannelizer() {
 //    std::cout << "Initializing post-process FIR polyphase filterbank channelizer with " << numChannels << " channels." << std::endl;
     if (channelizer) {
@@ -84,16 +55,17 @@ void SDRPostThread::initPFBChannelizer() {
 
 void SDRPostThread::updateActiveDemodulators() {
     // In range?
-    std::vector<DemodulatorInstance *>::iterator demod_i;
-    
-    nRunDemods = 0;
-    
+   
+    runDemods.clear();
+    demodChannel.clear();
+
     long long centerFreq = wxGetApp().getFrequency();
 
-    for (demod_i = demodulators.begin(); demod_i != demodulators.end(); demod_i++) {
-        DemodulatorInstance *demod = *demod_i;
-        DemodulatorThreadInputQueue *demodQueue = demod->getIQInputDataPipe();
-        
+    //retreive the current list of demodulators:
+    auto demodulators = wxGetApp().getDemodMgr().getDemodulators();
+   
+    for (auto demod : demodulators) {
+            
         // not in range?
         if (demod->isDeltaLock()) {
             if (demod->getFrequency() != centerFreq + demod->getDeltaLockOfs()) {
@@ -106,9 +78,14 @@ void SDRPostThread::updateActiveDemodulators() {
         
         if (abs(frequency - demod->getFrequency()) > (sampleRate / 2)) {
             // deactivate if active
-            if (demod->isActive() && !demod->isFollow() && !demod->isTracking()) {
+           
+            if (wxGetApp().getDemodMgr().getLastActiveDemodulator() == demod) {
+
                 demod->setActive(false);
             }
+            else if (demod->isActive() && !demod->isFollow() && !demod->isTracking()) {
+                demod->setActive(false);
+            } 
             
             // follow if follow mode
             if (demod->isFollow() && centerFreq != demod->getFrequency()) {
@@ -117,7 +94,7 @@ void SDRPostThread::updateActiveDemodulators() {
             }
         } else if (!demod->isActive()) { // in range, activate if not activated
             demod->setActive(true);
-            if (wxGetApp().getDemodMgr().getLastActiveDemodulator() == NULL) {
+            if (wxGetApp().getDemodMgr().getLastActiveDemodulator() == nullptr) {
 
                 wxGetApp().getDemodMgr().setActiveDemodulator(demod);
             }
@@ -127,16 +104,25 @@ void SDRPostThread::updateActiveDemodulators() {
             continue;
         }
         
-        // Add to the current run
-        if (nRunDemods == runDemods.size()) {
-            runDemods.push_back(demod);
-            demodChannel.push_back(-1);
-        } else {
-            runDemods[nRunDemods] = demod;
-            demodChannel[nRunDemods] = -1;
-        }
-        nRunDemods++;
+        // Add active demods to the current run:
+
+        runDemods.push_back(demod);
+        demodChannel.push_back(-1);
+    }
+}
+
+void SDRPostThread::resetAllDemodulators() {
+    
+    //retreive the current list of demodulators:
+    auto demodulators = wxGetApp().getDemodMgr().getDemodulators();
+
+    for (auto demod : demodulators) {
+
+        demod->setActive(false);
+        demod->getIQInputDataPipe()->flush();
     }
+
+    doRefresh = true;
 }
 
 void SDRPostThread::updateChannels() {
@@ -177,62 +163,57 @@ void SDRPostThread::run() {
 
 //    std::cout << "SDR post-processing thread started.." << std::endl;
 
-    iqDataInQueue = static_cast<SDRThreadIQDataQueue*>(getInputQueue("IQDataInput"));
-    iqDataOutQueue = static_cast<DemodulatorThreadInputQueue*>(getOutputQueue("IQDataOutput"));
-    iqVisualQueue = static_cast<DemodulatorThreadInputQueue*>(getOutputQueue("IQVisualDataOutput"));
-    iqActiveDemodVisualQueue = static_cast<DemodulatorThreadInputQueue*>(getOutputQueue("IQActiveDemodVisualDataOutput"));
+    iqDataInQueue = std::static_pointer_cast<SDRThreadIQDataQueue>(getInputQueue("IQDataInput"));
+    iqDataOutQueue = std::static_pointer_cast<DemodulatorThreadInputQueue>(getOutputQueue("IQDataOutput"));
+    iqVisualQueue = std::static_pointer_cast<DemodulatorThreadInputQueue>(getOutputQueue("IQVisualDataOutput"));
+    iqActiveDemodVisualQueue = std::static_pointer_cast<DemodulatorThreadInputQueue>(getOutputQueue("IQActiveDemodVisualDataOutput"));
     
     while (!stopping) {
-        SDRThreadIQData *data_in;
+        SDRThreadIQDataPtr data_in;
         
-        iqDataInQueue->pop(data_in);
-        //        std::lock_guard < std::mutex > lock(data_in->m_mutex);
-
-        std::lock_guard < std::mutex > lock(busy_demod);
+        if (!iqDataInQueue->pop(data_in, HEARTBEAT_CHECK_PERIOD_MICROS)) {
+            continue;
+        }
+         
+        bool doUpdate = false;
 
         if (data_in && data_in->data.size()) {
             if(data_in->numChannels > 1) {
-                runPFBCH(data_in);
+                runPFBCH(data_in.get());
             } else {
-                runSingleCH(data_in);
+                runSingleCH(data_in.get());
             }
         }
-
-        if (data_in) {
-            data_in->decRefCount();   
-        }
-
-        bool doUpdate = false;
-        for (size_t j = 0; j < nRunDemods; j++) {
-            DemodulatorInstance *demod = runDemods[j];
+        
+        for (size_t j = 0; j < runDemods.size(); j++) {
+            DemodulatorInstancePtr demod = runDemods[j];
             if (abs(frequency - demod->getFrequency()) > (sampleRate / 2)) {
                 doUpdate = true;
             }
         }
         
         //Only update the list of demodulators here
-        if (doUpdate) {
+        if (doUpdate || doRefresh) {
             updateActiveDemodulators();
         }
     } //end while
     
     //Be safe, remove as many elements as possible
-    DemodulatorThreadIQData *visualDataDummy;
-    while (iqVisualQueue && iqVisualQueue->try_pop(visualDataDummy)) {
-        visualDataDummy->decRefCount();        
-    }
-
-    //    buffers.purge();
-    //    visualDataBuffers.purge();
+    iqVisualQueue->flush();   
+    iqDataInQueue->flush();
+    iqDataOutQueue->flush();
+    iqActiveDemodVisualQueue->flush();
 
 //    std::cout << "SDR post-processing thread done." << std::endl;
 }
 
 void SDRPostThread::terminate() {
     IOThread::terminate();
-    SDRThreadIQData *dummy = new SDRThreadIQData;
-    //VSO: blocking push
-    iqDataInQueue->push(dummy);
+    //unblock push()
+    iqVisualQueue->flush();
+    iqDataInQueue->flush();
+    iqDataOutQueue->flush();
+    iqActiveDemodVisualQueue->flush();
 }
 
 void SDRPostThread::runSingleCH(SDRThreadIQData *data_in) {
@@ -262,10 +243,10 @@ void SDRPostThread::runSingleCH(SDRThreadIQData *data_in) {
         doRefresh.store(false);
     }
     
-    size_t refCount = nRunDemods;
-    bool doIQDataOut = (iqDataOutQueue != NULL && !iqDataOutQueue->full());
-    bool doDemodVisOut = (nRunDemods && iqActiveDemodVisualQueue != NULL && !iqActiveDemodVisualQueue->full());
-    bool doVisOut = (iqVisualQueue != NULL && !iqVisualQueue->full());
+    size_t refCount = runDemods.size();
+    bool doIQDataOut = (iqDataOutQueue != nullptr && !iqDataOutQueue->full());
+    bool doDemodVisOut = (runDemods.size() > 0 && iqActiveDemodVisualQueue != nullptr && !iqActiveDemodVisualQueue->full());
+    bool doVisOut = (iqVisualQueue != nullptr && !iqVisualQueue->full());
     
     if (doIQDataOut) {
         refCount++;
@@ -278,8 +259,8 @@ void SDRPostThread::runSingleCH(SDRThreadIQData *data_in) {
     }
     
     if (refCount) {
-        DemodulatorThreadIQData *demodDataOut = buffers.getBuffer();
-        demodDataOut->setRefCount(refCount);
+        DemodulatorThreadIQDataPtr demodDataOut = buffers.getBuffer();
+
         demodDataOut->frequency = frequency;
         demodDataOut->sampleRate = sampleRate;
         
@@ -307,9 +288,15 @@ void SDRPostThread::runSingleCH(SDRThreadIQData *data_in) {
             iqVisualQueue->push(demodDataOut);
         }
         
-        for (size_t i = 0; i < nRunDemods; i++) {
-            //VSO: blocking push
-            runDemods[i]->getIQInputDataPipe()->push(demodDataOut);
+        for (size_t i = 0; i < runDemods.size(); i++) {
+            // try-push() : we do our best to only stimulate active demods, but some could happen to be dead, full, or indeed non-active.
+            //so in short never block here no matter what.
+            if (!runDemods[i]->getIQInputDataPipe()->try_push(demodDataOut)) {
+
+             //   std::cout << "SDRPostThread::runSingleCH() attempt to push into demod '" << runDemods[i]->getLabel()
+             //       << "' (" << runDemods[i]->getFrequency() << " Hz) failed, demod is either too busy, not-active, or dead..." << std::endl << std::flush;
+                std::this_thread::yield();
+            }
         }
     }
 }
@@ -332,17 +319,15 @@ void SDRPostThread::runPFBCH(SDRThreadIQData *data_in) {
         dataOut.resize(outSize);
     }
     
-    if (iqDataOutQueue != NULL && !iqDataOutQueue->full()) {
-        DemodulatorThreadIQData *iqDataOut = visualDataBuffers.getBuffer();
+    if (iqDataOutQueue != nullptr && !iqDataOutQueue->full()) {
+        DemodulatorThreadIQDataPtr iqDataOut = visualDataBuffers.getBuffer();
         
         bool doVis = false;
         
-        if (iqVisualQueue != NULL && !iqVisualQueue->full()) {
+        if (iqVisualQueue != nullptr && !iqVisualQueue->full()) {
             doVis = true;
         }
         
-        iqDataOut->setRefCount(1 + (doVis?1:0));
-        
         iqDataOut->frequency = data_in->frequency;
         iqDataOut->sampleRate = data_in->sampleRate;
         iqDataOut->data.assign(data_in->data.begin(), data_in->data.begin() + dataSize);
@@ -367,11 +352,11 @@ void SDRPostThread::runPFBCH(SDRThreadIQData *data_in) {
         doRefresh.store(false);
     }
     
-    DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
+    DemodulatorInstancePtr activeDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
     int activeDemodChannel = -1;
     
     // Find active demodulators
-    if (nRunDemods) {
+    if (runDemods.size() > 0) {
         
         // channelize data
         // firpfbch output rate is (input rate / channels)
@@ -384,15 +369,15 @@ void SDRPostThread::runPFBCH(SDRThreadIQData *data_in) {
         }
         
         // Find nearest channel for each demodulator
-        for (size_t i = 0; i < nRunDemods; i++) {
-            DemodulatorInstance *demod = runDemods[i];
+        for (size_t i = 0; i < runDemods.size(); i++) {
+            DemodulatorInstancePtr demod = runDemods[i];
             demodChannel[i] = getChannelAt(demod->getFrequency());
             if (demod == activeDemod) {
                 activeDemodChannel = demodChannel[i];
             }
         }
         
-        for (size_t i = 0; i < nRunDemods; i++) {
+        for (size_t i = 0; i < runDemods.size(); i++) {
             // cache channel usage refcounts
             if (demodChannel[i] >= 0) {
                 demodChannelActive[demodChannel[i]]++;
@@ -401,14 +386,13 @@ void SDRPostThread::runPFBCH(SDRThreadIQData *data_in) {
         
         // Run channels
         for (int i = 0; i < numChannels+1; i++) {
-            int doDemodVis = ((activeDemodChannel == i) && (iqActiveDemodVisualQueue != NULL) && !iqActiveDemodVisualQueue->full())?1:0;
+            int doDemodVis = ((activeDemodChannel == i) && (iqActiveDemodVisualQueue != nullptr) && !iqActiveDemodVisualQueue->full())?1:0;
             
             if (!doDemodVis && demodChannelActive[i] == 0) {
                 continue;
             }
             
-            DemodulatorThreadIQData *demodDataOut = buffers.getBuffer();
-            demodDataOut->setRefCount(demodChannelActive[i] + doDemodVis);
+            DemodulatorThreadIQDataPtr demodDataOut = buffers.getBuffer();
             demodDataOut->frequency = chanCenters[i];
             demodDataOut->sampleRate = chanBw;
             
@@ -452,13 +436,18 @@ void SDRPostThread::runPFBCH(SDRThreadIQData *data_in) {
                 iqActiveDemodVisualQueue->push(demodDataOut);
             }
             
-            for (size_t j = 0; j < nRunDemods; j++) {
+            for (size_t j = 0; j < runDemods.size(); j++) {
                 if (demodChannel[j] == i) {
-                    DemodulatorInstance *demod = runDemods[j];
-                    //VSO: blocking push
-                    demod->getIQInputDataPipe()->push(demodDataOut);
+                    
+                    // try-push() : we do our best to only stimulate active demods, but some could happen to be dead, full, or indeed non-active.
+                    //so in short never block here no matter what.
+                    if (!runDemods[j]->getIQInputDataPipe()->try_push(demodDataOut)) {
+                    //    std::cout << "SDRPostThread::runPFBCH() attempt to push into demod '" << runDemods[i]->getLabel()
+                    //        << "' (" << runDemods[i]->getFrequency() << " Hz) failed, demod is either too busy, not-active, or dead..." << std::endl << std::flush;
+                        std::this_thread::yield();
+                    }
                 }
-            }
+            } //end for
         }
     }
 }
diff --git a/src/sdr/SDRPostThread.h b/src/sdr/SDRPostThread.h
index 2f7ad3e..2725901 100644
--- a/src/sdr/SDRPostThread.h
+++ b/src/sdr/SDRPostThread.h
@@ -11,10 +11,8 @@ public:
     SDRPostThread();
     ~SDRPostThread();
 
-    void bindDemodulator(DemodulatorInstance *demod);
-    void bindDemodulators(std::vector<DemodulatorInstance *> *demods);
-    void removeDemodulator(DemodulatorInstance *demod);
-    
+    void notifyDemodulatorsChanged();
+   
     virtual void run();
     virtual void terminate();
 
@@ -23,16 +21,10 @@ public:
     void setIQVisualRange(long long frequency, int bandwidth);
         
 protected:
-    SDRThreadIQDataQueue *iqDataInQueue;
-    DemodulatorThreadInputQueue *iqDataOutQueue;
-    DemodulatorThreadInputQueue *iqVisualQueue;
-    DemodulatorThreadInputQueue *iqActiveDemodVisualQueue;
-    
-    //protects access to demodulators lists and such
-    std::mutex busy_demod;
-    std::vector<DemodulatorInstance *> demodulators;
-
-    
+    SDRThreadIQDataQueuePtr iqDataInQueue;
+    DemodulatorThreadInputQueuePtr iqDataOutQueue;
+    DemodulatorThreadInputQueuePtr iqVisualQueue;
+    DemodulatorThreadInputQueuePtr iqActiveDemodVisualQueue;
 
 private:
 
@@ -41,14 +33,15 @@ private:
     void updateChannels();
     int getChannelAt(long long frequency);
 
+    void resetAllDemodulators();
+
     ReBuffer<DemodulatorThreadIQData> buffers;
     std::vector<liquid_float_complex> fpData;
     std::vector<liquid_float_complex> dataOut;
     std::vector<long long> chanCenters;
     long long chanBw = 0;
     
-    size_t nRunDemods;
-    std::vector<DemodulatorInstance *> runDemods;
+    std::vector<DemodulatorInstancePtr> runDemods;
     std::vector<int> demodChannel;
     std::vector<int> demodChannelActive;
 
diff --git a/src/sdr/SoapySDRThread.cpp b/src/sdr/SoapySDRThread.cpp
index bc509e0..3ca5f7b 100644
--- a/src/sdr/SoapySDRThread.cpp
+++ b/src/sdr/SoapySDRThread.cpp
@@ -6,14 +6,17 @@
 #include <vector>
 #include "CubicSDR.h"
 #include <string>
+#include <algorithm>
 #include <SoapySDR/Logger.h>
+#include <chrono>
 
+#define TARGET_DISPLAY_FPS 60
 
 SDRThread::SDRThread() : IOThread(), buffers("SDRThreadBuffers") {
-    device = NULL;
+    device = nullptr;
 
-    deviceConfig.store(NULL);
-    deviceInfo.store(NULL);
+    deviceConfig.store(nullptr);
+    deviceInfo.store(nullptr);
 
     sampleRate.store(DEFAULT_SAMPLE_RATE);
     frequency.store(0);
@@ -25,6 +28,7 @@ SDRThread::SDRThread() : IOThread(), buffers("SDRThreadBuffers") {
     rate_changed.store(false);
     freq_changed.store(false);
     offset_changed.store(false);
+    antenna_changed.store(false);
     ppm_changed .store(false);
     device_changed.store(false);
 
@@ -98,7 +102,7 @@ bool SDRThread::init() {
     int streamMTU = device->getStreamMTU(stream);
     mtuElems.store(streamMTU);
     
-    std::cout << "Stream MTU: " << mtuElems.load() << std::endl << std::flush;
+    std::cout << "Device Stream MTU: " << mtuElems.load() << std::endl << std::flush;
     
     deviceInfo.load()->setStreamArgs(currentStreamArgs);
     deviceConfig.load()->setStreamOpts(currentStreamArgs);
@@ -130,11 +134,12 @@ bool SDRThread::init() {
     device->setGainMode(SOAPY_SDR_RX,0,agc_mode.load());
     
     numChannels.store(getOptimalChannelCount(sampleRate.load()));
-    numElems.store(getOptimalElementCount(sampleRate.load(), 30));
+    numElems.store(getOptimalElementCount(sampleRate.load(), TARGET_DISPLAY_FPS));
+    //fallback if  mtuElems was wrong.
     if (!mtuElems.load()) {
         mtuElems.store(numElems.load());
     }
-    inpBuffer.data.resize(numElems.load());
+
     overflowBuffer.data.resize(mtuElems.load());
     
     buffs[0] = malloc(mtuElems.load() * 4 * sizeof(float));
@@ -148,13 +153,14 @@ bool SDRThread::init() {
         settingChanged.erase(settingChanged.begin(), settingChanged.end());
     }
     
+	//apply settings.
     { //enter scoped-lock
         std::lock_guard < std::mutex > lock(setting_busy);
 
         for (settings_i = settingsInfo.begin(); settings_i != settingsInfo.end(); settings_i++) {
             SoapySDR::ArgInfo setting = (*settings_i);
-            if ((settingChanged.find(setting.key) != settingChanged.end()) && (settings.find(setting.key) != settings.end())) {
-                device->writeSetting(setting.key, settings[setting.key]);
+            if ((settingChanged.find(setting.key) != settingChanged.end()) && (settings.find(setting.key) != settings.end())) {              
+				device->writeSetting(setting.key, settings[setting.key]);
                 settingChanged[setting.key] = false;
             } else {
                 settings[setting.key] = device->readSetting(setting.key);
@@ -168,7 +174,10 @@ bool SDRThread::init() {
     updateSettings();
     
     wxGetApp().sdrThreadNotify(SDRThread::SDR_THREAD_INITIALIZED, std::string("Device Initialized."));
-    
+	
+	//rebuild menu now that settings are really been applied.
+	wxGetApp().notifyMainUIOfDeviceChange(true);
+
     return true;
 }
 
@@ -178,7 +187,17 @@ void SDRThread::deinit() {
     free(buffs[0]);
 }
 
-void SDRThread::readStream(SDRThreadIQDataQueue* iqDataOutQueue) {
+void SDRThread::assureBufferMinSize(SDRThreadIQData * dataOut, size_t minSize) {
+    
+    if (dataOut->data.size() < minSize) {
+        dataOut->data.resize(minSize);
+    }
+}
+
+//Called in an infinite loop, read SaopySDR device to build 
+// a 'this.numElems' sized batch of samples (SDRThreadIQData) and push it into  iqDataOutQueue.
+//this batch of samples is built to represent 1 frame / TARGET_DISPLAY_FPS.
+int SDRThread::readStream(SDRThreadIQDataQueuePtr iqDataOutQueue) {
     int flags;
     long long timeNs;
 
@@ -186,41 +205,69 @@ void SDRThread::readStream(SDRThreadIQDataQueue* iqDataOutQueue) {
     int nElems = numElems.load();
     int mtElems = mtuElems.load();
 
-    //If overflow occured on the previous readStream(), transfer it in inpBuffer now
+    // Warning: if MTU > numElems, i.e if device MTU is too big w.r.t the sample rate, the TARGET_DISPLAY_FPS cannot
+    //be reached and the CubicSDR displays "slows down". 
+    //To get back a TARGET_DISPLAY_FPS, the user need to adapt 
+    //the SoapySDR Device to use smaller buffer sizes, because  
+    // readStream() is suited to device MTU and cannot be really adapted dynamically.
+    //TODO: Add in doc the need to reduce SoapySDR device buffer length (if available) to restore higher fps.
+
+    //0. Retreive a new batch 
+    SDRThreadIQDataPtr dataOut = buffers.getBuffer();
+
+    //resize to the target size immedialetly, to minimize later reallocs:
+    assureBufferMinSize(dataOut.get(), nElems);
+
+    //1.If overflow occured on the previous readStream(), transfer it in dataOut directly. 
     if (numOverflow > 0) {
-        int n_overflow = numOverflow;
-        if (n_overflow > nElems) {
-            n_overflow = nElems;
-        }
-        memcpy(&inpBuffer.data[0], &overflowBuffer.data[0], n_overflow * sizeof(liquid_float_complex));
+        int n_overflow = std::min(numOverflow, nElems);
+        
+        //safety
+        assureBufferMinSize(dataOut.get(), n_overflow);
+
+        ::memcpy(&dataOut->data[0], &overflowBuffer.data[0], n_overflow * sizeof(liquid_float_complex));
         n_read = n_overflow;
+
+        //is still > 0 if MTU > nElements (low sample rate w.r.t the MTU !)
         numOverflow -= n_overflow;
+
+        // std::cout << "SDRThread::readStream() 1.1 overflowBuffer not empty, collect the remaining " << n_overflow << " samples in it..." << std::endl;
         
-        if (numOverflow) { // still some left..
-            memmove(&overflowBuffer.data[0], &overflowBuffer.data[n_overflow], numOverflow * sizeof(liquid_float_complex));
+        if (numOverflow > 0) { // still some left, shift the remaining samples to the begining..
+            ::memmove(&overflowBuffer.data[0], &overflowBuffer.data[n_overflow], numOverflow * sizeof(liquid_float_complex));
+
+        //    std::cout << "SDRThread::readStream() 1.2 overflowBuffer still not empty, compact the remaining " << numOverflow << " samples in it..." << std::endl;
         }
-    }
+    } //end if numOverflow > 0
     
-    //attempt readStream() at most nElems, by mtElems-sized chunks, append inpBuffer.
+    int readStreamCode = 0;
+
+    //2. attempt readStream() at most nElems, by mtElems-sized chunks, append in dataOut->data directly.
     while (n_read < nElems && !stopping) {
-        int n_requested = nElems-n_read;
         
+        //Whatever the number of remaining samples needed to reach nElems,  we always try to read a mtElems-size chunk,
+        //from which SoapySDR effectively returns n_stream_read.
         int n_stream_read = device->readStream(stream, buffs, mtElems, flags, timeNs);
+        
+        readStreamCode = n_stream_read;
 
         //if the n_stream_read <= 0, bail out from reading. 
         if (n_stream_read == 0) {
-             std::cout << "SDRThread::readStream(): read blocking..." << std::endl;
+             std::cout << "SDRThread::readStream(): 2. SoapySDR read blocking..." << std::endl;
              break;
         }
         else if (n_stream_read < 0) {
-            std::cout << "SDRThread::readStream(): read failed with code: " << n_stream_read << std::endl;
+            std::cout << "SDRThread::readStream(): 2. SoapySDR read failed with code: " << n_stream_read << std::endl;
             break;
         }
-
-        //sucess read beyond nElems, with overflow
+        
+        //sucess read beyond nElems, so with overflow:
         if ((n_read + n_stream_read) > nElems) {
 
-            //Copy at most n_requested CF32 into inpBuffer.data liquid_float_complex,
+            //n_requested is the exact number to reach nElems.
+            int n_requested = nElems-n_read;
+    
+            //Copy at most n_requested CF32 into .data liquid_float_complex,
             //starting at n_read position.
             //inspired from SoapyRTLSDR code, this mysterious void** is indeed an array of CF32(real/imag) samples, indeed an array of 
             //float with the following layout [sample 1 real part , sample 1 imag part,  sample 2 real part , sample 2 imag part,sample 3 real part , sample 3 imag part,...etc]
@@ -228,29 +275,70 @@ void SDRThread::readStream(SDRThreadIQDataQueue* iqDataOutQueue) {
             //nor that the Re/Im layout of fields matches the float array order, assign liquid_float_complex field by field.
             float *pp = (float *)buffs[0];
 
-            for (int i = 0; i < n_requested; i++) {
-                inpBuffer.data[n_read + i].real = pp[2 * i];
-                inpBuffer.data[n_read + i].imag = pp[2 * i + 1];
-            }
+            //safety
+            assureBufferMinSize(dataOut.get(), n_read + n_requested);
 
-            numOverflow = n_stream_read-n_requested;
+            if (iq_swap.load()) {
+                for (int i = 0; i < n_requested; i++) {
+                    dataOut->data[n_read + i].imag = pp[2 * i];
+                    dataOut->data[n_read + i].real = pp[2 * i + 1];
+                }
+            } else {
+                for (int i = 0; i < n_requested; i++) {
+                    dataOut->data[n_read + i].real = pp[2 * i];
+                    dataOut->data[n_read + i].imag = pp[2 * i + 1];
+                }
+            }
            
-            //shift of n_requested samples, each one made of 2 floats...
+           //shift of n_requested samples, each one made of 2 floats...
             pp += n_requested * 2;
+
+            //numNewOverflow are in exess, they have to be added in the existing overflowBuffer.
+            int numNewOverflow = n_stream_read - n_requested;
+
             //so push the remainder samples to overflowBuffer:
-            for (int i = 0; i < numOverflow; i++) {
-                overflowBuffer.data[i].real = pp[2 * i];
-                overflowBuffer.data[i].imag = pp[2 * i + 1];
+            if (numNewOverflow > 0) {
+            //	std::cout << "SDRThread::readStream(): 2. SoapySDR read make nElems overflow by " << numNewOverflow << " samples..." << std::endl;
+            }
+
+            //safety
+            assureBufferMinSize(&overflowBuffer, numOverflow + numNewOverflow);
+
+            if (iq_swap.load()) {
+
+                for (int i = 0; i < numNewOverflow; i++) {
+                    overflowBuffer.data[numOverflow + i].imag = pp[2 * i];
+                    overflowBuffer.data[numOverflow + i].real = pp[2 * i + 1];
+                }
+            }
+            else {
+                for (int i = 0; i < numNewOverflow; i++) {
+                    overflowBuffer.data[numOverflow + i].real = pp[2 * i];
+                    overflowBuffer.data[numOverflow + i].imag = pp[2 * i + 1];
+                }
             }
+            numOverflow += numNewOverflow;
+           
             n_read += n_requested;
-        } else if (n_stream_read > 0) {
-            
+        } else if (n_stream_read > 0) { // no overflow, read the whole n_stream_read.
+
             float *pp = (float *)buffs[0];
 
-            for (int i = 0; i < n_stream_read; i++) {
-                inpBuffer.data[n_read + i].real = pp[2 * i];
-                inpBuffer.data[n_read + i].imag = pp[2 * i + 1];
+            //safety
+            assureBufferMinSize(dataOut.get(), n_read + n_stream_read);
+
+            if (iq_swap.load()) {
+                for (int i = 0; i < n_stream_read; i++) {
+                    dataOut->data[n_read + i].imag = pp[2 * i];
+                    dataOut->data[n_read + i].real = pp[2 * i + 1];
+                }
             }
+            else {
+                for (int i = 0; i < n_stream_read; i++) {
+                    dataOut->data[n_read + i].real = pp[2 * i];
+                    dataOut->data[n_read + i].imag = pp[2 * i + 1];
+                }
+            } 
 
             n_read += n_stream_read;
         } else {
@@ -258,19 +346,12 @@ void SDRThread::readStream(SDRThreadIQDataQueue* iqDataOutQueue) {
         }
     } //end while
     
+    //3. At that point, dataOut contains nElems (or less if a read has return an error), try to post in queue, else discard.
     if (n_read > 0 && !stopping && !iqDataOutQueue->full()) {
-        SDRThreadIQData *dataOut = buffers.getBuffer();
-
-        if (iq_swap.load()) {
-            dataOut->data.resize(n_read);
-            for (int i = 0; i < n_read; i++) {
-                dataOut->data[i].imag = inpBuffer.data[i].real;
-                dataOut->data[i].real = inpBuffer.data[i].imag;
-            }
-        } else {
-            dataOut->data.assign(inpBuffer.data.begin(), inpBuffer.data.begin()+n_read);
-        }
         
+        //clamp result to the actual read size:
+        dataOut->data.resize(n_read);
+
         dataOut->frequency = frequency.load();
         dataOut->sampleRate = sampleRate.load();
         dataOut->dcCorrected = hasHardwareDC.load();
@@ -278,32 +359,45 @@ void SDRThread::readStream(SDRThreadIQDataQueue* iqDataOutQueue) {
         
         if (!iqDataOutQueue->try_push(dataOut)) {
             //The rest of the system saturates,
-            //finally the push didn't suceeded, recycle dataOut immediatly.
-            dataOut->setRefCount(0);
+            //finally the push didn't suceeded.
             
-            std::cout << "SDRThread::readStream(): iqDataOutQueue output queue is full, discard processing ! " << std::endl;
+            readStreamCode = -32;
+            std::cout << "SDRThread::readStream(): 3.2 iqDataOutQueue output queue is full, discard processing of the batch..." << std::endl;
 
             //saturation, let a chance to the other threads to consume the existing samples
             std::this_thread::yield();
         }
     }
+    else {
+        readStreamCode = -31;
+        std::cout << "SDRThread::readStream(): 3.1 iqDataOutQueue output queue is full, discard processing of the batch..." << std::endl;
+        //saturation, let a chance to the other threads to consume the existing samples
+        std::this_thread::yield();
+    }
+
+    return readStreamCode;
 }
 
+
 void SDRThread::readLoop() {
-    SDRThreadIQDataQueue* iqDataOutQueue = static_cast<SDRThreadIQDataQueue*>( getOutputQueue("IQDataOutput"));
+  
+    SDRThreadIQDataQueuePtr iqDataOutQueue = std::static_pointer_cast<SDRThreadIQDataQueue>( getOutputQueue("IQDataOutput"));
     
-    if (iqDataOutQueue == NULL) {
+    if (iqDataOutQueue == nullptr) {
         return;
     }
     
     updateGains();
-
+ 
     while (!stopping.load()) {
+
         updateSettings();
+
         readStream(iqDataOutQueue);
-    }
 
-    buffers.purge();
+    } //End while
+
+    iqDataOutQueue->flush();
 }
 
 void SDRThread::updateGains() {
@@ -327,6 +421,13 @@ void SDRThread::updateSettings() {
     if (!stream) {
         return;
     }
+
+    if (antenna_changed.load()) {
+        
+       device->setAntenna(SOAPY_SDR_RX, 0, antennaName);
+           
+       antenna_changed.store(false);
+    }
     
     if (offset_changed.load()) {
         if (!freq_changed.load()) {
@@ -337,6 +438,7 @@ void SDRThread::updateSettings() {
     }
     
     if (rate_changed.load()) {
+
         device->setSampleRate(SOAPY_SDR_RX,0,sampleRate.load());
         // TODO: explore bandwidth setting option to see if this is necessary for others
         if (device->getDriverKey() == "bladeRF") {
@@ -344,17 +446,20 @@ void SDRThread::updateSettings() {
         }
         sampleRate.store(device->getSampleRate(SOAPY_SDR_RX,0));
         numChannels.store(getOptimalChannelCount(sampleRate.load()));
-        numElems.store(getOptimalElementCount(sampleRate.load(), 60));
+        numElems.store(getOptimalElementCount(sampleRate.load(), TARGET_DISPLAY_FPS));
         int streamMTU = device->getStreamMTU(stream);
         mtuElems.store(streamMTU);
+        //fallback if  mtuElems was wrong
         if (!mtuElems.load()) {
             mtuElems.store(numElems.load());
         }
-        inpBuffer.data.resize(numElems.load());
+
         overflowBuffer.data.resize(mtuElems.load());
         free(buffs[0]);
         buffs[0] = malloc(mtuElems.load() * 4 * sizeof(float));
+        //clear overflow buffer
         numOverflow = 0;
+
         rate_changed.store(false);
         doUpdate = true;
     }
@@ -385,13 +490,12 @@ void SDRThread::updateSettings() {
         if (!agc_mode.load()) {
             updateGains();
             
+			//re-apply the saved configuration gains:
             DeviceConfig *devConfig = deviceConfig.load();
             ConfigGains gains = devConfig->getGains();
             
-            if (gains.size()) {
-                for (ConfigGains::iterator gain_i = gains.begin(); gain_i != gains.end(); gain_i++) {
-                    setGain(gain_i->first, gain_i->second);
-                }
+            for (ConfigGains::iterator gain_i = gains.begin(); gain_i != gains.end(); gain_i++) {
+                setGain(gain_i->first, gain_i->second);
             }
         }
         doUpdate = true;
@@ -410,7 +514,6 @@ void SDRThread::updateSettings() {
         gain_value_changed.store(false);
     }
     
-    
     if (setting_value_changed.load()) {
 
         std::lock_guard < std::mutex > lock(setting_busy);
@@ -444,7 +547,7 @@ void SDRThread::run() {
     
     SDRDeviceInfo *activeDev = deviceInfo.load();
     
-    if (activeDev != NULL) {
+    if (activeDev != nullptr) {
         std::cout << "device init()" << std::endl;
         if (!init()) {
             std::cout << "SDR Thread stream init error." << std::endl;
@@ -464,6 +567,15 @@ void SDRThread::run() {
     std::cout << "SDR thread done." << std::endl;
 }
 
+void SDRThread::terminate() {
+    IOThread::terminate();
+
+    SDRThreadIQDataQueuePtr iqDataOutQueue = std::static_pointer_cast<SDRThreadIQDataQueue>(getOutputQueue("IQDataOutput"));
+
+    if (iqDataOutQueue != nullptr) {
+        iqDataOutQueue->flush();
+    }
+}
 
 SDRDeviceInfo *SDRThread::getDevice() {
     return deviceInfo.load();
@@ -538,6 +650,12 @@ void SDRThread::unlockFrequency() {
 void SDRThread::setOffset(long long ofs) {
     offset.store(ofs);
     offset_changed.store(true);
+
+    DeviceConfig *devConfig = deviceConfig.load();
+    if (devConfig) {
+        devConfig->setOffset(ofs);
+    }
+
 //    std::cout << "Set offset: " << offset.load() << std::endl;
 }
 
@@ -545,6 +663,20 @@ long long SDRThread::getOffset() {
     return offset.load();
 }
 
+void SDRThread::setAntenna(const std::string& name) {
+    antennaName = name;
+    antenna_changed.store(true);
+
+    DeviceConfig *devConfig = deviceConfig.load();
+    if (devConfig) {
+        devConfig->setAntennaName(antennaName);
+    }
+}
+
+std::string SDRThread::getAntenna() {
+    return antennaName;
+}
+
 void SDRThread::setSampleRate(long rate) {
     sampleRate.store(rate);
     rate_changed = true;
@@ -561,6 +693,12 @@ long SDRThread::getSampleRate() {
 void SDRThread::setPPM(int ppm) {
     this->ppm.store(ppm);
     ppm_changed.store(true);
+
+    DeviceConfig *devConfig = deviceConfig.load();
+    if (devConfig) {
+        devConfig->setPPM(ppm);
+    }
+
 //    std::cout << "Set PPM: " << this->ppm.load() << std::endl;
 }
 
@@ -603,9 +741,9 @@ void SDRThread::setGain(std::string name, float value) {
 
 float SDRThread::getGain(std::string name) {
     std::lock_guard < std::mutex > lock(gain_busy);
-	float val = gainValues[name];
-	
-	return val;
+    float val = gainValues[name];
+    
+    return val;
 }
 
 void SDRThread::writeSetting(std::string name, std::string value) {
diff --git a/src/sdr/SoapySDRThread.h b/src/sdr/SoapySDRThread.h
index 2982ac1..c72c5a9 100644
--- a/src/sdr/SoapySDRThread.h
+++ b/src/sdr/SoapySDRThread.h
@@ -4,7 +4,7 @@
 #pragma once
 
 #include <atomic>
-
+#include <memory>
 #include "ThreadBlockingQueue.h"
 #include "DemodulatorMgr.h"
 #include "SDRDeviceInfo.h"
@@ -15,8 +15,9 @@
 #include <SoapySDR/Registry.hpp>
 #include <SoapySDR/Device.hpp>
 
+#include <stddef.h>
 
-class SDRThreadIQData: public ReferenceCounter {
+class SDRThreadIQData {
 public:
     long long frequency;
     long long sampleRate;
@@ -34,26 +35,33 @@ public:
 
     }
 
-    ~SDRThreadIQData() {
+    virtual ~SDRThreadIQData() {
 
     }
 };
-
-typedef ThreadBlockingQueue<SDRThreadIQData *> SDRThreadIQDataQueue;
+typedef std::shared_ptr<SDRThreadIQData> SDRThreadIQDataPtr;
+typedef ThreadBlockingQueue<SDRThreadIQDataPtr> SDRThreadIQDataQueue;
+typedef std::shared_ptr<SDRThreadIQDataQueue> SDRThreadIQDataQueuePtr;
 
 class SDRThread : public IOThread {
 private:
     bool init();
     void deinit();
-    void readStream(SDRThreadIQDataQueue* iqDataOutQueue);
+    
+    //returns the SoapyDevice readStream return value,
+    //i.e if >= 0 the numbre of samples read, else if < 0 an error code.
+    int readStream(SDRThreadIQDataQueuePtr iqDataOutQueue);
+
     void readLoop();
 
 public:
     SDRThread();
     ~SDRThread();
-    enum SDRThreadState { SDR_THREAD_MESSAGE, SDR_THREAD_INITIALIZED, SDR_THREAD_FAILED };
+
+    enum SDRThreadState { SDR_THREAD_MESSAGE, SDR_THREAD_INITIALIZED, SDR_THREAD_FAILED};
     
     virtual void run();
+    virtual void terminate();
 
     SDRDeviceInfo *getDevice();
     void setDevice(SDRDeviceInfo *dev);
@@ -69,6 +77,9 @@ public:
     
     void setOffset(long long ofs);
     long long getOffset();
+
+    void setAntenna(const std::string& name);
+    std::string getAntenna();
     
     void setSampleRate(long rate);
     long getSampleRate();
@@ -99,7 +110,6 @@ protected:
     SoapySDR::Device *device;
     void *buffs[1];
     ReBuffer<SDRThreadIQData> buffers;
-    SDRThreadIQData inpBuffer;
     SDRThreadIQData overflowBuffer;
     int numOverflow;
     std::atomic<DeviceConfig *> deviceConfig;
@@ -113,7 +123,8 @@ protected:
     std::atomic_llong frequency, offset, lock_freq;
     std::atomic_int ppm, numElems, mtuElems, numChannels;
     std::atomic_bool hasPPM, hasHardwareDC;
-    std::atomic_bool agc_mode, rate_changed, freq_changed, offset_changed,
+    std::string antennaName;
+    std::atomic_bool agc_mode, rate_changed, freq_changed, offset_changed, antenna_changed,
         ppm_changed, device_changed, agc_mode_changed, gain_value_changed, setting_value_changed, frequency_locked, frequency_lock_init, iq_swap;
 
     std::mutex gain_busy;
@@ -121,4 +132,7 @@ protected:
     std::map<std::string, bool> gainChanged;
     
     SoapySDR::Kwargs streamArgs;
+
+private:
+	void assureBufferMinSize(SDRThreadIQData * dataOut, size_t minSize);
 };
diff --git a/src/ui/GLPanel.cpp b/src/ui/GLPanel.cpp
index 4963d0b..010fbbc 100644
--- a/src/ui/GLPanel.cpp
+++ b/src/ui/GLPanel.cpp
@@ -308,7 +308,7 @@ void GLPanel::calcTransform(mat4 transform_in) {
 void GLPanel::draw() {
     float min = -1.0, max = 1.0;
 
-    glLoadMatrixf(transform);
+    glLoadMatrixf(transform.to_ptr());
     
     if (fillType != GLPANEL_FILL_NONE && visible) {
         glEnable(GL_BLEND);
@@ -378,7 +378,7 @@ void GLPanel::draw() {
         }
         //        if (coord == GLPANEL_Y_UP) {
         //        }
-        glLoadMatrixf(transform * mCoord);
+        glLoadMatrixf((transform * mCoord).to_ptr());
         drawPanelContents();
     }
 }
diff --git a/src/ui/GLPanel.h b/src/ui/GLPanel.h
index 94cd7a6..1ab5152 100644
--- a/src/ui/GLPanel.h
+++ b/src/ui/GLPanel.h
@@ -63,6 +63,7 @@ public:
     std::vector<GLPanel *> children;
     
     GLPanel();
+    virtual ~GLPanel() {};
     
     void setPosition(float x, float y);
 
diff --git a/src/util/GLFont.cpp b/src/util/GLFont.cpp
index 5acf124..924f9f8 100644
--- a/src/util/GLFont.cpp
+++ b/src/util/GLFont.cpp
@@ -3,6 +3,8 @@
 
 #include "GLFont.h"
 
+#include <wx/string.h>
+
 #include <iostream>
 #include <fstream>
 #include <algorithm>
@@ -12,14 +14,6 @@
 #include "CoreFoundation/CoreFoundation.h"
 #endif
 
-static std::wstring getExePath(void)
-{
-    //get the dir path of the executable
-    wxFileName exePath = wxFileName(wxStandardPaths::Get().GetExecutablePath());
-   
-    return  std::wstring(exePath.GetPath().ToStdWstring());
-}
-
 #ifndef RES_FOLDER
 #define RES_FOLDER ""
 #endif
@@ -253,11 +247,11 @@ void GLFont::loadFontOnce() {
     //Re-compute the resource dir.
     resourceFolder = fontDefFileName.GetPath();
 
-    std::wstring fontDefFileNamePath = fontDefFileName.GetFullPath(wxPATH_NATIVE).ToStdWstring();
+    std::string fontDefFileNamePath = fontDefFileName.GetFullPath(wxPATH_NATIVE).ToStdString();
     
     std::wifstream input;
-    std::string inpFileStr(fontDefFileNamePath.begin(), fontDefFileNamePath.end());
-    input.open(inpFileStr, std::ios::in);
+   
+    input.open(fontDefFileNamePath, std::ios::in);
 
     std::wstring op;
 
diff --git a/src/util/ThreadBlockingQueue.h b/src/util/ThreadBlockingQueue.h
index 47819d0..59fb224 100644
--- a/src/util/ThreadBlockingQueue.h
+++ b/src/util/ThreadBlockingQueue.h
@@ -25,6 +25,8 @@
 class ThreadQueueBase {
 };
 
+typedef std::shared_ptr<ThreadQueueBase> ThreadQueueBasePtr;
+
 /** A thread-safe asynchronous blocking queue */
 template<typename T>
 class ThreadBlockingQueue : public ThreadQueueBase {
@@ -36,16 +38,15 @@ public:
 
     /*! Create safe blocking queue. */
     ThreadBlockingQueue() {
-        //at least 1 (== Exchanger)
+        //at least 1 (== Java SynchronizedQueue)
         m_max_num_items = MIN_ITEM_NB;
     };
     
-    //Copy constructor
-    ThreadBlockingQueue(const ThreadBlockingQueue& sq) {
-        std::lock_guard < std::mutex > lock(sq.m_mutex);
-        m_queue = sq.m_queue;
-        m_max_num_items = sq.m_max_num_items;
-    }
+    //Forbid Copy construction.
+	ThreadBlockingQueue(const ThreadBlockingQueue& sq) = delete;
+
+	/*! Forbid copy assignment. */
+	ThreadBlockingQueue& operator=(const ThreadBlockingQueue& sq) = delete;
 
     /*! Destroy safe queue. */
     ~ThreadBlockingQueue() {
@@ -74,10 +75,10 @@ public:
      * \param[in] item An item.
      * \param[in] timeout a max waiting timeout in microseconds for an item to be pushed. 
      * by default, = 0 means indefinite wait.
-     * \param[in] errorMessage an error message written on std::cout in case of the timeout wait
+     * \param[in] errorMessage if != nullptr (is nullptr by default) an error message written on std::cout in case of the timeout wait
      * \return true if an item was pushed into the queue, else a timeout has occured.
      */
-    bool push(const value_type& item, std::uint64_t timeout = BLOCKING_INFINITE_TIMEOUT,const char* errorMessage = "") {
+    bool push(const value_type& item, std::uint64_t timeout = BLOCKING_INFINITE_TIMEOUT,const char* errorMessage = nullptr) {
         std::unique_lock < std::mutex > lock(m_mutex);
 
         if (timeout == BLOCKING_INFINITE_TIMEOUT) {
@@ -90,12 +91,15 @@ public:
             return false;
         }
         else if (false == m_cond_not_full.wait_for(lock, std::chrono::microseconds(timeout),
-           [this]() { return m_queue.size() < m_max_num_items; })) {
-            std::thread::id currentThreadId = std::this_thread::get_id();
-            std::cout << "WARNING: Thread 0x" << std::hex << currentThreadId << std::dec <<
-                " (" << currentThreadId << ") executing {" << typeid(*this).name() << "}.push() has failed with timeout > " <<
-                (timeout * 0.001) << " ms, message: " << errorMessage << std::endl;
-           return false;
+            [this]() { return m_queue.size() < m_max_num_items; })) {
+
+            if (errorMessage != nullptr) {
+                std::thread::id currentThreadId = std::this_thread::get_id();
+                std::cout << "WARNING: Thread 0x" << std::hex << currentThreadId << std::dec <<
+                    " (" << currentThreadId << ") executing {" << typeid(*this).name() << "}.push() has failed with timeout > " <<
+                    (timeout * 0.001) << " ms, message: '" << errorMessage << "'" << std::endl << std::flush;
+            } 
+            return false;
         }
 
         m_queue.push_back(item);
@@ -123,10 +127,10 @@ public:
     /**
      * Pops item from the queue. If the queue is empty, blocks for timeout microseconds, or until item becomes available.
      * \param[in] timeout The number of microseconds to wait. O (default) means indefinite wait.
-     * \param[in] errorMessage an error message written on std::cout in case of the timeout wait
+     * \param[in] errorMessage if != nullptr (is nullptr by default) an error message written on std::cout in case of the timeout wait
      * \return true if get an item from the queue, false if no item is received before the timeout.
      */
-    bool pop(value_type& item, std::uint64_t timeout = BLOCKING_INFINITE_TIMEOUT, const char* errorMessage = "") {
+    bool pop(value_type& item, std::uint64_t timeout = BLOCKING_INFINITE_TIMEOUT, const char* errorMessage = nullptr) {
         std::unique_lock < std::mutex > lock(m_mutex);
 
         if (timeout == BLOCKING_INFINITE_TIMEOUT) {
@@ -140,10 +144,13 @@ public:
         }
         else if (false == m_cond_not_empty.wait_for(lock, std::chrono::microseconds(timeout),
             [this]() { return !m_queue.empty(); })) {
-            std::thread::id currentThreadId = std::this_thread::get_id();
-            std::cout << "WARNING: Thread 0x" << std::hex << currentThreadId << std::dec <<
-                " (" << currentThreadId << ") executing {" << typeid(*this).name() << "}.pop() has failed with timeout > " <<
-                (timeout * 0.001) << " ms, message: " << errorMessage << std::endl;
+
+            if (errorMessage != nullptr) {
+                std::thread::id currentThreadId = std::this_thread::get_id();
+                std::cout << "WARNING: Thread 0x" << std::hex << currentThreadId << std::dec <<
+                    " (" << currentThreadId << ") executing {" << typeid(*this).name() << "}.pop() has failed with timeout > " <<
+                    (timeout * 0.001) << " ms, message: '" << errorMessage << "'" << std::endl << std::flush;
+            }
             return false;
         }
 
@@ -208,57 +215,10 @@ public:
         m_cond_not_full.notify_all();
     }
 
-    /**
-     *  Swaps the contents.
-     * \param[out] sq The ThreadBlockingQueue to swap with 'this'.
-     */
-    void swap(ThreadBlockingQueue& sq) {
-        if (this != &sq) {
-            std::lock_guard < std::mutex > lock1(m_mutex);
-            std::lock_guard < std::mutex > lock2(sq.m_mutex);
-            m_queue.swap(sq.m_queue);
-            std::swap(m_max_num_items, sq.m_max_num_items);
-
-            if (!m_queue.empty()) {
-                m_cond_not_empty.notify_all();
-            }
-
-            if (!sq.m_queue.empty()) {
-                sq.m_cond_not_empty.notify_all();
-            }
 
-            if (!m_queue.full()) {
-                m_cond_not_full.notify_all();
-            }
-
-            if (!sq.m_queue.full()) {
-                sq.m_cond_not_full.notify_all();
-            }
-        }
-    }
-
-    /*! The copy assignment operator */
-    ThreadBlockingQueue& operator=(const ThreadBlockingQueue& sq) {
-        if (this != &sq) {
-            std::lock_guard < std::mutex > lock1(m_mutex);
-            std::lock_guard < std::mutex > lock2(sq.m_mutex);
-  
-            m_queue = sq.m_queue;
-            m_max_num_items = sq.m_max_num_items;
-
-            if (!m_queue.empty()) {
-                m_cond_not_empty.notify_all();
-            }
-
-            if (!m_queue.full()) {
-                m_cond_not_full.notify_all();
-            }
-        }
-        return *this;
-    }
 
 private:
-    //TODO: use a circular buffer structure ? (fixed array + modulo)
+
     std::deque<T> m_queue;
 
     mutable std::mutex m_mutex;
@@ -266,9 +226,3 @@ private:
     std::condition_variable m_cond_not_full;
     size_t m_max_num_items = MIN_ITEM_NB;
 };
-
-/*! Swaps the contents of two ThreadBlockingQueue objects. (external operator) */
-template<typename T>
-void swap(ThreadBlockingQueue<T>& q1, ThreadBlockingQueue<T>& q2) {
-    q1.swap(q2);
-}
diff --git a/src/util/ThreadQueue.cpp b/src/util/ThreadQueue.cpp
deleted file mode 100644
index 3597da5..0000000
--- a/src/util/ThreadQueue.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-// Copyright (c) Charles J. Cliffe
-// SPDX-License-Identifier: GPL-2.0+
-
-#include <ThreadQueue.h>
\ No newline at end of file
diff --git a/src/util/ThreadQueue.h b/src/util/ThreadQueue.h
deleted file mode 100644
index 1805b4b..0000000
--- a/src/util/ThreadQueue.h
+++ /dev/null
@@ -1,302 +0,0 @@
-// Copyright (c) Charles J. Cliffe
-// SPDX-License-Identifier: GPL-2.0+
-
-#pragma once 
-
-/* Credit to Alfredo Pons / https://plus.google.com/109903449837592676231
- * Code from http://gnodebian.blogspot.com.es/2013/07/a-thread-safe-asynchronous-queue-in-c11.html
- *
- * Changes:
- *   Charles J. Nov-19-2014
- *     - Renamed SafeQueue -> ThreadQueue 
- *   Sonnier.V Feb-10-2017
- *     - Simplified, various fixes
- */
-
-#include <deque>
-#include <list>
-#include <mutex>
-#include <thread>
-#include <cstdint>
-#include <condition_variable>
-
-class ThreadQueueBase {   
-};
-
-/** A thread-safe asynchronous queue */
-template<typename T>
-class ThreadQueue : public ThreadQueueBase {
-
-    typedef typename std::deque<T>::value_type value_type;
-    typedef typename std::deque<T>::size_type size_type;
-
-public:
-
-    /*! Create safe queue. */
-    ThreadQueue() {
-        m_max_num_items = 0;
-    };
-    ThreadQueue(ThreadQueue&& sq) {
-        m_queue = std::move(sq.m_queue);
-        m_max_num_items = sq.m_max_num_items;
-    }
-    ThreadQueue(const ThreadQueue& sq) {
-        std::lock_guard < std::mutex > lock(sq.m_mutex);
-        m_queue = sq.m_queue;
-        m_max_num_items = sq.m_max_num_items;
-    }
-
-    /*! Destroy safe queue. */
-    ~ThreadQueue() {
-        std::lock_guard < std::mutex > lock(m_mutex);
-    }
-
-    /**
-     * Sets the maximum number of items in the queue. Defaults is 0: No limit
-     * \param[in] item An item.
-     */
-    void set_max_num_items(unsigned int max_num_items) {
-        std::lock_guard < std::mutex > lock(m_mutex);
-        m_max_num_items = max_num_items;  
-    }
-
-    /**
-     *  Pushes the item into the queue.
-     * \param[in] item An item.
-     * \return true if an item was pushed into the queue
-     */
-    bool push(const value_type& item) {
-        std::lock_guard < std::mutex > lock(m_mutex);
-
-        if (m_max_num_items > 0 && m_queue.size() > m_max_num_items) {
-            return false;
-        }
-
-        m_queue.push_back(item);
-        m_cond_not_empty.notify_all();
-        return true;
-    }
-
-    /**
-     *  Pushes the item into the queue.
-     * \param[in] item An item.
-     * \return true if an item was pushed into the queue
-     */
-    bool push(const value_type&& item) {
-        std::lock_guard < std::mutex > lock(m_mutex);
-
-        if (m_max_num_items > 0 && m_queue.size() > m_max_num_items) {
-            return false;
-        }
-
-        m_queue.push_back(item);
-        m_cond_not_empty.notify_all();
-        return true;
-    }
-
-    /**
-     *  Pops item from the queue. If queue is empty, this function blocks until item becomes available.
-     * \param[out] item The item.
-     */
-    void pop(value_type& item) {
-        std::unique_lock < std::mutex > lock(m_mutex);
-        m_cond_not_empty.wait(lock, [this]() // Lambda funct
-                {
-                    return !m_queue.empty();
-                });
-        item = m_queue.front();
-        m_queue.pop_front();
-    }
-
-    /**
-     *  Pops item from the queue using the contained type's move assignment operator, if it has one..
-     *  This method is identical to the pop() method if that type has no move assignment operator.
-     *  If queue is empty, this function blocks until item becomes available.
-     * \param[out] item The item.
-     */
-    void move_pop(value_type& item) {
-        std::unique_lock < std::mutex > lock(m_mutex);
-        m_cond_not_empty.wait(lock, [this]() // Lambda funct
-                {
-                    return !m_queue.empty();
-                });
-        item = std::move(m_queue.front());
-        m_queue.pop_front();
-    }
-
-    /**
-     *  Tries to pop item from the queue.
-     * \param[out] item The item.
-     * \return False is returned if no item is available.
-     */
-    bool try_pop(value_type& item) {
-        std::lock_guard < std::mutex > lock(m_mutex);
-
-        if (m_queue.empty())
-            return false;
-
-        item = m_queue.front();
-        m_queue.pop_front();
-        return true;
-    }
-
-    /**
-     *  Tries to pop item from the queue using the contained type's move assignment operator, if it has one..
-     *  This method is identical to the try_pop() method if that type has no move assignment operator.
-     * \param[out] item The item.
-     * \return False is returned if no item is available.
-     */
-    bool try_move_pop(value_type& item) {
-        std::lock_guard < std::mutex > lock(m_mutex);
-
-        if (m_queue.empty())
-            return false;
-
-        item = std::move(m_queue.front());
-        m_queue.pop_front();
-        return true;
-    }
-
-    /**
-     *  Pops item from the queue. If the queue is empty, blocks for timeout microseconds, or until item becomes available.
-     * \param[out] t An item.
-     * \param[in] timeout The number of microseconds to wait.
-     * \return true if get an item from the queue, false if no item is received before the timeout.
-     */
-    bool timeout_pop(value_type& item, std::uint64_t timeout) {
-        std::unique_lock < std::mutex > lock(m_mutex);
-
-        if (m_queue.empty()) {
-            if (timeout == 0)
-                return false;
-
-            if (m_cond_not_empty.wait_for(lock, std::chrono::microseconds(timeout)) == std::cv_status::timeout)
-                return false;
-        }
-
-        item = m_queue.front();
-        m_queue.pop_front();
-        return true;
-    }
-
-    /**
-     *  Pops item from the queue using the contained type's move assignment operator, if it has one..
-     *  If the queue is empty, blocks for timeout microseconds, or until item becomes available.
-     *  This method is identical to the try_pop() method if that type has no move assignment operator.
-     * \param[out] t An item.
-     * \param[in] timeout The number of microseconds to wait.
-     * \return true if get an item from the queue, false if no item is received before the timeout.
-     */
-    bool timeout_move_pop(value_type& item, std::uint64_t timeout) {
-        std::unique_lock < std::mutex > lock(m_mutex);
-
-        if (m_queue.empty()) {
-            if (timeout == 0)
-                return false;
-
-            if (m_cond_not_empty.wait_for(lock, std::chrono::microseconds(timeout)) == std::cv_status::timeout)
-                return false;
-        }
-
-        item = std::move(m_queue.front());
-        m_queue.pop_front();
-        return true;
-    }
-
-    /**
-     *  Gets the number of items in the queue.
-     * \return Number of items in the queue.
-     */
-    size_type size() const {
-        std::lock_guard < std::mutex > lock(m_mutex);
-        return m_queue.size();
-    }
-
-    /**
-     *  Check if the queue is empty.
-     * \return true if queue is empty.
-     */
-    bool empty() const {
-        std::lock_guard < std::mutex > lock(m_mutex);
-        return m_queue.empty();
-    }
-
-    /**
-     *  Check if the queue is full.
-     * \return true if queue is full.
-     */
-    bool full() const {
-        std::lock_guard < std::mutex > lock(m_mutex);
-        return (m_max_num_items != 0) && (m_queue.size() >= m_max_num_items);
-    }
-
-    /**
-     *  Remove any items in the queue.
-     */
-    void flush() {
-        std::lock_guard < std::mutex > lock(m_mutex);
-        m_queue.clear();
-    }
-
-    /**
-     *  Swaps the contents.
-     * \param[out] sq The ThreadQueue to swap with 'this'.
-     */
-    void swap(ThreadQueue& sq) {
-        if (this != &sq) {
-            std::lock_guard < std::mutex > lock1(m_mutex);
-            std::lock_guard < std::mutex > lock2(sq.m_mutex);
-            m_queue.swap(sq.m_queue);
-            std::swap(m_max_num_items, sq.m_max_num_items);
-
-            if (!m_queue.empty())
-                m_cond_not_empty.notify_all();
-   
-
-            if (!sq.m_queue.empty())
-                sq.m_cond_not_empty.notify_all();
-        }
-    }
-
-    /*! The copy assignment operator */
-    ThreadQueue& operator=(const ThreadQueue& sq) {
-        if (this != &sq) {
-            std::lock_guard < std::mutex > lock1(m_mutex);
-            std::lock_guard < std::mutex > lock2(sq.m_mutex);
-   
-            m_queue = sq.m_queue;
-            m_max_num_items = sq.m_max_num_items;
-
-            if (!m_queue.empty()) 
-                m_cond_not_empty.notify_all();
-        }
-
-        return *this;
-    }
-
-    /*! The move assignment operator */
-    ThreadQueue& operator=(ThreadQueue && sq) {
-        std::lock_guard < std::mutex > lock(m_mutex);
-        m_queue = std::move(sq.m_queue);
-        m_max_num_items = sq.m_max_num_items;
-
-        if (!m_queue.empty()) 
-            m_cond_not_empty.notify_all();
-      
-        return *this;
-    }
-
-private:
-
-    std::deque<T> m_queue;
-
-    mutable std::mutex m_mutex;
-    std::condition_variable m_cond_not_empty;
-    size_t m_max_num_items;
-};
-
-/*! Swaps the contents of two ThreadQueue objects. */
-template<typename T>
-void swap(ThreadQueue<T>& q1, ThreadQueue<T>& q2) {
-    q1.swap(q2);
-}
diff --git a/src/util/Timer.cpp b/src/util/Timer.cpp
index d9d0b37..385681e 100644
--- a/src/util/Timer.cpp
+++ b/src/util/Timer.cpp
@@ -4,165 +4,175 @@
 #include "Timer.h"
 
 #ifdef _WIN32
-	#include <windows.h>
-	#include <mmsystem.h>
+    #include <windows.h>
 #endif
 
 #include <iostream>
 
 Timer::Timer(void) : time_elapsed(0), system_milliseconds(0), start_time(0), end_time(0), last_update(0), num_updates(0), paused_time(0), offset(0), paused_state(false), lock_state(false), lock_rate(0)
 {
+#ifdef _WIN32
+    // According to Microsoft, QueryPerformanceXXX API is perfectly
+    //fine for Windows 7+ systems, and use the highest appropriate counter.
+    //this only need to be done once.
+    ::QueryPerformanceFrequency(&win_frequency);
+#endif
 }
 
 
 void Timer::start(void) 
 {
-	update();
-	num_updates = 0;
-	start_time = system_milliseconds;
-	last_update = start_time;
-	paused_state = false;
-	lock_state = false;
-	lock_rate = 0;
-	paused_time = 0;
-	offset = 0;
+    update();
+    num_updates = 0;
+    start_time = system_milliseconds;
+    last_update = start_time;
+    paused_state = false;
+    lock_state = false;
+    lock_rate = 0;
+    paused_time = 0;
+    offset = 0;
 }
 
 
 void Timer::stop(void) 
 {
-	end_time = system_milliseconds;
+    end_time = system_milliseconds;
 }
 
 
 void Timer::reset(void)
 {
-	start();
+    start();
 }
 
 
 void Timer::lockFramerate(float f_rate)
 {
-	lock_rate = 1.0f/f_rate;
-	lock_state = true;
+    lock_rate = 1.0f/f_rate;
+    lock_state = true;
 }
 
 
 void Timer::unlock()
 {
-	unsigned long msec_tmp = system_milliseconds;
-	
-	lock_state = false;
+    unsigned long msec_tmp = system_milliseconds;
+    
+    lock_state = false;
 
-	update();
-	
-	last_update = system_milliseconds-(unsigned long)lock_rate;
-	
-	offset += msec_tmp-system_milliseconds;
-	
-	lock_rate = 0;
+    update();
+    
+    last_update = system_milliseconds-(unsigned long)lock_rate;
+    
+    offset += msec_tmp-system_milliseconds;
+    
+    lock_rate = 0;
 }
 
 bool Timer::locked()
 {
-	return lock_state;
+    return lock_state;
 }
 
 void Timer::update(void) 
 {
-	num_updates++;
-	last_update = system_milliseconds;
-	
-	
-	if (lock_state)
-	{
-		system_milliseconds += (unsigned long)(lock_rate*1000.0);
-	}
-	else
-	{
+    num_updates++;
+    last_update = system_milliseconds;
+    
+    
+    if (lock_state)
+    {
+        system_milliseconds += (unsigned long)(lock_rate*1000.0);
+    }
+    else
+    {
 #ifdef _WIN32
 
-		system_milliseconds = timeGetTime ();
+        //Use QuaryPerformanceCounter, imune to problems sometimes
+        //multimedia timers have.
+        LARGE_INTEGER win_current_count;
+        ::QueryPerformanceCounter(&win_current_count);
+
+        system_milliseconds = (unsigned long)(win_current_count.QuadPart * 1000.0 / win_frequency.QuadPart);
 
 #else
-		gettimeofday(&time_val,&time_zone);
+        gettimeofday(&time_val,&time_zone);
 
-		system_milliseconds = (unsigned long)time_val.tv_usec;
-		system_milliseconds /= 1000;
-		system_milliseconds += (unsigned long)(time_val.tv_sec*1000);
+        system_milliseconds = (unsigned long)time_val.tv_usec;
+        system_milliseconds /= 1000;
+        system_milliseconds += (unsigned long)(time_val.tv_sec*1000);
 #endif
-	}
+    }
 
 
-	if (paused_state) paused_time += system_milliseconds-last_update;
+    if (paused_state) paused_time += system_milliseconds-last_update;
 
-	time_elapsed = system_milliseconds-start_time-paused_time+offset;
+    time_elapsed = system_milliseconds-start_time-paused_time+offset;
 }
 
 
 unsigned long Timer::getMilliseconds(void) 
 {
-	return time_elapsed;
+    return time_elapsed;
 }
 
 
 
 double Timer::getSeconds(void) 
 {
-	return ((double)getMilliseconds())/1000.0;
+    return ((double)getMilliseconds())/1000.0;
 }
 
 
 void Timer::setMilliseconds(unsigned long milliseconds_in) 
 {
-	offset -= (system_milliseconds-start_time-paused_time+offset)-milliseconds_in;
+    offset -= (system_milliseconds-start_time-paused_time+offset)-milliseconds_in;
 }
 
 
 
 void Timer::setSeconds(double seconds_in) 
 {
-	setMilliseconds((long)(seconds_in*1000.0));
+    setMilliseconds((long)(seconds_in*1000.0));
 }
 
 
 double Timer::lastUpdateSeconds(void)
 {
-	return ((double)lastUpdateMilliseconds())/1000.0;
+    return ((double)lastUpdateMilliseconds())/1000.0;
 }
 
 
 unsigned long Timer::lastUpdateMilliseconds(void)
 {
-	return system_milliseconds-last_update;
+    return system_milliseconds-last_update;
 }
 
 unsigned long Timer::totalMilliseconds()
 {
-	return system_milliseconds-start_time;
+    return system_milliseconds-start_time;
 }
 
 
 double Timer::totalSeconds(void)
 {
-	return totalMilliseconds()/1000.0;
+    return totalMilliseconds()/1000.0;
 }
 
 
 unsigned long Timer::getNumUpdates(void)
 {
-	return num_updates;
+    return num_updates;
 }
 
 
 void Timer::paused(bool pause_in)
 {
-	paused_state = pause_in;
+    paused_state = pause_in;
 }
 
 bool Timer::paused()
 {
-	return paused_state;
+    return paused_state;
 }
 
 void Timer::timerTestFunc() {
diff --git a/src/util/Timer.h b/src/util/Timer.h
index 95d3d15..b45b218 100644
--- a/src/util/Timer.h
+++ b/src/util/Timer.h
@@ -30,6 +30,8 @@ private:
 #ifndef _WIN32
     struct timeval time_val;
     struct timezone time_zone;
+#else
+    LARGE_INTEGER win_frequency;
 #endif
 
     bool paused_state;
@@ -91,6 +93,7 @@ public:
      *  \return Total time elapsed since the timer start() to the last update() excluding time paused() in milliseconds
      */
     unsigned long getMilliseconds(void);
+
     /// Alias of getMilliseconds() which returns time in seconds
     /**
      *  \return Total time elapsed since the timer start() to the last update() excluding time paused() in seconds
@@ -159,6 +162,7 @@ public:
      */
     bool paused();
     
+
     
     void timerTestFunc();
 };
diff --git a/src/visual/GainCanvas.cpp b/src/visual/GainCanvas.cpp
index a5c0b56..70010cf 100644
--- a/src/visual/GainCanvas.cpp
+++ b/src/visual/GainCanvas.cpp
@@ -17,6 +17,7 @@
 #include "CubicSDRDefs.h"
 #include "AppFrame.h"
 #include <algorithm>
+#include <cmath>
 
 wxBEGIN_EVENT_TABLE(GainCanvas, wxGLCanvas) EVT_PAINT(GainCanvas::OnPaint)
 EVT_IDLE(GainCanvas::OnIdle)
@@ -41,6 +42,8 @@ GainCanvas::GainCanvas(wxWindow *parent, std::vector<int> dispAttrs) :
     startPos = spacing/2.0;
     barHeight = 0.8f;
     refreshCounter = 0;
+
+	userGainAsChanged = false;
 }
 
 GainCanvas::~GainCanvas() {
@@ -69,13 +72,40 @@ void GainCanvas::OnIdle(wxIdleEvent &event) {
 	} else {
 		event.Skip();
 	}
+
+	bool areGainsChangedHere = false;
     
     for (auto gi : gainPanels) {
         if (gi->getChanged()) {
-            wxGetApp().setGain(gi->getName(), gi->getValue());
+			areGainsChangedHere  = true;
+			// Gain only displays integer gain values, so set the applied gain 
+			//value to exactly that. 
+            wxGetApp().setGain(gi->getName(), (int)(gi->getValue()));
+			//A gain may be exposed as setting also so assure refresh of the menu also.
+			wxGetApp().notifyMainUIOfDeviceChange(false); //do not rebuild the gain UI
+
             gi->setChanged(false);
         }
     }
+
+	//User input has changed the gain, so schedule an update of values
+	//in 150ms in the future, else the device may not have taken the value into account.
+	if (areGainsChangedHere) {
+		userGainAsChanged = true;
+		userGainAsChangedDelayTimer.start();
+	}
+	else {
+		userGainAsChangedDelayTimer.update();
+
+		if (!userGainAsChanged || (userGainAsChanged && userGainAsChangedDelayTimer.getMilliseconds() > 150)) {
+			
+			if (updateGainValues()) {
+				Refresh();
+			}
+
+			userGainAsChanged = false;
+		}
+	}
 }
 
 void GainCanvas::SetLevel() {
@@ -83,11 +113,10 @@ void GainCanvas::SetLevel() {
     
     for (auto gi : gainPanels) {
         if (gi->isMeterHit(mpos)) {
-            float value = gi->getMeterHitValue(mpos, *gi);
+            float value = gi->getMeterHitValue(mpos);
             
             gi->setValue(value);
-            gi->setChanged(true);
-            
+            gi->setChanged(true);           
             break;
         }
     }
@@ -100,7 +129,7 @@ void GainCanvas::OnMouseMoved(wxMouseEvent& event) {
     
     for (auto gi : gainPanels) {
         if (gi->isMeterHit(mpos)) {
-            float value = gi->getMeterHitValue(mpos, *gi);
+            float value = gi->getMeterHitValue(mpos);
         
             gi->setHighlight(value);
             gi->setHighlightVisible(true);
@@ -167,13 +196,12 @@ void GainCanvas::OnMouseEnterWindow(wxMouseEvent& event) {
 #endif
 }
 
-
-
 void GainCanvas::setHelpTip(std::string tip) {
     helpTip = tip;
 }
 
 void GainCanvas::updateGainUI() {
+
     SDRDeviceInfo *devInfo = wxGetApp().getDevice();
 
     //possible if we 'Refresh Devices' then devInfo becomes null
@@ -183,9 +211,14 @@ void GainCanvas::updateGainUI() {
     }
 
     DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(devInfo->getDeviceId());
-    
+	
+	//read the gains from the device.
+	//This may be wrong because the device is not started, or has yet 
+	//to take into account a user gain change. Doesn't matter,
+	//UpdateGainValues() takes cares of updating the true value realtime.
     gains = devInfo->getGains(SOAPY_SDR_RX, 0);
-    SDRRangeMap::iterator gi;
+    
+	SDRRangeMap::iterator gi;
     
     numGains = gains.size();
     float i = 0;
@@ -205,7 +238,7 @@ void GainCanvas::updateGainUI() {
         bgPanel.removeChild(mDel);
         delete mDel;
     }
-    
+
     for (auto gi : gains) {
         MeterPanel *mPanel = new MeterPanel(gi.first, gi.second.minimum(), gi.second.maximum(), devConfig->getGain(gi.first,wxGetApp().getGain(gi.first)));
 
@@ -217,10 +250,67 @@ void GainCanvas::updateGainUI() {
         gainPanels.push_back(mPanel);
         i++;
     }
-    
+	  
     setThemeColors();
 }
 
+// call this to refresh the gain values only, not the whole UI.
+bool GainCanvas::updateGainValues() {
+
+	bool isRefreshNeeded = false;
+
+	SDRDeviceInfo *devInfo = wxGetApp().getDevice();
+
+	//possible if we 'Refresh Devices' then devInfo becomes null
+	//until a new device is selected.
+	//also, do not attempt an update with the device is not started.
+	if (devInfo == nullptr || !devInfo->isActive()) {
+		return false;
+	}
+
+	DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(devInfo->getDeviceId());
+
+	gains = devInfo->getGains(SOAPY_SDR_RX, 0);
+	SDRRangeMap::iterator gi;
+
+	size_t numGainsToRefresh = std::min(gains.size(), gainPanels.size());
+	size_t panelIndex = 0;
+
+	//actually the order of gains iteration should be constant because map of string,
+	//and gainPanels were built in that order in updateGainUI()
+	for (auto gi : gains) {
+
+		if (panelIndex >= numGainsToRefresh) {
+			break;
+		}
+
+		// do not update if a change is already pending.
+		if (!gainPanels[panelIndex]->getChanged()) {
+
+			//read the actual gain from the device, round it
+			float actualRoundedGain = (float)std::round(devInfo->getCurrentGain(SOAPY_SDR_RX, 0, gi.first));
+			
+			//do nothing if the difference is less than 1.0, since the panel do not show it anyway.
+			if ((int)actualRoundedGain != (int)(gainPanels[panelIndex]->getValue())) {
+
+				gainPanels[panelIndex]->setValue(actualRoundedGain);
+
+				//update the config with this value : 
+				//a consequence of such updates is that the use setting 
+				// is overriden by the current one in AGC mode.
+				//TODO: if it not desirable, do not update in AGC mode.
+				devConfig->setGain(gi.first, actualRoundedGain);
+
+				isRefreshNeeded = true;
+			}
+		} //end if no external change pending.
+
+		panelIndex++;
+	}
+
+	return isRefreshNeeded;
+}
+
 void GainCanvas::setThemeColors() {
     RGBA4f c1, c2;
     
diff --git a/src/visual/GainCanvas.h b/src/visual/GainCanvas.h
index 2e7a552..323724b 100644
--- a/src/visual/GainCanvas.h
+++ b/src/visual/GainCanvas.h
@@ -8,6 +8,7 @@
 
 #include <vector>
 #include <queue>
+#include <atomic>
 
 #include "InteractiveCanvas.h"
 #include "MouseTracker.h"
@@ -25,9 +26,13 @@ public:
 
     void setHelpTip(std::string tip);
     void updateGainUI();
-    void setThemeColors();
+	void setThemeColors();
     
 private:
+
+	// call this to refresh the gain values only, return true if refresh is needed
+	bool updateGainValues();
+
     void OnPaint(wxPaintEvent& event);
     void OnIdle(wxIdleEvent &event);
 
@@ -50,6 +55,9 @@ private:
     float spacing, barWidth, startPos, barHeight, numGains;
     int refreshCounter;
     wxSize clientSize;
+
+	std::atomic_bool userGainAsChanged;
+	Timer userGainAsChangedDelayTimer;
     //
 wxDECLARE_EVENT_TABLE();
 };
diff --git a/src/visual/InteractiveCanvas.h b/src/visual/InteractiveCanvas.h
index 3ffb173..091a9f6 100644
--- a/src/visual/InteractiveCanvas.h
+++ b/src/visual/InteractiveCanvas.h
@@ -13,7 +13,7 @@
 class InteractiveCanvas: public wxGLCanvas {
 public:
     InteractiveCanvas(wxWindow *parent, std::vector<int> dispAttrs);
-    ~InteractiveCanvas();
+    virtual ~InteractiveCanvas();
 
     long long getFrequencyAt(float x);
     long long getFrequencyAt(float x, long long iqCenterFreq, long long iqBandwidth);
diff --git a/src/visual/PrimaryGLContext.cpp b/src/visual/PrimaryGLContext.cpp
index 72f0be5..cd56408 100644
--- a/src/visual/PrimaryGLContext.cpp
+++ b/src/visual/PrimaryGLContext.cpp
@@ -62,7 +62,7 @@ PrimaryGLContext::PrimaryGLContext(wxGLCanvas *canvas, wxGLContext *sharedContex
 //#endif
 }
 
-void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, RGBA4f color, long long center_freq, long long srate, bool centerline) {
+void PrimaryGLContext::DrawDemodInfo(DemodulatorInstancePtr demod, RGBA4f color, long long center_freq, long long srate, bool centerline) {
     if (!demod) {
         return;
     }
@@ -104,17 +104,26 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, RGBA4f color, l
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
     bool soloMode = wxGetApp().getSoloMode();
+    bool isRecording = demod->isRecording();
     bool isSolo = soloMode && demod == wxGetApp().getDemodMgr().getLastActiveDemodulator();
     
+    RGBA4f labelBg(0, 0, 0, 0.35f);
+
     if (isSolo) {
-        glColor4f(0.8f, 0.8f, 0, 0.35f);
+        labelBg.r = labelBg.g = 0.8f;
     } else if (demod->isMuted()) {
-        glColor4f(0.8f, 0, 0, 0.35f);
+        labelBg.r = 0.8f;
     } else if (soloMode) {
-        glColor4f(0.2f, 0, 0, 0.35f);
-    } else {
-        glColor4f(0, 0, 0, 0.35f);
+        labelBg.r = 0.2f;
+    }
+
+    // TODO: Better recording indicator... pulsating red circle?
+    if (isRecording) {
+        auto t = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
+        labelBg.g = sinf(2.0f * M_PI * (float(t) / 1000.0f)) * 0.25f + 0.75f;
     }
+
+    glColor4f(labelBg.r, labelBg.g, labelBg.b, labelBg.a);
     
     glBegin(GL_QUADS);
     glVertex3f(uxPos - ofsLeft, hPos + labelHeight, 0.0);
@@ -156,18 +165,29 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, RGBA4f color, l
 
     glColor4f(1.0, 1.0, 1.0, 0.8f);
 
-    std::string demodLabel = demod->getLabel();
-    
+    std::string demodLabel, demodPrefix;
+
+    if (demod->isDeltaLock()) {
+        demodPrefix.append("V");
+    }
+
+    if (isRecording) {
+        demodPrefix.append("R");
+    }
+
     if (demod->isMuted()) {
-        demodLabel = std::string("[M] ") + demodLabel;
+        demodPrefix.append("M");
     } else if (isSolo) {
-        demodLabel = std::string("[S] ") + demodLabel;
+        demodPrefix.append("S");
     }
-    
-    if (demod->isDeltaLock()) {
-        demodLabel.append(" [V]");
-    }
-    
+
+    // Set the prefix
+    if (!demodPrefix.empty()) {
+        demodLabel = "[" + demodPrefix + "] ";
+    }    
+    // Append the default label
+    demodLabel.append(demod->getLabel());
+
     if (demod->getDemodulatorType() == "USB") {
         GLFont::getFont(16, GLFont::getScaleFactor()).drawString(demodLabel, uxPos, hPos, GLFont::GLFONT_ALIGN_LEFT, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true);
     } else if (demod->getDemodulatorType() == "LSB") {
@@ -287,7 +307,7 @@ void PrimaryGLContext::DrawFreqBwInfo(long long freq, int bw, RGBA4f color, long
     glDisable(GL_BLEND);
 }
 
-void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, RGBA4f color, long long center_freq, long long srate) {
+void PrimaryGLContext::DrawDemod(DemodulatorInstancePtr demod, RGBA4f color, long long center_freq, long long srate) {
     if (!demod) {
         return;
     }
@@ -356,20 +376,14 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, RGBA4f color, long
 
     glEnable(GL_BLEND);
 
-    GLFont::Align demodAlign = GLFont::GLFONT_ALIGN_CENTER;
-
     //Displayed string is wstring, so use wxString to do the heavy lifting of converting  getDemodulatorType()...
     wxString demodStr;
 
     demodStr.assign(demod->getDemodulatorType());
 
-    demodAlign = GLFont::GLFONT_ALIGN_CENTER;
-
     if (demodStr == "LSB") {
-        demodAlign = GLFont::GLFONT_ALIGN_RIGHT;
         uxPos -= xOfs;
     } else if (demodStr == "USB") {
-        demodAlign = GLFont::GLFONT_ALIGN_LEFT;
         uxPos += xOfs;
     }
     // advanced demodulators start here
@@ -415,7 +429,8 @@ void PrimaryGLContext::drawSingleDemodLabel(const std::wstring& demodStr, float
 }
 
 void PrimaryGLContext::DrawFreqSelector(float uxPos, RGBA4f color, float w, long long /* center_freq */, long long srate) {
-    DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
+    
+    DemodulatorInstancePtr demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
 
     long long bw = 0;
 
diff --git a/src/visual/PrimaryGLContext.h b/src/visual/PrimaryGLContext.h
index f421def..a799e75 100644
--- a/src/visual/PrimaryGLContext.h
+++ b/src/visual/PrimaryGLContext.h
@@ -26,9 +26,9 @@ public:
 
     void DrawFreqSelector(float uxPos, RGBA4f color, float w = 0, long long center_freq = -1, long long srate = 0);
     void DrawRangeSelector(float uxPos1, float uxPos2, RGBA4f color);
-    void DrawDemod(DemodulatorInstance *demod, RGBA4f color, long long center_freq = -1, long long srate = 0);
+    void DrawDemod(DemodulatorInstancePtr demod, RGBA4f color, long long center_freq = -1, long long srate = 0);
     
-    void DrawDemodInfo(DemodulatorInstance *demod, RGBA4f color, long long center_freq = -1, long long srate = 0, bool centerline = false);
+    void DrawDemodInfo(DemodulatorInstancePtr demod, RGBA4f color, long long center_freq = -1, long long srate = 0, bool centerline = false);
     void DrawFreqBwInfo(long long freq, int bw, RGBA4f color, long long center_freq = - 1, long long srate = 0, bool stack = false, bool centerline = false);
 
     void setHoverAlpha(float hoverAlpha);
diff --git a/src/visual/ScopeCanvas.cpp b/src/visual/ScopeCanvas.cpp
index 5371513..1f8fc80 100644
--- a/src/visual/ScopeCanvas.cpp
+++ b/src/visual/ScopeCanvas.cpp
@@ -34,7 +34,7 @@ wxEND_EVENT_TABLE()
 ScopeCanvas::ScopeCanvas(wxWindow *parent, std::vector<int> dispAttrs) : InteractiveCanvas(parent, dispAttrs), ppmMode(false), ctr(0), ctrTarget(0), dragAccel(0), helpTip("") {
 
     glContext = new ScopeContext(this, &wxGetApp().GetContext(this));
-    inputData.set_max_num_items(2);
+    inputData->set_max_num_items(2);
     bgPanel.setFill(GLPanel::GLPANEL_FILL_GRAD_Y);
     bgPanel.setSize(1.0, 0.5f);
     bgPanel.setPosition(0.0, -0.5f);
@@ -104,8 +104,8 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
     wxPaintDC dc(this);
     const wxSize ClientSize = GetClientSize();
     
-    ScopeRenderData *avData;
-    while (inputData.try_pop(avData)) {
+    ScopeRenderDataPtr avData;
+    while (inputData->try_pop(avData)) {
        
         
         if (!avData->spectrum) {
@@ -113,7 +113,7 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
             if (avData->waveform_points.size()) {
                 scopePanel.setPoints(avData->waveform_points);
             }
-            avData->decRefCount();
+
         } else {
             if (avData->waveform_points.size()) {
                 spectrumPanel.setPoints(avData->waveform_points);
@@ -124,8 +124,7 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
                 spectrumPanel.setFFTSize(avData->fft_size);
                 spectrumPanel.setShowDb(showDb);
             }
-            
-            avData->decRefCount();
+         
         }
     }
 
@@ -149,7 +148,7 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
     
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
-    glLoadMatrixf(CubicVR::mat4::perspective(45.0, 1.0, 1.0, 1000.0));
+    glLoadMatrixf(CubicVR::mat4::perspective(45.0, 1.0, 1.0, 1000.0).to_ptr());
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     
@@ -211,7 +210,7 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
         spectrumPanel.drawChildren();
     }
     
-    glLoadMatrixf(scopePanel.transform);
+    glLoadMatrixf(scopePanel.transform.to_ptr());
     if (!deviceName.empty()) {
         glContext->DrawDeviceName(deviceName);
     }
@@ -234,8 +233,8 @@ void ScopeCanvas::OnIdle(wxIdleEvent &event) {
     event.RequestMore();
 }
 
-ScopeRenderDataQueue *ScopeCanvas::getInputQueue() {
-    return &inputData;
+ScopeRenderDataQueuePtr ScopeCanvas::getInputQueue() {
+    return inputData;
 }
 
 void ScopeCanvas::OnMouseMoved(wxMouseEvent& event) {
diff --git a/src/visual/ScopeCanvas.h b/src/visual/ScopeCanvas.h
index 7511437..bf16eb9 100644
--- a/src/visual/ScopeCanvas.h
+++ b/src/visual/ScopeCanvas.h
@@ -8,6 +8,7 @@
 
 #include <vector>
 #include <queue>
+#include <memory>
 
 #include "ScopeContext.h"
 #include "ScopeVisualProcessor.h"
@@ -42,7 +43,7 @@ public:
     
     void setHelpTip(std::string tip);
 
-    ScopeRenderDataQueue *getInputQueue();
+    ScopeRenderDataQueuePtr getInputQueue();
     
 private:
     void OnPaint(wxPaintEvent& event);
@@ -54,7 +55,7 @@ private:
     void OnMouseEnterWindow(wxMouseEvent& event);
     void OnMouseLeftWindow(wxMouseEvent& event);
 
-    ScopeRenderDataQueue inputData;
+    ScopeRenderDataQueuePtr inputData = std::make_shared<ScopeRenderDataQueue>();
     ScopePanel scopePanel;
     GLPanel parentPanel;
     SpectrumPanel spectrumPanel;
diff --git a/src/visual/SpectrumCanvas.cpp b/src/visual/SpectrumCanvas.cpp
index 742bb2c..4630f9b 100644
--- a/src/visual/SpectrumCanvas.cpp
+++ b/src/visual/SpectrumCanvas.cpp
@@ -37,7 +37,7 @@ SpectrumCanvas::SpectrumCanvas(wxWindow *parent, std::vector<int> dispAttrs) :
 
     glContext = new PrimaryGLContext(this, &wxGetApp().GetContext(this));
 
-    visualDataQueue.set_max_num_items(1);
+    visualDataQueue->set_max_num_items(1);
             
     SetCursor(wxCURSOR_SIZEWE);
     scaleFactor = 1.0;
@@ -54,15 +54,14 @@ void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
     wxPaintDC dc(this);
     const wxSize ClientSize = GetClientSize();
     
-    SpectrumVisualData *vData;
-    if (visualDataQueue.try_pop(vData)) {
+    SpectrumVisualDataPtr vData;
+    if (visualDataQueue->try_pop(vData)) {
             
         if (vData) {
             spectrumPanel.setPoints(vData->spectrum_points);
             spectrumPanel.setPeakPoints(vData->spectrum_hold_points);
             spectrumPanel.setFloorValue(vData->fft_floor);
             spectrumPanel.setCeilValue(vData->fft_ceiling);
-            vData->decRefCount();
         }
     }
     
@@ -91,9 +90,8 @@ void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
     
     glLoadIdentity();
     
-    std::vector<DemodulatorInstance *> &demods = wxGetApp().getDemodMgr().getDemodulators();
-
-    DemodulatorInstance *activeDemodulator = wxGetApp().getDemodMgr().getActiveDemodulator();
+    auto demods = wxGetApp().getDemodMgr().getDemodulators();
+    auto activeDemodulator = wxGetApp().getDemodMgr().getActiveDemodulator();
 
     for (int i = 0, iMax = demods.size(); i < iMax; i++) {
         if (!demods[i]->isActive()) {
@@ -113,7 +111,7 @@ void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
                 freq = roundf((float)freq/(float)snap)*snap;
             }
 
-            DemodulatorInstance *lastActiveDemodulator = wxGetApp().getDemodMgr().getLastActiveDemodulator();
+            auto lastActiveDemodulator = wxGetApp().getDemodMgr().getLastActiveDemodulator();
 
             bool isNew = (((waterfallCanvas->isShiftDown() || (lastActiveDemodulator && !lastActiveDemodulator->isActive())) && lastActiveDemodulator) || (!lastActiveDemodulator));
             
@@ -287,8 +285,8 @@ void SpectrumCanvas::attachWaterfallCanvas(WaterfallCanvas* canvas_in) {
     waterfallCanvas = canvas_in;
 }
 
-SpectrumVisualDataQueue *SpectrumCanvas::getVisualDataQueue() {
-    return &visualDataQueue;
+SpectrumVisualDataQueuePtr SpectrumCanvas::getVisualDataQueue() {
+    return visualDataQueue;
 }
 
 void SpectrumCanvas::OnMouseRightDown(wxMouseEvent& event) {
diff --git a/src/visual/SpectrumCanvas.h b/src/visual/SpectrumCanvas.h
index 68374aa..580d917 100644
--- a/src/visual/SpectrumCanvas.h
+++ b/src/visual/SpectrumCanvas.h
@@ -5,6 +5,7 @@
 
 #include <vector>
 #include <queue>
+#include <memory>
 
 #include "InteractiveCanvas.h"
 #include "PrimaryGLContext.h"
@@ -44,7 +45,7 @@ public:
     void setScaleFactorEnabled(bool en);
     void setFFTSize(int fftSize);
     
-    SpectrumVisualDataQueue *getVisualDataQueue();
+    SpectrumVisualDataQueuePtr getVisualDataQueue();
     
 private:
     void OnPaint(wxPaintEvent& event);
@@ -70,7 +71,7 @@ private:
     int bwChange;
     bool resetScaleFactor, scaleFactorEnabled;
     
-    SpectrumVisualDataQueue visualDataQueue;
+    SpectrumVisualDataQueuePtr  visualDataQueue = std::make_shared<SpectrumVisualDataQueue>();
 
 // event table
 wxDECLARE_EVENT_TABLE();
diff --git a/src/visual/TuningCanvas.cpp b/src/visual/TuningCanvas.cpp
index 9ee6b3e..66ebabe 100644
--- a/src/visual/TuningCanvas.cpp
+++ b/src/visual/TuningCanvas.cpp
@@ -61,10 +61,11 @@ TuningCanvas::~TuningCanvas() {
 }
 
 bool TuningCanvas::changed() {
-    DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
+
+    auto activeDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
     
     long long current_freq = 0;
-    if (activeDemod != NULL) {
+    if (activeDemod != nullptr) {
         freq = activeDemod->getFrequency();
     }
     long long current_bw = wxGetApp().getDemodMgr().getLastBandwidth();
@@ -92,10 +93,10 @@ void TuningCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
 
     glContext->DrawBegin();
 
-    DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
+    auto activeDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
     
     freq = 0;
-    if (activeDemod != NULL) {
+    if (activeDemod != nullptr) {
         freq = activeDemod->getFrequency();
     }
     bw = wxGetApp().getDemodMgr().getLastBandwidth();
@@ -170,7 +171,7 @@ void TuningCanvas::StepTuner(ActiveState state, int exponent, bool up) {
         amount *= 2;
     }
     
-    DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
+    auto activeDemod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
     if (state == TUNING_HOVER_FREQ && activeDemod) {
         long long freq = activeDemod->getFrequency();
         long long diff = abs(wxGetApp().getFrequency() - freq);
@@ -245,6 +246,7 @@ void TuningCanvas::StepTuner(ActiveState state, int exponent, bool up) {
         }
 
         wxGetApp().setPPM(currentPPM);
+        wxGetApp().notifyMainUIOfDeviceChange();
     }
 }
 
@@ -329,7 +331,7 @@ void TuningCanvas::OnMouseMoved(wxMouseEvent& event) {
     if (hoverState == TUNING_HOVER_BW || hoverState == TUNING_HOVER_FREQ) {
          wxGetApp().getDemodMgr().setActiveDemodulator(wxGetApp().getDemodMgr().getLastActiveDemodulator());
      } else {
-         wxGetApp().getDemodMgr().setActiveDemodulator(NULL);
+         wxGetApp().getDemodMgr().setActiveDemodulator(nullptr);
      }
 }
 
@@ -399,7 +401,7 @@ void TuningCanvas::OnMouseLeftWindow(wxMouseEvent& event) {
     SetCursor(wxCURSOR_CROSS);
     hoverIndex = 0;
     hoverState = TUNING_HOVER_NONE;
-    wxGetApp().getDemodMgr().setActiveDemodulator(NULL);
+    wxGetApp().getDemodMgr().setActiveDemodulator(nullptr);
 
     if (currentPPM != lastPPM) {
         wxGetApp().saveConfig();
diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp
index b75ca92..8efd1e5 100644
--- a/src/visual/WaterfallCanvas.cpp
+++ b/src/visual/WaterfallCanvas.cpp
@@ -24,6 +24,8 @@
 
 #include <wx/numformatter.h>
 
+#include "DemodulatorThread.h"
+
 wxBEGIN_EVENT_TABLE(WaterfallCanvas, wxGLCanvas)
 EVT_PAINT(WaterfallCanvas::OnPaint)
 EVT_IDLE(WaterfallCanvas::OnIdle)
@@ -97,16 +99,16 @@ void WaterfallCanvas::processInputQueue() {
     if (linesPerSecond) {
         if (lpsIndex >= targetVis) {
             while (lpsIndex >= targetVis) {
-                SpectrumVisualData *vData;
+                SpectrumVisualDataPtr vData;
 
-                if (visualDataQueue.try_pop(vData)) {
+                if (visualDataQueue->try_pop(vData)) {
                     
                     if (vData) {
                         if (vData->spectrum_points.size() == fft_size * 2) {
                             waterfallPanel.setPoints(vData->spectrum_points);
                         }
                         waterfallPanel.step();
-                        vData->decRefCount();
+                      
                         updated = true;
                     }
                     lpsIndex-=targetVis;
@@ -263,10 +265,10 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
     waterfallPanel.calcTransform(CubicVR::mat4::identity());
     waterfallPanel.draw();
 
-    std::vector<DemodulatorInstance *> &demods = wxGetApp().getDemodMgr().getDemodulators();
+    auto demods = wxGetApp().getDemodMgr().getDemodulators();
 
-    DemodulatorInstance *activeDemodulator = wxGetApp().getDemodMgr().getActiveDemodulator();
-    DemodulatorInstance *lastActiveDemodulator = wxGetApp().getDemodMgr().getLastActiveDemodulator();
+    auto activeDemodulator = wxGetApp().getDemodMgr().getActiveDemodulator();
+    auto lastActiveDemodulator = wxGetApp().getDemodMgr().getLastActiveDemodulator();
 
     bool isNew = shiftDown
             || (wxGetApp().getDemodMgr().getLastActiveDemodulator() && !wxGetApp().getDemodMgr().getLastActiveDemodulator()->isActive());
@@ -307,9 +309,9 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
             }
         } else {
             if (lastActiveDemodulator) {
-                glContext->DrawDemod(lastActiveDemodulator, ((isNew && activeDemodulator == NULL) || (activeDemodulator != NULL))?currentTheme->waterfallHighlight:currentTheme->waterfallDestroy, currentCenterFreq, currentBandwidth);
+                glContext->DrawDemod(lastActiveDemodulator, ((isNew && activeDemodulator == nullptr) || (activeDemodulator != nullptr))?currentTheme->waterfallHighlight:currentTheme->waterfallDestroy, currentCenterFreq, currentBandwidth);
             }
-            if (activeDemodulator == NULL) {
+            if (activeDemodulator == nullptr) {
                 glContext->DrawFreqSelector(mouseTracker.getMouseX(), ((isNew && lastActiveDemodulator) || (!lastActiveDemodulator) )?currentTheme->waterfallNew:currentTheme->waterfallHover, 0, currentCenterFreq, currentBandwidth);
             } else {
                 glContext->DrawDemod(activeDemodulator, currentTheme->waterfallHover, currentCenterFreq, currentBandwidth);
@@ -390,7 +392,7 @@ void WaterfallCanvas::OnKeyUp(wxKeyEvent& event) {
 void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
     InteractiveCanvas::OnKeyDown(event);
 
-    DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getActiveDemodulator();
+    auto activeDemod = wxGetApp().getDemodMgr().getActiveDemodulator();
 
     long long originalFreq = getCenterFrequency();
     long long freq = originalFreq;
@@ -490,9 +492,9 @@ void WaterfallCanvas::OnIdle(wxIdleEvent &event) {
 void WaterfallCanvas::updateHoverState() {
     long long freqPos = getFrequencyAt(mouseTracker.getMouseX());
     
-    std::vector<DemodulatorInstance *> demodsHover = wxGetApp().getDemodMgr().getDemodulatorsAt(freqPos, 15000);
+    auto demodsHover = wxGetApp().getDemodMgr().getDemodulatorsAt(freqPos, 15000);
     
-    wxGetApp().getDemodMgr().setActiveDemodulator(NULL);
+    wxGetApp().getDemodMgr().setActiveDemodulator(nullptr);
     
     if (altDown) {
         nextDragState = WF_DRAG_RANGE;
@@ -506,10 +508,10 @@ void WaterfallCanvas::updateHoverState() {
     } else if (demodsHover.size() && !shiftDown) {
         long near_dist = getBandwidth();
         
-        DemodulatorInstance *activeDemodulator = NULL;
+        DemodulatorInstancePtr activeDemodulator = nullptr;
         
         for (int i = 0, iMax = demodsHover.size(); i < iMax; i++) {
-            DemodulatorInstance *demod = demodsHover[i];
+            auto demod = demodsHover[i];
             long long freqDiff = demod->getFrequency() - freqPos;
             long halfBw = (demod->getBandwidth() / 2);
             long long currentBw = getBandwidth();
@@ -537,7 +539,7 @@ void WaterfallCanvas::updateHoverState() {
             }
         }
         
-        if (activeDemodulator == NULL) {
+        if (activeDemodulator == nullptr) {
             nextDragState = WF_DRAG_NONE;
             SetCursor(wxCURSOR_CROSS);
             return;
@@ -563,35 +565,35 @@ void WaterfallCanvas::updateHoverState() {
             
             mouseTracker.setVertDragLock(true);
             mouseTracker.setHorizDragLock(false);
-            setStatusText("Click and drag to change demodulator bandwidth. SPACE or numeric key for direct frequency input. [, ] to nudge, M for mute, D to delete, C to center, E to edit label.");
+            setStatusText("Drag to change bandwidth. SPACE or 0-9 for direct frequency input. [, ] to nudge, M for mute, D to delete, C to center, E to edit label, R to record.");
         } else {
             SetCursor(wxCURSOR_SIZING);
             nextDragState = WF_DRAG_FREQUENCY;
             
             mouseTracker.setVertDragLock(true);
             mouseTracker.setHorizDragLock(false);
-            setStatusText("Click and drag to change demodulator frequency; SPACE or numeric key for direct input. [, ] to nudge, M for mute, D to delete, C to center, E to edit label.");
+            setStatusText("Drag to change frequency; SPACE or 0-9 for direct input. [, ] to nudge, M for mute, D to delete, C to center, E to edit label, R to record.");
         }
     }
     else {
         SetCursor(wxCURSOR_CROSS);
         nextDragState = WF_DRAG_NONE;
         if (shiftDown) {
-            setStatusText("Click to create a new demodulator or hold ALT to drag range, SPACE or numeric key for direct center frequency input.");
+            setStatusText("Click to create a new demodulator or hold ALT to drag new range.");
         }
         else {
             setStatusText(
-                "Click to set active demodulator frequency or hold ALT to drag range; hold SHIFT to create new.  Right drag or wheel to Zoom.  Arrow keys to navigate/zoom, C to center.");
+                "Click to set demodulator frequency or hold ALT to drag range; hold SHIFT to create new.  Right drag or wheel to Zoom.  Arrow keys to navigate/zoom, C to center.  Shift-R record/stop all.");
         }
     }
 }
 
 void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) {
     InteractiveCanvas::OnMouseMoved(event);
-    DemodulatorInstance *demod = wxGetApp().getDemodMgr().getActiveDemodulator();
+    auto demod = wxGetApp().getDemodMgr().getActiveDemodulator();
 
     if (mouseTracker.mouseDown()) {
-        if (demod == NULL) {
+        if (demod == nullptr) {
             return;
         }
         if (dragState == WF_DRAG_BANDWIDTH_LEFT || dragState == WF_DRAG_BANDWIDTH_RIGHT) {
@@ -650,7 +652,7 @@ void WaterfallCanvas::OnMouseDown(wxMouseEvent& event) {
     wxGetApp().getDemodMgr().updateLastState();
 
     if (dragState && dragState != WF_DRAG_RANGE) {
-        DemodulatorInstance *demod = wxGetApp().getDemodMgr().getActiveDemodulator();
+        auto demod = wxGetApp().getDemodMgr().getActiveDemodulator();
         if (demod) {
             dragOfs = (long long) (mouseTracker.getMouseX() * (float) getBandwidth()) + getCenterFrequency() - (getBandwidth() / 2) - demod->getFrequency();
             dragBW = demod->getBandwidth();
@@ -670,14 +672,14 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
     InteractiveCanvas::OnMouseReleased(event);
     wxGetApp().getDemodMgr().updateLastState();
 
-    bool isNew = shiftDown || (wxGetApp().getDemodMgr().getLastActiveDemodulator() == NULL)
+    bool isNew = shiftDown || (wxGetApp().getDemodMgr().getLastActiveDemodulator() == nullptr)
             || (wxGetApp().getDemodMgr().getLastActiveDemodulator() && !wxGetApp().getDemodMgr().getLastActiveDemodulator()->isActive());
 
     mouseTracker.setVertDragLock(false);
     mouseTracker.setHorizDragLock(false);
 
-    DemodulatorInstance *demod = isNew?NULL:wxGetApp().getDemodMgr().getLastActiveDemodulator();
-    DemodulatorInstance *activeDemod = isNew?NULL:wxGetApp().getDemodMgr().getActiveDemodulator();
+    DemodulatorInstancePtr demod = isNew?nullptr:wxGetApp().getDemodMgr().getLastActiveDemodulator();
+    DemodulatorInstancePtr activeDemod = isNew?nullptr:wxGetApp().getDemodMgr().getActiveDemodulator();
 
     DemodulatorMgr *mgr = &wxGetApp().getDemodMgr();
 
@@ -727,7 +729,7 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
                 demod->writeModemSettings(mgr->getLastModemSettings(mgr->getLastDemodulatorType()));
                 demod->run();
 
-                wxGetApp().bindDemodulator(demod);
+                wxGetApp().notifyDemodulatorsChanged();
                 DemodulatorThread::releaseSquelchLock(nullptr);
             }
 
@@ -827,10 +829,10 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
 
             demod->run();
 
-            wxGetApp().bindDemodulator(demod);
+            wxGetApp().notifyDemodulatorsChanged();
         }
 
-        if (demod == NULL) {
+        if (demod == nullptr) {
             dragState = WF_DRAG_NONE;
             return;
         }
@@ -850,7 +852,7 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
 void WaterfallCanvas::OnMouseLeftWindow(wxMouseEvent& event) {
     InteractiveCanvas::OnMouseLeftWindow(event);
     SetCursor(wxCURSOR_CROSS);
-    wxGetApp().getDemodMgr().setActiveDemodulator(NULL);
+    wxGetApp().getDemodMgr().setActiveDemodulator(nullptr);
     mouseZoom = 1.0;
 }
 
@@ -880,8 +882,8 @@ void WaterfallCanvas::OnMouseRightReleased(wxMouseEvent& event) {
     mouseZoom = 1.0;
 }
 
-SpectrumVisualDataQueue *WaterfallCanvas::getVisualDataQueue() {
-    return &visualDataQueue;
+SpectrumVisualDataQueuePtr WaterfallCanvas::getVisualDataQueue() {
+    return visualDataQueue;
 }
 
 void WaterfallCanvas::updateCenterFrequency(long long freq) {
@@ -915,13 +917,7 @@ void WaterfallCanvas::setLinesPerSecond(int lps) {
     linesPerSecond = lps;
 
     //empty all
-    SpectrumVisualData *vData;
-    while (visualDataQueue.try_pop(vData)) {
-        
-        if (vData) {
-            vData->decRefCount();
-        }
-    }
+    visualDataQueue->flush();
 }
 
 void WaterfallCanvas::setMinBandwidth(int min) {
diff --git a/src/visual/WaterfallCanvas.h b/src/visual/WaterfallCanvas.h
index 4f3ed31..21dea27 100644
--- a/src/visual/WaterfallCanvas.h
+++ b/src/visual/WaterfallCanvas.h
@@ -8,7 +8,7 @@
 
 #include <vector>
 #include <queue>
-
+#include <memory>
 #include "InteractiveCanvas.h"
 #include "MouseTracker.h"
 #include "SpectrumCanvas.h"
@@ -31,7 +31,7 @@ public:
     
     void attachSpectrumCanvas(SpectrumCanvas *canvas_in);
     void processInputQueue();
-    SpectrumVisualDataQueue *getVisualDataQueue();
+    SpectrumVisualDataQueuePtr getVisualDataQueue();
 
     void setLinesPerSecond(int lps);
     void setMinBandwidth(int min);
@@ -88,7 +88,8 @@ private:
     float scaleMove;
     int dragBW;
     
-    SpectrumVisualDataQueue visualDataQueue;
+    SpectrumVisualDataQueuePtr visualDataQueue = std::make_shared<SpectrumVisualDataQueue>();
+
     Timer gTimer;
     double lpsIndex;
     bool preBuf;

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-hamradio/cubicsdr.git



More information about the pkg-hamradio-commits mailing list