From 93e9a127b879bce8e7d73de201efa787afed08aa Mon Sep 17 00:00:00 2001
From: Marek Blok <Marek.Blok@pg.edu.pl>
Date: Fri, 10 Sep 2021 09:46:18 +0200
Subject: [PATCH] DSP::WMM_object_t and DSP::SOUND_object_t minor fix

---
 CHANGELOG                  |  3 +++
 src/cpp/ALSA_support.cpp   |  4 ++--
 src/cpp/DSP_IO.cpp         |  2 +-
 src/cpp/WMM_support.cpp    | 43 ++++++++++++++++++++++++++++++++++----
 src/include/ALSA_support.h |  2 +-
 src/include/DSP_lib.h      |  2 +-
 src/include/DSP_types.h    |  7 ++++++-
 src/include/WMM_support.h  |  3 ++-
 8 files changed, 55 insertions(+), 11 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index d861133..0b860c4 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -6,6 +6,9 @@ TODO::
 LAST DONE:
 
 CHANGES:
+- ver. 0.20.009 - <b>2021.09.10</b> Changed: 
+  - Fixed: DSP::WMM_object_t and DSP::SOUND_object_t now send to sound card all pending data and wait for finish before closing
+
 - ver. 0.20.008 - <b>2021.05.16</b> Changed: 
   - Added SOUND_object_t::get_wave_in_raw_buffer for non-callback input operations
   - DSP::u::AudioInput now falls back to non-callback mode if SOUND_object_t doesn't support callbacks
diff --git a/src/cpp/ALSA_support.cpp b/src/cpp/ALSA_support.cpp
index 00a65d9..a54f695 100644
--- a/src/cpp/ALSA_support.cpp
+++ b/src/cpp/ALSA_support.cpp
@@ -281,9 +281,9 @@ bool DSP::ALSA_object_t::close_PCM_device_input(void) {
   return true;
 }
 
-bool DSP::ALSA_object_t::close_PCM_device_output(void) {
+bool DSP::ALSA_object_t::close_PCM_device_output(bool do_drain) {
   assert(!"DSP::ALSA_object_t::close_PCM_device_output not implemented yet");
-  close_alsa_device(true);
+  close_alsa_device(do_drain);
   return true;
 }
 
diff --git a/src/cpp/DSP_IO.cpp b/src/cpp/DSP_IO.cpp
index 7187567..c5a112a 100644
--- a/src/cpp/DSP_IO.cpp
+++ b/src/cpp/DSP_IO.cpp
@@ -4179,7 +4179,7 @@ DSP::u::AudioOutput::~AudioOutput()
   { // if device was opened successfully
     snd_object.stop_playback();
 
-    snd_object.close_PCM_device_output();
+    snd_object.close_PCM_device_output(true);
 
     // #ifdef WINMMAPI
     //   result = waveOutReset(hWaveOut);
diff --git a/src/cpp/WMM_support.cpp b/src/cpp/WMM_support.cpp
index 6c50e81..f935df6 100644
--- a/src/cpp/WMM_support.cpp
+++ b/src/cpp/WMM_support.cpp
@@ -30,7 +30,7 @@ DSP::WMM_object_t::~WMM_object_t()
     close_PCM_device_input();
   }
   if (is_device_output_open) {
-    close_PCM_device_output();
+    close_PCM_device_output(true);
   }
 
 }
@@ -139,7 +139,21 @@ unsigned int DSP::WMM_object_t::select_input_device_by_number(const unsigned int
 
 bool DSP::WMM_object_t::stop_playback(void) {
   StopPlayback = true;
-  //! \TODO can we do more ?
+
+  // if there are still buffers that haven't been yet sent to sound card then do it now
+  if (IsPlayingNow == false)
+  {
+    if (NextBufferOutInd == DSP::NoOfAudioOutputBuffers - 2) //all but one spare buffer are filled up
+    { // send all data from buffers to soundcard to start playback
+      for (unsigned int ind=0; ind < DSP::NoOfAudioOutputBuffers-1; ind++) //one spare buffer
+      {
+        result=waveOutWrite(hWaveOut,
+          &(waveHeaderOut[ind]), sizeof(WAVEHDR));
+        DSP::f::AudioCheckError(result);
+      }
+      IsPlayingNow = true;
+    }
+  }
 
   return true;
 }
@@ -269,7 +283,7 @@ long DSP::WMM_object_t::open_PCM_device_4_output(const int &no_of_channels, int
   if (is_device_output_open)
   {
     DSP::log << "DSP::WMM_object_t::open_PCM_device_4_output" << DSP::e::LogMode::second << "Device has been already opened: closing device before reopening" << endl;
-    close_PCM_device_output();
+    close_PCM_device_output(false);
   }
 
   switch (no_of_bits)
@@ -390,7 +404,28 @@ bool DSP::WMM_object_t::close_PCM_device_input(void) {
   return true;
 }
 
-bool DSP::WMM_object_t::close_PCM_device_output(void) {
+bool DSP::WMM_object_t::close_PCM_device_output(const bool &do_drain) {
+  stop_playback(); // just to be sure that all prepared buffershave been sent to sound card
+
+  if (do_drain == true) {
+    bool still_playing = true;
+    while (still_playing) {
+      int counter = 0;
+      for (unsigned int ind=0; ind < DSP::NoOfAudioOutputBuffers; ind++) //one spare buffer
+      {
+        if (waveHeaderOut[NextBufferOutInd].dwFlags & WHDR_DONE)
+          counter++;
+      }
+      if (counter == DSP::NoOfAudioOutputBuffers) {
+        still_playing = false;
+      }
+      else {
+        // let system process others and then check again
+        DSP::f::Sleep(0);
+      }
+    }
+  }
+
   result = waveOutReset(hWaveOut);
   DSP::f::AudioCheckError(result);
   
diff --git a/src/include/ALSA_support.h b/src/include/ALSA_support.h
index 7e803fb..5d413b7 100644
--- a/src/include/ALSA_support.h
+++ b/src/include/ALSA_support.h
@@ -42,7 +42,7 @@ namespace DSP {
         long open_PCM_device_4_output(const int &no_of_channels, int no_of_bits, const long &sampling_rate, const long &audio_outbuffer_size = -1);
         long open_PCM_device_4_input(const int &no_of_channels, int no_of_bits, const long &sampling_rate, const long &audio_inbuffer_size = -1);
         bool close_PCM_device_input(void);
-        bool close_PCM_device_output(void);
+        bool close_PCM_device_output(const bool &do_drain);
 
         //! returns true is the playback is on
         bool is_device_playing(void);
diff --git a/src/include/DSP_lib.h b/src/include/DSP_lib.h
index bca9649..e0ff366 100644
--- a/src/include/DSP_lib.h
+++ b/src/include/DSP_lib.h
@@ -11,7 +11,7 @@
 
 #define DSP_VER_MAJOR 0
 #define DSP_VER_MINOR 20
-#define DSP_VER_BUILD 8 // !!! without zeroes before, else this will be treated as octal number
+#define DSP_VER_BUILD 9 // !!! without zeroes before, else this will be treated as octal number
 #define DSP_VER_YEAR  2021
 #define DSP_VER       DSP_VER_MAJOR.DSP_VER_MINOR.DSP_VER_BUILD
 
diff --git a/src/include/DSP_types.h b/src/include/DSP_types.h
index a99afd5..ffbd22d 100644
--- a/src/include/DSP_types.h
+++ b/src/include/DSP_types.h
@@ -573,11 +573,16 @@ namespace DSP {
       //! audio_inbuffer_size is in samples (note that, for example, sample for 16bit stereo is represented by 4bytes)
       virtual long open_PCM_device_4_input(const int &no_of_channels, int no_of_bits, const long &sampling_rate, const long &audio_inbuffer_size = -1) = 0;
       virtual bool close_PCM_device_input(void) = 0;
-      virtual bool close_PCM_device_output(void) = 0;
+      //! close sound card output
+      /*! if do_drain == true wait until sound card stops playing 
+       */ 
+      virtual bool close_PCM_device_output(const bool &do_drain) = 0;
 
       //! returns true is the playback is on
       virtual bool is_device_playing(void) = 0;
       //! initializes playback stopping
+      /*! If there are still buffers that haven't been yet sent to sound card then do it now
+       */
       virtual bool stop_playback(void) = 0;
       //! returns true is the sound capture is on
       virtual bool is_device_recording(void) = 0;
diff --git a/src/include/WMM_support.h b/src/include/WMM_support.h
index 63af568..05f907f 100644
--- a/src/include/WMM_support.h
+++ b/src/include/WMM_support.h
@@ -83,8 +83,9 @@ namespace DSP {
         //! opens default PCM device for capture and returns selected sampling rate on success or negative error code
         long open_PCM_device_4_input(const int &no_of_channels, int no_of_bits, const long &sampling_rate, const long &audio_inbuffer_size = -1);
 
+
         bool close_PCM_device_input(void);
-        bool close_PCM_device_output(void);
+        bool close_PCM_device_output(const bool &do_drain);
 
         bool stop_playback(void);
         bool stop_recording(void);
-- 
GitLab