diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..01c01e4
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,33 @@
+# This file is a template, and might need editing before it works on your project.
+# To contribute improvements to CI/CD templates, please follow the Development guide at:
+# https://docs.gitlab.com/ee/development/cicd/templates.html
+# This specific template is located at:
+# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/C++.gitlab-ci.yml
+
+# use the official gcc image, based on debian
+# can use verions as well, like gcc:5.2
+# see https://hub.docker.com/_/gcc/
+
+image: gcc
+
+build:
+  stage: build
+  # instead of calling g++ directly you can also use some build toolkit like make
+  # install the necessary build tools when needed
+  before_script:
+  - apt update && apt -y install libwxgtk3.0-gtk3-dev cmake libfccp-dev libpulse-dev libasound2-dev
+  script:
+    - mkdir build && cd build && cmake .. && cmake --build .
+  artifacts:
+    paths:
+      - build/AudMeS
+      # depending on your build setup it's most likely a good idea to cache outputs to reduce the build time
+      # cache:
+      #   paths:
+      #     - "*.o"
+
+# run tests using the binary built before
+#test:
+#  stage: test
+#  script:
+#    - ./runmytests.sh
diff --git a/AudMeS.cpp b/AudMeS.cpp
index fa754d8..ed16081 100644
--- a/AudMeS.cpp
+++ b/AudMeS.cpp
@@ -73,19 +73,17 @@ EVT_CHOICE(ID_OSCXSCALE, MainFrame::OnOscXScaleChanged)
 EVT_CHOICE(ID_FFTLENGTH, MainFrame::OnOscXScaleChanged)
 END_EVENT_TABLE()
 
-short* g_OscBuffer_Left;
-short* g_OscBuffer_Right;
+float* g_OscBuffer_Left;
+float* g_OscBuffer_Right;
 long int g_OscBufferPosition;
 
-short* g_SpeBuffer_Left;
-short* g_SpeBuffer_Right;
+float* g_SpeBuffer_Left;
+float* g_SpeBuffer_Right;
 long int g_SpeBufferPosition;
 
 int g_OscBufferChanged;
 int g_SpeBufferChanged;
 
-static const int frm_low = 20;
-
 ///////////////////////////////////////////////////////////////////////
 MainFrame::MainFrame(wxWindow* parent, int id, const wxString& title, const wxPoint& pos,
                      const wxSize& size, long WXUNUSED(style))
@@ -209,8 +207,9 @@ MainFrame::MainFrame(wxWindow* parent, int id, const wxString& title, const wxPo
 
   // Spectrum analyzer
   label_5 = new wxStaticText(notebook_1_spe, -1, wxT("FFT Window Type:"));
-  const wxString choice_fft_choices[] = {wxT("Rect"), wxT("Hanning"), wxT("Blackman")};
-  choice_fft = new wxChoice(notebook_1_spe, ID_FFTWINDOW, wxDefaultPosition, wxDefaultSize, 3,
+  const wxString choice_fft_choices[] = {wxT("Rect"), wxT("Hanning"), wxT("Blackman"),
+                                         wxT("BlackHarr")};
+  choice_fft = new wxChoice(notebook_1_spe, ID_FFTWINDOW, wxDefaultPosition, wxDefaultSize, 4,
                             choice_fft_choices, 0);
 
   label_9 = new wxStaticText(notebook_1_spe, -1, wxT("Number of samples:"));
@@ -484,7 +483,9 @@ void MainFrame::set_custom_props() {
   g_OscBufferChanged = 0;
   g_SpeBufferChanged = 0;
 
-  frm_running = false;
+  frm_running = 0;
+  frm_measure = 0;
+  frm_istep = 0;
 
   m_configfilename = wxT("");
 
@@ -495,17 +496,37 @@ void MainFrame::set_custom_props() {
   m_SpeBufferLength = (long)(sweep_div);
 
   m_RWAudio = new RWAudio();
+  RWAudioDevList playDevList;
+  RWAudioDevList recordDevList;
+
+  m_RWAudio->GetRWAudioDevices(&playDevList, &recordDevList);
   int ret = 0;
+
+  if (0 >= playDevList.card_info.size()) {
+    wxMessageBox(
+        _T("Sound card issue:\n\nNo output, see\nTools -> Audio interface Configuration\n"),
+        _T("Alert"), wxICON_INFORMATION | wxOK);
+    ret = 1;
+  }
+  if (0 >= recordDevList.card_info.size()) {
+    wxMessageBox(_T("Sound card issue:\n\nNo input, see\nTools -> Audio interface Configuration\n"),
+                 _T("Alert"), wxICON_INFORMATION | wxOK);
+    ret = 1;
+  }
+
+  if (!ret) {
 #ifdef XSCALEINTIME
-  ret = m_RWAudio->InitSnd((long int)(1.5 * m_OscBufferLength * m_SamplingFreq / 10000 + 10),
-                           m_SpeBufferLength, m_rtinfo);
+    ret = m_RWAudio->InitSnd((long int)(1.5 * m_OscBufferLength * m_SamplingFreq / 10000 + 10),
+                             m_SpeBufferLength, m_rtinfo);
 #else
-  ret = m_RWAudio->InitSnd((long int)(1.5 * m_OscBufferLength), m_SpeBufferLength, m_rtinfo);
+    ret = m_RWAudio->InitSnd((long int)(1.5 * m_OscBufferLength), m_SpeBufferLength, m_rtinfo);
 #endif
 
-  if (ret)
-    wxMessageBox(_T("Sound card issue:\n\nPlease check\nTools -> Audio interface Configuration\n"),
-                 _T("Alert"), wxICON_INFORMATION | wxOK);
+    if (ret)
+      wxMessageBox(
+          _T("Sound card issue:\n\nPlease check\nTools -> Audio interface Configuration\n"),
+          _T("Alert"), wxICON_INFORMATION | wxOK);
+  }
 }
 
 void MainFrame::OnAboutClick(wxCommandEvent& WXUNUSED(event)) {
@@ -587,10 +608,10 @@ void MainFrame::OnLoadFRM(wxCommandEvent& WXUNUSED(event)) {
 
 void MainFrame::OnAutoCalClick(wxCommandEvent& WXUNUSED(event)) {
   if (button_osc_start->GetValue()) {
-    short minValueL = 32767;
-    short maxValueL = -32767;
-    short minValueR = 32767;
-    short maxValueR = -32767;
+    float minValueL = 1;
+    float maxValueL = -1;
+    float minValueR = 1;
+    float maxValueR = -1;
 
     for (unsigned long int i = 0; i < m_OscBufferLength; i++) {
       if (minValueL > g_OscBuffer_Left[i]) minValueL = g_OscBuffer_Left[i];
@@ -616,6 +637,52 @@ void MainFrame::OnAutoCalClick(wxCommandEvent& WXUNUSED(event)) {
   }
 }
 
+static const int frm_low = 20;
+
+void MainFrame::CalcFreqResponse() {
+  /* periodically called by OnTimer
+   * delays for measuring work by waiting for the next call
+   */
+  if (frm_running) {
+    if (frm_istep <= (int)frm_ipoints) {
+      float freq = frm_low * pow(10.0, 3.0 * frm_istep / frm_ipoints);
+
+      if (0 == frm_measure) {
+        // play new frequency e.g. from 20Hz to 20kHz
+        m_RWAudio->PlaySetGenerator(freq, freq, 0, 0, pow(10, slide_l_am->GetValue() / 20.0),
+                                    pow(10, slide_r_am->GetValue() / 20.0));
+        wxString bla;
+        bla.Printf(wxT("Frequency : %.1f "), freq);
+        window_1_frm->ShowUserText(bla, 100, 20);
+      }
+      if (1 == frm_measure) g_SpeBufferChanged = 0;  // now get audio data
+
+      if (g_SpeBufferChanged && frm_measure > 1) {
+        // new audio data has arrived
+        double l_rms = 0;
+        double r_rms = 0;
+        // compute RMS value in the grabbed wave and store it as a result
+        for (unsigned long int ii = 0; ii < m_SpeBufferLength; ii++) {
+          l_rms += g_SpeBuffer_Left[ii] * g_SpeBuffer_Left[ii];
+          r_rms += g_SpeBuffer_Right[ii] * g_SpeBuffer_Right[ii];
+        }
+        m_frm_freqs.Add(freq);
+        m_frm_lgains.Add(sqrt(l_rms / m_SpeBufferLength));
+        m_frm_rgains.Add(sqrt(r_rms / m_SpeBufferLength));
+        frm_measure = -1;  // zero after increment
+        frm_istep++;
+      }
+      frm_measure++;
+    } else {
+      frm_running = false;
+      window_1_frm->ShowUserText(wxString(""), 0, 0);
+      button_frm_start->SetValue(false);
+      button_frm_start->SetLabel(_T("Start"));
+      SendGenSettings();  // stop generator
+    }
+  }
+}
+
 void MainFrame::DrawFreqResponse(void) {
   wxArrayDouble left, right;
 
@@ -662,11 +729,10 @@ void MainFrame::DrawOscilloscope(void) {
   double trigger_edge;
   double trigger_level;
   double hysteresis_level = 10;
-  long scope_resolution;
 
-  double range_div = pow(2, choice_osc_l_res->GetCurrentSelection());
+  double range_div = pow(2, choice_osc_l_res->GetCurrentSelection() - 15);
   double shft_val = 20.0 * (choice_osc_l_off->GetCurrentSelection() - 5) / 128.0;
-  double range_div2 = pow(2, choice_osc_l_res_copy->GetCurrentSelection());
+  double range_div2 = pow(2, choice_osc_l_res_copy->GetCurrentSelection() - 15);
   double shft_val2 = 20.0 * (choice_osc_l_off_copy->GetCurrentSelection() - 5) / 128.0;
   i = 0;
 
@@ -676,11 +742,8 @@ void MainFrame::DrawOscilloscope(void) {
   switch (choice_osc_trig_source->GetCurrentSelection()) {
     case 1:
       // left channel - look for the value under hysteresis point and then over 0
-      choice_osc_l_res->GetString(choice_osc_l_res->GetCurrentSelection())
-          .ToLong(&scope_resolution);
       hysteresis_level =
-          scope_resolution /
-          10.0;  // later the hysteresis percent will be maybe settable in the control
+          range_div / 10.0;  // later the hysteresis percent will be maybe settable in the control
       while (i < m_OscBufferLength) {
         if ((trigger_level - hysteresis_level) > (trigger_edge * g_OscBuffer_Left[i])) {
           break;
@@ -697,11 +760,8 @@ void MainFrame::DrawOscilloscope(void) {
       break;
     case 2:
       // right channel
-      choice_osc_l_res_copy->GetString(choice_osc_l_res_copy->GetCurrentSelection())
-          .ToLong(&scope_resolution);
       hysteresis_level =
-          scope_resolution /
-          10.0;  // later the hysteresis percent will be maybe settable in the control
+          range_div2 / 10.0;  // later the hysteresis percent will be maybe settable in the control
       while (i < m_OscBufferLength) {
         if ((trigger_level - hysteresis_level) > (trigger_edge * g_OscBuffer_Right[i])) {
           break;
@@ -828,6 +888,14 @@ void MainFrame::DrawSpectrum(void) {
                      (double)nsampl;
       }
       break;
+    case 3:  // Blackman Harris minimum 4 term
+      for (int i = 0; i < nsampl; i++) {
+        windowf[i] = 2.63 *
+                     (0.35875 + -0.48829 * cos(i * multiplier) + 0.14128 * cos(i * multiplier * 2) +
+                      -0.01168 * cos(i * multiplier * 3)) /
+                     (double)nsampl;
+      }
+      break;
     default:  // Rectangle
       for (int i = 0; i < nsampl; i++) {
         windowf[i] = 1.0 / (double)nsampl;
@@ -837,10 +905,14 @@ void MainFrame::DrawSpectrum(void) {
 
   /*
    * Scale max. amplitude to 1 which is 0 db.
-   * 16 bit samples and fft correction factor 4
-   * 20 * log(1/65536 * 4) is -84.2 db
+   * We only use use nsampl/2 of the FFT.
+   * Compensate with multiplying by 2 = 6dB.
    */
-  const double dbscaler = -84.2;
+  const double dbscaler = 6;
+
+  double dval = 0.0;
+  double dmax = 0.0;
+  int imax = 0;
 
   // left channel
   for (int i = 0; i < nsampl; i++) {
@@ -850,17 +922,42 @@ void MainFrame::DrawSpectrum(void) {
 
   if (fft_double(nsampl, 0, realin, NULL, realout, imagout)) {
     realout[0] = imagout[0] = 0;  // remove DC
-    /* show only one half, this means nsampl/2 corresponds to fvz/2 */
+    /* show only half FFT */
     for (int i = 0; i < nsampl / 2; i++) {
-      ardbl.Add(20.0 * log10(sqrt(realout[i] * realout[i] + imagout[i] * imagout[i])) + dbscaler);
+      dval = realout[i] * realout[i] + imagout[i] * imagout[i];
+      if (dval > dmax) {
+        dmax = dval;
+        imax = i;
+      }
+      ardbl.Add(20.0 * log10(sqrt(dval)) + dbscaler);
     }
   } else {
     /* wrong computation */
-    for (int i = 0; i < nsampl; i++) {
-      ardbl.Add(25 * (sin(0.01 * i) + sin(0.012 * i)));
+    for (int i = 0; i < nsampl / 2; i++) {
+      ardbl.Add(-150);
     }
   }
 
+  if (imax > 0) {
+    double freq = (double)imax * m_SamplingFreq / nsampl;
+    double thdval[10];
+    for (int i = 0; i < 10; i++) {
+      int j = imax * (i + 1);
+      if (j < nsampl / 2)
+        thdval[i] = sqrt(realout[j] * realout[j] + imagout[j] * imagout[j]);
+      else
+        thdval[i] = 0.0;
+    }
+    double thd = 100 *
+                 (thdval[1] + thdval[2] + thdval[3] + thdval[4] + thdval[5] + thdval[6] +
+                  thdval[7] + thdval[8] + thdval[9]) /
+                 thdval[0];
+    wxString freqency;
+    freqency.Printf(wxT("Frequency : %.1lf Hz, Magnitude: %.1lf dB, THD : %lf%%"), freq,
+                    20.0 * log10(thdval[0]) + dbscaler, thd);
+    frame_1_statusbar->SetStatusText(freqency);
+  }
+
   // right channel
   for (int i = 0; i < nsampl; i++) {
     // copy and apply window
@@ -869,14 +966,14 @@ void MainFrame::DrawSpectrum(void) {
 
   if (fft_double(nsampl, 0, realin, NULL, realout, imagout)) {
     realout[0] = imagout[0] = 0;  // remove DC
-    /* show only one half, this means nsampl/2 corresponds to fvz/2 */
+    /* show only half FFT */
     for (int i = 0; i < nsampl / 2; i++) {
       ardbl2.Add(20.0 * log10(sqrt(realout[i] * realout[i] + imagout[i] * imagout[i])) + dbscaler);
     }
   } else {
     /* wrong computation */
-    for (int i = 0; i < nsampl; i++) {
-      ardbl2.Add(25 * (sin(0.01 * i) + sin(0.012 * i)));
+    for (int i = 0; i < nsampl / 2; i++) {
+      ardbl2.Add(-150);
     }
   }
 
@@ -898,20 +995,19 @@ void MainFrame::DrawSpectrum(void) {
 
 void MainFrame::OnTimer(wxTimerEvent& WXUNUSED(event)) {
   bool refresh = false;
-  if (0 != g_OscBufferChanged && button_osc_start->GetValue()) {
+  if (g_OscBufferChanged && button_osc_start->GetValue()) {
     DrawOscilloscope();
     g_OscBufferChanged = 0;
     refresh = true;
   }
-  if (0 != g_SpeBufferChanged) {
-    if (button_spe_start->GetValue()) {
-      DrawSpectrum();
-      refresh = true;
-    }
-    if (button_frm_start->GetValue()) {
-      DrawFreqResponse();
-      refresh = true;
-    }
+  CalcFreqResponse();
+  if (button_frm_start->GetValue()) {
+    DrawFreqResponse();
+    refresh = true;
+  }
+  if (g_SpeBufferChanged && button_spe_start->GetValue()) {
+    DrawSpectrum();
+    refresh = true;
     g_SpeBufferChanged = 0;
   }
   if (refresh) {
@@ -967,57 +1063,28 @@ void MainFrame::OnOscStart(wxCommandEvent& WXUNUSED(event)) {
 }
 
 void MainFrame::OnFrmStart(wxCommandEvent& WXUNUSED(event)) {
-  long ipoints;
-
   if (button_frm_start->GetValue()) {
+    long ip;
     button_frm_start->SetLabel(_T("Stop"));
-
-    // make steppings and measurement
     wxString tpoints = text_ctrl1_frm->GetValue();
-
-    tpoints.ToLong(&ipoints, 10);
-    if (ipoints > 120) ipoints = 120;
-    if (ipoints < 1) ipoints = 1;
-
-    frm_running = true;
+    tpoints.ToLong(&ip, 10);
+    if (ip > 120) ip = 120;
+    if (ip < 1) ip = 1;
+    frm_ipoints = (int)ip;
+    frm_istep = 0;
 
     m_frm_freqs.Clear();
     m_frm_lgains.Clear();
     m_frm_rgains.Clear();
-    for (int i = 0; i <= (int)ipoints; i++) {
-      // from 20Hz to 20kHz
-      float freq = frm_low * pow(10.0, 3.0 * i / ipoints);
-      m_RWAudio->PlaySetGenerator(freq, freq, 0, 0, pow(10, slide_l_am->GetValue() / 20.0),
-                                  pow(10, slide_r_am->GetValue() / 20.0));
-      wxString bla;
-      bla.Printf(wxT("Frequency : %.1f "), freq);
-      window_1_frm->ShowUserText(bla, 100, 20);
-      sleep(200);
-      wxYield();
-      sleep(400);
-      wxYield();
-      // find RMS value in the grabbed wave and store it as a result
-      // TODO: depends on the spectrum buffer size - which may be small
-      double l_rms = 0;
-      double r_rms = 0;
-      for (unsigned long int ii = 0; ii < m_SpeBufferLength; ii++) {
-        l_rms += (double)g_SpeBuffer_Left[ii] / 32768.0 * (double)g_SpeBuffer_Left[ii] / 32768.0;
-        r_rms += g_SpeBuffer_Right[ii] / 32768.0 * g_SpeBuffer_Right[ii] / 32768.0;
-      }
-      m_frm_freqs.Add(freq);
-      m_frm_lgains.Add(sqrt(l_rms / m_SpeBufferLength));
-      m_frm_rgains.Add(sqrt(r_rms / m_SpeBufferLength));
 
-      if (!frm_running) break;
-    }
-    sleep(200);
-    wxYield();
+    frm_measure = 0;
+    frm_running = true;
+  } else {
+    frm_running = false;
     button_frm_start->SetValue(false);
+    button_frm_start->SetLabel(_T("Start"));
+    SendGenSettings();  // stop generator
   }
-  button_frm_start->SetLabel(_T("Start"));
-  frm_running = false;
-  SendGenSettings();
-  window_1_frm->ShowUserText(wxString(""), 0, 0);
 }
 
 void MainFrame::OnGeneratorChanged(wxCommandEvent& WXUNUSED(event)) {
@@ -1169,14 +1236,6 @@ void MainFrame::OnTxtFreqRChanged(wxCommandEvent& WXUNUSED(event)) {
   }
 }
 
-void MainFrame::sleep(int ms) {
-#ifdef __WXMSW__
-  Sleep(ms);
-#else
-  usleep(ms * 1000);
-#endif
-}
-
 class AudMeSApp : public wxApp {
  public:
   bool OnInit();
diff --git a/AudMeS.h b/AudMeS.h
index d509947..26b232e 100644
--- a/AudMeS.h
+++ b/AudMeS.h
@@ -78,6 +78,7 @@ class MainFrame : public wxFrame {
   void OnAutoCalClick(wxCommandEvent& event);
   void OnOscXScaleChanged(wxCommandEvent& event);
   void DrawFreqResponse(void);
+  void CalcFreqResponse(void);
   void DrawOscilloscope(void);
   void DrawSpectrum(void);
 
@@ -152,8 +153,11 @@ class MainFrame : public wxFrame {
 
   RWAudio* m_RWAudio;
   wxTimer* m_timer;
-  // RWPlayer i_pl;
+
   bool frm_running;
+  int frm_ipoints;
+  int frm_istep;
+  int frm_measure;
 
   wxArrayDouble m_frm_freqs;
   wxArrayDouble m_frm_lgains;
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7e3d237..ce9b254 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,15 +18,14 @@ include_directories(.) # for local libfccp
 
 # Default build type is Release
 if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
-   set(CMAKE_BUILD_TYPE "Release")
+	set(CMAKE_BUILD_TYPE "Release")
 endif()
+message("Build type is ${CMAKE_BUILD_TYPE}")
 
 if (WIN32)
 	set(AM_SOURCES ${AM_SOURCES} audmes.rc)
-	string(REPLACE "\\" "/" HDIR $ENV{HOMEDRIVE}$ENV{HOMEPATH})
+	string(REPLACE "\\" "/" HDIR "$ENV{HOMEDRIVE}$ENV{HOMEPATH}")
 	set(wxWidgets_ROOT_DIR "${HDIR}/projects/wx3.0.5")
-	set(wxWidgets_LIB_DIR "${wxWidgets_ROOT_DIR}/lib/gcc810_dll")
-	set(wxWidgets_CONFIGURATION mswu)
 endif()
 
 if (${APPLE})
@@ -34,7 +33,7 @@ if (${APPLE})
 	set(AM_SOURCES ${audmes_icon} ${AM_SOURCES})
 endif()
 
-find_package(wxWidgets COMPONENTS core base REQUIRED)
+find_package(wxWidgets REQUIRED core base)
 include("${wxWidgets_USE_FILE}")
 
 add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${AM_SOURCES})
@@ -60,8 +59,13 @@ if (${APPLE})
 endif()
 
 if (MINGW)
-	add_definitions(-D__WINDOWS_WASAPI__ -D__WXMSW__)
-	target_link_libraries(${PROJECT_NAME} -mwindows -static ${wxWidgets_LIBRARIES} ksuser mfplat mfuuid wmcodecdspuuid)
+	add_definitions(-D__WINDOWS_WASAPI__ -D__WINDOWS_DS__ -D__WXMSW__)
+	target_link_libraries(${PROJECT_NAME} -mwindows ${wxWidgets_LIBRARIES} dsound ksuser mfplat mfuuid wmcodecdspuuid)
+	add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
+	COMMAND ${CMAKE_COMMAND} -E copy "${wxWidgets_LIB_DIR}/wxbase30u_gcc810.dll" "."
+	COMMAND ${CMAKE_COMMAND} -E copy "${wxWidgets_LIB_DIR}/wxbase30ud_gcc810.dll" "."
+	COMMAND ${CMAKE_COMMAND} -E copy "${wxWidgets_LIB_DIR}/wxmsw30u_core_gcc810.dll" "."
+	COMMAND ${CMAKE_COMMAND} -E copy "${wxWidgets_LIB_DIR}/wxmsw30ud_core_gcc810.dll" ".")
 endif()
 
 if (${CMAKE_HOST_SYSTEM_NAME} MATCHES "Linux")
@@ -81,15 +85,20 @@ if (${CMAKE_HOST_SYSTEM_NAME} MATCHES "Linux")
 endif()
 
 if (MINGW)
-    set(CMAKE_INSTALL_PREFIX ".")
-	install(TARGETS ${PROJECT_NAME} DESTINATION "bin")
-	install(FILES "${CMAKE_SOURCE_DIR}/README.md" DESTINATION "bin")
-	install(FILES "${CMAKE_SOURCE_DIR}/NEWS" RENAME "NEWS.txt" DESTINATION "bin")
-	install(FILES "c:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-sjlj-rt_v6-rev0/mingw32/bin/libwinpthread-1.dll" DESTINATION "bin")
-	install(FILES "c:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-sjlj-rt_v6-rev0/mingw32/bin/libstdc++-6.dll" DESTINATION "bin")
-	install(FILES "c:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-sjlj-rt_v6-rev0/mingw32/bin/libgcc_s_sjlj-1.dll" DESTINATION "bin")
-	install(FILES "${wxWidgets_ROOT_DIR}/lib/gcc810_dll/wxbase30u_gcc810.dll" DESTINATION "bin")
-	install(FILES "${wxWidgets_ROOT_DIR}/lib/gcc810_dll/wxmsw30u_core_gcc810.dll" DESTINATION "bin")
+	if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
+		message(WARNING "Installation only in **Release** builds supported")
+	endif()
+	set(CMAKE_INSTALL_PREFIX .)
+	install(TARGETS ${PROJECT_NAME} DESTINATION .)
+	install(FILES "${CMAKE_SOURCE_DIR}/README.md" DESTINATION .)
+	install(FILES "${CMAKE_SOURCE_DIR}/NEWS" RENAME "NEWS.txt" DESTINATION .)
+	# add runtime libraries - static linking does not work with wxWidgets binaries
+	set(MINGW_LIBS "c:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-sjlj-rt_v6-rev0/mingw32/bin")
+	install(FILES "${MINGW_LIBS}/libwinpthread-1.dll" DESTINATION .)
+	install(FILES "${MINGW_LIBS}/libstdc++-6.dll" DESTINATION .)
+	install(FILES "${MINGW_LIBS}/libgcc_s_sjlj-1.dll" DESTINATION .)
+	install(FILES "${wxWidgets_LIB_DIR}/wxbase30u_gcc810.dll" DESTINATION .)
+	install(FILES "${wxWidgets_LIB_DIR}/wxmsw30u_core_gcc810.dll" DESTINATION .)
 	set(CPACK_GENERATOR "ZIP")
 endif()
 
@@ -97,8 +106,8 @@ if (APPLE)
 	set(APP_NAME ${PROJECT_NAME})
 	# Install app and libraries
 	install(TARGETS ${APP_NAME}
-	    BUNDLE DESTINATION . COMPONENT Runtime
-	    RUNTIME DESTINATION bin COMPONENT Runtime
+		BUNDLE DESTINATION . COMPONENT Runtime
+		RUNTIME DESTINATION bin COMPONENT Runtime
 	)
 	set(APPS "\${CMAKE_INSTALL_PREFIX}/${APP_NAME}.app")
 	set(CMAKE_MACOSX_RPATH ON)
diff --git a/RWAudio_IO.cpp b/RWAudio_IO.cpp
index 18f1709..0403f5e 100644
--- a/RWAudio_IO.cpp
+++ b/RWAudio_IO.cpp
@@ -42,12 +42,12 @@ FILE *ddbg;
 #endif
 
 // extern variables from AudMeS.cpp
-extern short *g_OscBuffer_Left;
-extern short *g_OscBuffer_Right;
+extern float *g_OscBuffer_Left;
+extern float *g_OscBuffer_Right;
 extern long int g_OscBufferPosition;
 
-extern short *g_SpeBuffer_Left;
-extern short *g_SpeBuffer_Right;
+extern float *g_SpeBuffer_Left;
+extern float *g_SpeBuffer_Right;
 extern long int g_SpeBufferPosition;
 
 extern int g_OscBufferChanged;
@@ -67,11 +67,18 @@ bool lfsr16() {
   return bit;
 }
 
+/*
+ * callback function to catch runtime errors
+ */
+void catcherr(RtAudioError::Type WXUNUSED(type), const std::string &errorText) {
+  std::cerr << '\n' << errorText << '\n' << std::endl;
+}
+
 /*
  * callback function to fetch audio input and generate tones
  */
 int inout(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
-          double WXUNUSED(streamTime), RtAudioStreamStatus WXUNUSED(status), void *data) {
+          double WXUNUSED(streamTime), RtAudioStreamStatus status, void *data) {
 #ifdef _DEBUG
   fprintf(ddbg, "Jsme tady ");
 #endif
@@ -79,6 +86,8 @@ int inout(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
   RWAudio *aRWAudioClass = (RWAudio *)data;
   unsigned long i;
 
+  if (status) std::cerr << "Audio stream over/underflow detected." << std::endl;
+
   // copy input buffer into two L/R channels
   if (0 != aRWAudioClass->m_Buflen_Changed) {
     aRWAudioClass->m_Buflen_Changed = 0;
@@ -88,13 +97,13 @@ int inout(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
     free(g_SpeBuffer_Right);
     g_OscBufferPosition = 0;
     g_SpeBufferPosition = 0;
-    g_OscBuffer_Left = (short *)malloc(aRWAudioClass->m_OscBufferLen * sizeof(short));
-    g_OscBuffer_Right = (short *)malloc(aRWAudioClass->m_OscBufferLen * sizeof(short));
-    g_SpeBuffer_Left = (short *)malloc(aRWAudioClass->m_SpeBufferLen * sizeof(short));
-    g_SpeBuffer_Right = (short *)malloc(aRWAudioClass->m_SpeBufferLen * sizeof(short));
+    g_OscBuffer_Left = (float *)malloc(aRWAudioClass->m_OscBufferLen * sizeof(float));
+    g_OscBuffer_Right = (float *)malloc(aRWAudioClass->m_OscBufferLen * sizeof(float));
+    g_SpeBuffer_Left = (float *)malloc(aRWAudioClass->m_SpeBufferLen * sizeof(float));
+    g_SpeBuffer_Right = (float *)malloc(aRWAudioClass->m_SpeBufferLen * sizeof(float));
   }
 
-  short *inBuf = (short *)inputBuffer;
+  float *inBuf = (float *)inputBuffer;
 
   // make a copy for oscilloscope
   if (0 == g_OscBufferChanged) {
@@ -113,7 +122,7 @@ int inout(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
     }
   }
 
-  inBuf = (short *)inputBuffer;
+  inBuf = (float *)inputBuffer;
   // make a copy for spectrum analyzer
   if (0 == g_SpeBufferChanged) {
     for (i = 0; i < nBufferFrames; i++) {
@@ -132,7 +141,7 @@ int inout(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
   }
 
   // fill output buffer
-  short *outBuf = (short *)outputBuffer;
+  float *outBuf = (float *)outputBuffer;
 
 #ifdef _DEBUG
   fprintf(ddbg, "\n Frames: %d\n ", nBufferFrames);
@@ -213,11 +222,11 @@ int inout(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
     if ((2.0 * M_PI) < aRWAudioClass->m_genFI_l) aRWAudioClass->m_genFI_l -= 2.0 * M_PI;
     if ((2.0 * M_PI) < aRWAudioClass->m_genFI_r) aRWAudioClass->m_genFI_r -= 2.0 * M_PI;
 
-    *outBuf++ = (short)(32768.f * aRWAudioClass->m_genGain_l * y);
-    *outBuf++ = (short)(32768.f * aRWAudioClass->m_genGain_r * y2);
+    *outBuf++ = (float)(aRWAudioClass->m_genGain_l * y);
+    *outBuf++ = (float)(aRWAudioClass->m_genGain_r * y2);
 
 #ifdef _DEBUG
-    // fprintf(ddbg,"%04X %04X ",(short)(32768.f * y), (short)(32768.f * y2));
+    // fprintf(ddbg,"%04X %04X ",(float)(32768.f * y), (float)(32768.f * y2));
 #endif
   }
   return 0;
@@ -247,10 +256,11 @@ int RWAudio::InitSnd(long int oscbuflen, long int spebuflen, std::string &rtinfo
 
   g_OscBufferPosition = 0;
   g_SpeBufferPosition = 0;
-  g_OscBuffer_Left = (short *)malloc(m_OscBufferLen * sizeof(short));
-  g_OscBuffer_Right = (short *)malloc(m_OscBufferLen * sizeof(short));
-  g_SpeBuffer_Left = (short *)malloc(m_SpeBufferLen * sizeof(short));
-  g_SpeBuffer_Right = (short *)malloc(m_SpeBufferLen * sizeof(short));
+
+  g_OscBuffer_Left = (float *)malloc(m_OscBufferLen * sizeof(float));
+  g_OscBuffer_Right = (float *)malloc(m_OscBufferLen * sizeof(float));
+  g_SpeBuffer_Left = (float *)malloc(m_SpeBufferLen * sizeof(float));
+  g_SpeBuffer_Right = (float *)malloc(m_SpeBufferLen * sizeof(float));
 
   RtAudio::DeviceInfo info;
   unsigned int devices;
@@ -311,11 +321,11 @@ int RWAudio::RestartAudio(int recDevId, int playDevId) {
   iParams.firstChannel = 0;
   oParams.firstChannel = 0;
 
-  // rtAOptions.flags |= RTAUDIO_NONINTERLEAVED;
+  rtAOptions.flags = 0;
 
   try {
-    m_AudioDriver.openStream(&oParams, &iParams, RTAUDIO_SINT16, m_sampleRate, &bufferFrames,
-                             &inout, (void *)this);  //, &rtAOptions );
+    m_AudioDriver.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, m_sampleRate, &bufferFrames,
+                             &inout, (void *)this, &rtAOptions, &catcherr);
   } catch (RtAudioError &e) {
     // std::cerr << '\n' << e.getMessage() << '\n' << std::endl;
     return 1;
diff --git a/dlg_audiointerface.cpp b/dlg_audiointerface.cpp
index b65c8ff..f95b2d7 100644
--- a/dlg_audiointerface.cpp
+++ b/dlg_audiointerface.cpp
@@ -311,16 +311,17 @@ void AudioInterfaceDialog::OnChoiceChanged(wxCommandEvent& WXUNUSED(event)) {
   }
   p_cho->Clear();
 
-  // std::cout << "\nPred loopou, pldev = " << pldev << " ; recdev = " << recdev ;
-  // compute the new list - find the same values in DevRecList and DevPlayList
-  for (unsigned int i = 0; i < m_DevPlayList.card_info[pldev].sampleRates.size(); i++) {
-    for (unsigned int j = 0; j < m_DevRecList.card_info[recdev].sampleRates.size(); j++) {
-      unsigned long int srateplay = m_DevPlayList.card_info[pldev].sampleRates[i];
-      unsigned long int sraterec = m_DevRecList.card_info[recdev].sampleRates[j];
-
-      if (srateplay == sraterec) {
-        p_cho->Append(wxString::Format(wxT("%ld "), srateplay));
-        if (srateplay == m_freq) cfreq = i;
+  if (0 < m_DevRecList.card_info.size() && 0 < m_DevPlayList.card_info.size()) {
+    // compute the new list - find the same values in DevRecList and DevPlayList
+    for (unsigned int i = 0; i < m_DevPlayList.card_info[pldev].sampleRates.size(); i++) {
+      for (unsigned int j = 0; j < m_DevRecList.card_info[recdev].sampleRates.size(); j++) {
+        unsigned long int srateplay = m_DevPlayList.card_info[pldev].sampleRates[i];
+        unsigned long int sraterec = m_DevRecList.card_info[recdev].sampleRates[j];
+
+        if (srateplay == sraterec) {
+          p_cho->Append(wxString::Format(wxT("%ld "), srateplay));
+          if (srateplay == m_freq) cfreq = i;
+        }
       }
     }
   }