diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp
index 03bae6e4abfd7e18765d9c5e6de66a6642d89505..443fa518224679a0220cb97f46ddafe7238c2056 100644
--- a/Source/PluginEditor.cpp
+++ b/Source/PluginEditor.cpp
@@ -16,8 +16,11 @@ Test2AudioProcessorEditor::Test2AudioProcessorEditor(Test2AudioProcessor &p)
   // Make sure that before the constructor has finished, you've set the
   // editor's size to whatever you need it to be.
   addAndMakeVisible(positionLabel);
+  // add a label that will display the current timecode and status..
+  addAndMakeVisible(timecodeDisplayLabel);
+  timecodeDisplayLabel.setFont(juce::Font(juce::Font::getDefaultMonospacedFontName(), 15.0f, juce::Font::plain));
+
   positionLabel.setText("Text input:", juce::dontSendNotification);
-  // positionLabel.attachToComponent(&inputText, true);
   positionLabel.setColour(juce::Label::textColourId, juce::Colours::orange);
   positionLabel.setJustificationType(juce::Justification::right);
   startTimerHz(60);
@@ -40,7 +43,7 @@ void Test2AudioProcessorEditor::paint(juce::Graphics &g)
 
   g.setColour(juce::Colours::white);
   g.setFont(15.0f);
-  g.drawFittedText("1) Position : " + std::to_string(processor.position), getLocalBounds(), juce::Justification::centred, 1);
+  g.drawFittedText("3) Position : " + std::to_string(processor.position), getLocalBounds(), juce::Justification::centred, 1);
   // if (processor.m_flogger)
   //   processor.m_flogger->logMessage("paint called");
 }
@@ -52,7 +55,7 @@ void Test2AudioProcessorEditor::resized()
 
   auto bounds = getLocalBounds();
   positionLabel.setBounds(bounds.removeFromBottom(30).withSizeKeepingCentre(50, 24));
-
+  timecodeDisplayLabel.setBounds(bounds.removeFromTop(26));
   if (processor.m_flogger)
     processor.m_flogger->logMessage(bounds.toString());
 }
diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h
index 271c020321e93922cf90736a005bd889bfffa553..c8ee2268bccefdc8d9475dafc152beac8d218756 100644
--- a/Source/PluginEditor.h
+++ b/Source/PluginEditor.h
@@ -29,7 +29,7 @@ private:
   // access the processor object that created it.
   Test2AudioProcessor &processor;
   // is this the way
-  juce::Label positionLabel; // = juce::Label("Position", "Position : 0");
+  juce::Label positionLabel, timecodeDisplayLabel; // = juce::Label("Position", "Position : 0");
   // or something like
   //juce::Label positionLabel = {"Position"};
 
@@ -40,7 +40,55 @@ private:
   void timerCallback() override
   {
     positionLabel.setText("Pos : " + std::to_string(processor.position), juce::dontSendNotification);
+    updateTimecodeDisplay(processor.lastPosInfo);
     repaint();
   }
+  // Updates the text in our position label.
+  void updateTimecodeDisplay(juce::AudioPlayHead::CurrentPositionInfo pos)
+  {
+    juce::MemoryOutputStream displayText;
+
+    displayText << "[" << juce::SystemStats::getJUCEVersion() << "]   "
+                << juce::String(pos.bpm, 2) << " bpm, "
+                << pos.timeSigNumerator << '/' << pos.timeSigDenominator
+                << "  -  " << timeToTimecodeString(pos.timeInSeconds)
+                << "  -  " << quarterNotePositionToBarsBeatsString(pos.ppqPosition, pos.timeSigNumerator, pos.timeSigDenominator);
+
+    if (pos.isRecording)
+      displayText << "  (recording)";
+    else if (pos.isPlaying)
+      displayText << "  (playing)";
+
+    timecodeDisplayLabel.setText(displayText.toString(), juce::dontSendNotification);
+  }
+
+  //==============================================================================
+  // quick-and-dirty function to format a timecode string
+  static juce::String timeToTimecodeString(double seconds)
+  {
+    auto millisecs = juce::roundToInt(seconds * 1000.0);
+    auto absMillisecs = std::abs(millisecs);
+
+    return juce::String::formatted("%02d:%02d:%02d.%03d",
+                                   millisecs / 3600000,
+                                   (absMillisecs / 60000) % 60,
+                                   (absMillisecs / 1000) % 60,
+                                   absMillisecs % 1000);
+  }
+  // quick-and-dirty function to format a bars/beats string
+  static juce::String quarterNotePositionToBarsBeatsString(double quarterNotes, int numerator, int denominator)
+  {
+    if (numerator == 0 || denominator == 0)
+      return "1|1|000";
+
+    auto quarterNotesPerBar = (numerator * 4 / denominator);
+    auto beats = (fmod(quarterNotes, quarterNotesPerBar) / quarterNotesPerBar) * numerator;
+
+    auto bar = ((int)quarterNotes) / quarterNotesPerBar + 1;
+    auto beat = ((int)beats) + 1;
+    auto ticks = ((int)(fmod(beats, 1.0) * 960.0 + 0.5));
+
+    return juce::String::formatted("%d|%d|%03d", bar, beat, ticks);
+  }
   JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Test2AudioProcessorEditor)
 };
diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp
index 9612e862d6f2517bc0e6444346b9f8a9ef87a567..0dabedddebde8f8aaf9f8ea81e3f48698789fd55 100644
--- a/Source/PluginProcessor.cpp
+++ b/Source/PluginProcessor.cpp
@@ -26,6 +26,12 @@ Test2AudioProcessor::Test2AudioProcessor()
 
     position = 0;
 
+    addParameter(gain = new juce::AudioParameterFloat("no_gain", // parameter ID
+                                                      "NoGain",  // parameter name
+                                                      0.0f,      // minimum value
+                                                      1.0f,      // maximum value
+                                                      0.5f));    // default value
+
     if (m_flogger)
         m_flogger->logMessage("PluginProcessor");
 }
@@ -204,12 +210,15 @@ void Test2AudioProcessor::getStateInformation(juce::MemoryBlock &destData)
     // You should use this method to store your parameters in the memory block.
     // You could do that either as raw data, or use the XML or ValueTree classes
     // as intermediaries to make it easy to save and load complex data.
+    juce::MemoryOutputStream(destData, true).writeFloat(*gain);
 }
 
 void Test2AudioProcessor::setStateInformation(const void *data, int sizeInBytes)
 {
     // You should use this method to restore your parameters from this memory block,
     // whose contents will have been created by the getStateInformation() call.
+
+    *gain = juce::MemoryInputStream(data, static_cast<size_t>(sizeInBytes), false).readFloat();
 }
 
 //==============================================================================
diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h
index 06e1bb4d02e8c30f46c7cdf05883e1aeeef97e97..6c52255e22c5df79a528b6ff079287781457b1ee 100644
--- a/Source/PluginProcessor.h
+++ b/Source/PluginProcessor.h
@@ -55,8 +55,30 @@ public:
 
   std::unique_ptr<juce::FileLogger> m_flogger;
   int position;
+  // this keeps a copy of the last set of time info that was acquired during an audio
+  // callback - the UI component will read this and display it.
+  juce::AudioPlayHead::CurrentPositionInfo lastPosInfo;
+
+  void updateCurrentTimeInfoFromHost()
+  {
+    if (auto *ph = getPlayHead())
+    {
+      juce::AudioPlayHead::CurrentPositionInfo newTime;
+
+      if (ph->getCurrentPosition(newTime))
+      {
+        lastPosInfo = newTime; // Successfully got the current time from the host..
+        return;
+      }
+    }
+
+    // If the host fails to provide the current time, we'll just reset our copy to a default..
+    lastPosInfo.resetToDefault();
+  }
 
 private:
+  //==============================================================================
+  juce::AudioParameterFloat *gain;
   //==============================================================================
   JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Test2AudioProcessor)
 };