From ec0ed6a057aed897ffa48dea65fce7ba15090697 Mon Sep 17 00:00:00 2001
From: Marek Blok <Marek.Blok@pg.edu.pl>
Date: Sat, 11 Nov 2023 13:04:30 +0100
Subject: [PATCH] Fix: AutoSplitter outputs can be reused

---
 CHANGELOG                 | 10 +++++++++
 src/cpp/DSP_modules.cpp   | 44 +++++++++++++++++++++++++++------------
 src/include/DSP_lib.h     |  2 +-
 src/include/DSP_modules.h | 10 ++++++---
 4 files changed, 49 insertions(+), 17 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 75eda99..fb8f48a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,4 +1,10 @@
 TODO::
+- BUG: When block connected to the output od the autosplitter is deleted number of autosplitter outputs is not reduced.
+  - the new block connected to the output connected to this autospliter generates new autospliter output
+  - [DONE: ver. 0.20.032] minimal correction: reuse unconnected autospliter outputs when new block is connected
+  - best correction: remove unconnected autospliter outputs when its output block is deleted (or its output is freed)
+    - TODO: create minimal example: source => two output blocks : delete one and check scheme for Noname blocks before reconnection
+    - NOTE: if the last output of autosplitter is cleared the autospliter block should be deleted also.
 - DSP::u::Zeroinserter => add variant with possibility to define number of inputs
 
   SOUND_support_t::get_wave_in_raw_buffer - zastąpić metodą zawierającą konwersję typu, ew. rozbudować konwersję w DSP::u::AudioInput
@@ -10,6 +16,10 @@ TODO::
 LAST DONE:
 
 CHANGES:
+- ver. 0.20.032 <b>2023.11.11</b> Fixed:
+  - DSP::Component::AddOutputLine - can now reuse free output line instead of adding new one
+    - This is minimal correction for the bug causing autospliter to have unconnected outputs after block deletion.
+      The unconnected output will now be reused on new connection.
 - ver. 0.20.031 <b>2023.11.10</b> Added:
   - DSP::u::AdjustableDelay - delay block with programaticly controlable delay (betwee 0 and user defined max_delay).
   - examples: echo.cpp - added adjustable delay block use.
diff --git a/src/cpp/DSP_modules.cpp b/src/cpp/DSP_modules.cpp
index 4666772..a89141b 100644
--- a/src/cpp/DSP_modules.cpp
+++ b/src/cpp/DSP_modules.cpp
@@ -1163,7 +1163,7 @@ bool DSP::_connect_class::splitconnect(const DSP::output &output, const DSP::inp
       // +++++++++++++++++++++++++++++++++++++++++++++++++ //
       // AddLine(OUTauto)
       AutoSplitter = ((DSP::u::Splitter *)dest_block);
-      SplitterOutInd = AutoSplitter->AddOutputLine();
+      SplitterOutInd = AutoSplitter->AddOutputLine(true);
       // connect autosplitter new line ==> ANY
       AutoSplitter->SetOutput(SplitterOutInd,
                               source_output_block, source_output_block_input_no);
@@ -1265,7 +1265,7 @@ bool DSP::_connect_class::splitconnect(const DSP::output &output, const DSP::inp
       // AddLine(INauto, OUT)
       // +++++++++++++++++++++++++++++++++++++++++++++++++++ //
       // resize splitter
-      SplitterOutInd = ((DSP::u::Splitter *)(source_block->Convert2Block()))->AddOutputLine();
+      SplitterOutInd = ((DSP::u::Splitter *)(source_block->Convert2Block()))->AddOutputLine(true);
       // +++++++++++++++++++++++++++++++++++++++++++++++++++ //
       // connect autosplitter new line ==> OUT
       source_block->SetOutput(SplitterOutInd,
@@ -1288,7 +1288,7 @@ bool DSP::_connect_class::splitconnect(const DSP::output &output, const DSP::inp
       // AddLine(Auto, OUT)
       // +++++++++++++++++++++++++++++++++++++++++++++++++++ //
       // resize splitter
-      SplitterOutInd = ((DSP::u::Splitter *)source_output_block)->AddOutputLine();
+      SplitterOutInd = ((DSP::u::Splitter *)source_output_block)->AddOutputLine(true);
       // +++++++++++++++++++++++++++++++++++++++++++++++++++ //
       // connect autosplitter new line ==> OUT
       source_output_block->SetOutput(SplitterOutInd,
@@ -1348,7 +1348,7 @@ bool DSP::_connect_class::splitconnect(const DSP::output &output, const DSP::inp
       // resize splitter
       for (tmp_ind = 0; tmp_ind < dest_block->NoOfOutputs; tmp_ind++)
       {
-        SplitterOutInd = AutoSplitter->AddOutputLine();
+        SplitterOutInd = AutoSplitter->AddOutputLine(true);
         // +++++++++++++++++++++++++++++++++++++++++++++++++++ //
         // connect autosplitter new line ==> OUT
         AutoSplitter->SetOutput(SplitterOutInd,
@@ -1377,7 +1377,7 @@ bool DSP::_connect_class::splitconnect(const DSP::output &output, const DSP::inp
       // resize splitter
       for (tmp_ind = 0; tmp_ind < dest_block->NoOfOutputs; tmp_ind++)
       {
-        SplitterOutInd = AutoSplitter->AddOutputLine();
+        SplitterOutInd = AutoSplitter->AddOutputLine(true);
         // +++++++++++++++++++++++++++++++++++++++++++++++++++ //
         // connect autosplitter new line ==> OUT
         AutoSplitter->SetOutput(SplitterOutInd,
@@ -1407,7 +1407,7 @@ bool DSP::_connect_class::splitconnect(const DSP::output &output, const DSP::inp
       // +++++++++++++++++++++++++++++++++++++++++++++++++ //
       // AddLine(OUTauto)
       AutoSplitter = ((DSP::u::Splitter *)dest_block);
-      SplitterOutInd = AutoSplitter->AddOutputLine();
+      SplitterOutInd = AutoSplitter->AddOutputLine(true);
       // connect autosplitter new line ==> ANY
       AutoSplitter->SetOutput(SplitterOutInd,
                               source_output_block, source_output_block_input_no);
@@ -1896,7 +1896,7 @@ void DSP::Component::SetNoOfOutputs(unsigned int No, bool reset)
     {
       OutputClocks[ind] = NULL;
 
-      OutputBlocks[ind] = &DummyBlock;
+      OutputBlocks[ind] = &DSP::Block::DummyBlock;
       OutputBlocks_InputNo[ind] = 0;
     }
   }
@@ -1914,7 +1914,7 @@ void DSP::Component::SetNoOfOutputs(unsigned int No, bool reset)
       else
       {
         OutputClocks[ind] = NULL;
-        OutputBlocks[ind] = &DummyBlock;
+        OutputBlocks[ind] = &DSP::Block::DummyBlock;
         OutputBlocks_InputNo[ind] = 0;
       }
     }
@@ -1929,10 +1929,28 @@ void DSP::Component::SetNoOfOutputs(unsigned int No, bool reset)
   }
 }
 
-int DSP::Component::AddOutputLine(void)
+int DSP::Component::AddOutputLine(const bool &reuse_free_output)
 {
-  SetNoOfOutputs(NoOfOutputs+1, false);
-  return NoOfOutputs-1;
+  int output_index = -1;
+
+  if (reuse_free_output == true) {
+    if (NoOfOutputs > 0) {
+      for (ind=0; ind < NoOfOutputs; ind++)
+      {
+        if (OutputBlocks[ind] == &DSP::Block::DummyBlock) {
+          output_index = ind;
+          break;
+        }
+      }
+    }
+  }
+
+  if (output_index == -1) {
+    // add new output
+    SetNoOfOutputs(NoOfOutputs+1, false);
+    output_index = NoOfOutputs-1;
+  }
+  return output_index;
 }
 
 
@@ -2626,7 +2644,7 @@ void DSP::Block::SetBlockInputClock(unsigned int InputNo, DSP::Clock_ptr InputCl
           for (ind=0; ind<NoOfOutputs; ind++)
           {
             if (OutputBlocks[ind] != NULL)
-              if (OutputBlocks[ind] != &DummyBlock)
+              if (OutputBlocks[ind] != &DSP::Block::DummyBlock)
                 OutputBlocks[ind]->SetBlockInputClock(OutputBlocks_InputNo[ind], NULL);
           }
         }
@@ -11257,7 +11275,7 @@ bool DSP::u::Copy::GetCopyOutput(unsigned int OutputNo, DSP::Block_ptr &output_b
 
   if (OutputNo < NoOfOutputs)
   {
-    if (OutputBlocks[OutputNo] != &DummyBlock)
+    if (OutputBlocks[OutputNo] != &DSP::Block::DummyBlock)
     {
       output_block = OutputBlocks[OutputNo];
       output_block_InputNo = OutputBlocks_InputNo[OutputNo];
diff --git a/src/include/DSP_lib.h b/src/include/DSP_lib.h
index 52cf42b..303e897 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 31 // !!! without zeroes before, else this will be treated as octal number
+#define DSP_VER_BUILD 32 // !!! without zeroes before, else this will be treated as octal number
 #define DSP_VER_YEAR  2023
 #define DSP_VER       DSP_VER_MAJOR.DSP_VER_MINOR.DSP_VER_BUILD
 
diff --git a/src/include/DSP_modules.h b/src/include/DSP_modules.h
index 9bf2483..248f36d 100644
--- a/src/include/DSP_modules.h
+++ b/src/include/DSP_modules.h
@@ -868,9 +868,13 @@ class DSP::Component : public virtual DSP::name, public DSP::_connect_class
     void SetNoOfOutputs(unsigned int No, bool reset = true);
     //! Adds additional output
     /*! Returns index of added output.
-     *  Block connection is preserved.
+     *  Block connections are preserved.
+     * 
+     *  If reuse_free_output == true check if the block has any free unconnected outputs 
+     *  and return its index instead of adding new output line.
+     *  If there are no free outputs, new output line is added.
      */
-    int AddOutputLine(void);
+    int AddOutputLine(const bool &reuse_free_output = false);
 
 
     //! Should be set true if the block must be destroyed automatically
@@ -1563,7 +1567,7 @@ class DSP::Block : public virtual DSP::Component
         UNUSED_ARGUMENT(block);
       #else
         std::stringstream tekst;
-        if (block == &DummyBlock)
+        if (block == &DSP::Block::DummyBlock)
         {
           tekst << "WARNING: Unconnected output detected (" << Caller->GetName() << ")";
         }
-- 
GitLab