changeset 275:ce2bab04f155

- Imported file input using libsndfile from old AIM-C and updated to the new API - Modified the Module base class to propogate Reset() calls down the module chain. - This required changing all Reset() functions in subclasses to ResetInternal() - Removed some unneeded imports from the Gaussians test
author tomwalters
date Tue, 16 Feb 2010 18:00:16 +0000
parents 3640d25b65ab
children a57b29e373c7
files trunk/SConstruct trunk/src/Modules/BMM/ModulePZFC.cc trunk/src/Modules/BMM/ModulePZFC.h trunk/src/Modules/Features/ModuleGaussians.cc trunk/src/Modules/Features/ModuleGaussians.h trunk/src/Modules/Features/ModuleGaussians_test.py trunk/src/Modules/Input/ModuleFileInput.cc trunk/src/Modules/Input/ModuleFileInput.h trunk/src/Modules/NAP/ModuleHCL.cc trunk/src/Modules/NAP/ModuleHCL.h trunk/src/Modules/SAI/ModuleSAI.cc trunk/src/Modules/SAI/ModuleSAI.h trunk/src/Support/Module.cc trunk/src/Support/Module.h
diffstat 14 files changed, 271 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/trunk/SConstruct	Tue Feb 16 13:23:23 2010 +0000
+++ b/trunk/SConstruct	Tue Feb 16 18:00:16 2010 +0000
@@ -95,7 +95,8 @@
 common_sources = ['Support/Common.cc',
                   'Support/SignalBank.cc',
                   'Support/Parameters.cc',
-                  'Support/Module.cc', 
+                  'Support/Module.cc',
+                  'Modules/Input/ModuleFileInput.cc',
                   'Modules/BMM/ModulePZFC.cc',
                   'Modules/NAP/ModuleHCL.cc',
                   #'Modules/SAI/ModuleSAI.cc',
@@ -116,7 +117,11 @@
 env.Append(CPPPATH = '#src')
 
 # Dependencies
-deplibs = ''
+deplibs = ['sndfile']
+
+for depname in deplibs:
+  env.ParseConfig('pkg-config --cflags --libs ' + depname)
+
 env.AppendUnique(LIBS = deplibs)
 
 # Set up the builder to build the program
--- a/trunk/src/Modules/BMM/ModulePZFC.cc	Tue Feb 16 13:23:23 2010 +0000
+++ b/trunk/src/Modules/BMM/ModulePZFC.cc	Tue Feb 16 18:00:16 2010 +0000
@@ -73,12 +73,12 @@
     return false;
 
   // This initialises all buffers which can be modified by Process()
-  Reset();
+  ResetInternal();
 
   return true;
 }
 
-void ModulePZFC::Reset() {
+void ModulePZFC::ResetInternal() {
   // These buffers may be actively modified by the algorithm
   agc_state_.clear();
   agc_state_.resize(channel_count_);
--- a/trunk/src/Modules/BMM/ModulePZFC.h	Tue Feb 16 13:23:23 2010 +0000
+++ b/trunk/src/Modules/BMM/ModulePZFC.h	Tue Feb 16 18:00:16 2010 +0000
@@ -43,10 +43,10 @@
   //! \brief Process a buffer
   virtual void Process(const SignalBank &input);
 
-  //! \brief Reset all internal state variables to their initial values
-  virtual void Reset();
+ private:
+   //! \brief Reset all internal state variables to their initial values
+   virtual void ResetInternal();
 
- private:
   //! \brief Prepare the module
   //! \param input Input SignalBank
   //! \param output true on success false on failure
--- a/trunk/src/Modules/Features/ModuleGaussians.cc	Tue Feb 16 13:23:23 2010 +0000
+++ b/trunk/src/Modules/Features/ModuleGaussians.cc	Tue Feb 16 18:00:16 2010 +0000
@@ -77,7 +77,7 @@
   return true;
 }
 
-void ModuleGaussians::Reset() {
+void ModuleGaussians::ResetInternal() {
   m_pSpectralProfile.clear();
   m_pSpectralProfile.resize(m_iNumChannels, 0.0f);
 }
--- a/trunk/src/Modules/Features/ModuleGaussians.h	Tue Feb 16 13:23:23 2010 +0000
+++ b/trunk/src/Modules/Features/ModuleGaussians.h	Tue Feb 16 18:00:16 2010 +0000
@@ -48,14 +48,14 @@
   //! \brief Process a buffer
   virtual void Process(const SignalBank &input);
 
+ private:
   //! \brief Reset the internal state of the module
-  void Reset();
+  virtual void ResetInternal();
 
- private:
-    /*! \brief Prepare the module
-     *  \param input Input signal
-     *  \param output true on success false on failure
-     */
+  /*! \brief Prepare the module
+   *  \param input Input signal
+   *  \param output true on success false on failure
+   */
   virtual bool InitializeInternal(const SignalBank &input);
 
   bool RubberGMMCore(int iNumComponents, bool bDoInit);
--- a/trunk/src/Modules/Features/ModuleGaussians_test.py	Tue Feb 16 13:23:23 2010 +0000
+++ b/trunk/src/Modules/Features/ModuleGaussians_test.py	Tue Feb 16 18:00:16 2010 +0000
@@ -22,13 +22,11 @@
 Created by Thomas Walters on 2010-02-15.
 Copyright 2010 Thomas Walters <tom@acousticscale.org>
 Test for the Gaussians module. Runs a number of pre-computed SAI profiles
-through the module, and tests them against the equivalent output from the
+through the module, and tests them against the saved output from the
 MATLAB rubber_GMM code.
 """
 
 import aimc
-import matplotlib
-import pylab
 from scipy import io
 
 def main():
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trunk/src/Modules/Input/ModuleFileInput.cc	Tue Feb 16 18:00:16 2010 +0000
@@ -0,0 +1,139 @@
+// Copyright 2006-2010, Willem van Engen, Thomas Walters
+//
+// AIM-C: A C++ implementation of the Auditory Image Model
+// http://www.acousticscale.org/AIMC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+/*! \file
+ *  \brief Audio file input
+ *
+ *  \author Willem van Engen <cnbh@willem.engen.nl>
+ *  \author Thomas Walters <tom@acousticscale.org>
+ *  \date created 2006/09/21
+ *  \version \$Id$
+ */
+
+#include <vector>
+
+#include "Modules/Input/ModuleFileInput.h"
+
+namespace aimc {
+ModuleFileInput::ModuleFileInput(Parameters *params) : Module(params) {
+	file_handle_ = NULL;
+	buffer_length_ = parameters_->DefaultInt("input.buffersize", 1024);
+
+  file_position_samples_ = 0;
+  file_loaded_ = false;
+  audio_channels_ = 0;
+  buffer_length_ = 0;
+  sample_rate_ = 0.0f;
+}
+
+ModuleFileInput::~ModuleFileInput() {
+  if (file_handle_)
+	  sf_close(file_handle_);
+}
+
+void ModuleFileInput::ResetInternal() {
+  output_.Initialize(audio_channels_, buffer_length_, sample_rate_);
+  output_.set_start_time(0);
+}
+
+bool ModuleFileInput::LoadFile(const char* filename) {
+	// Open the file
+	SF_INFO sfinfo;
+	memset((void*)&sfinfo, 0, sizeof(SF_INFO));
+	file_handle_ = sf_open(filename, SFM_READ, &sfinfo);
+
+	if (file_handle_ == NULL) {
+		//! \todo Also display error reason
+		LOG_ERROR(_T("Couldn't read audio file '%s'"), filename);
+		return false;
+	}
+
+  file_loaded_ = true;
+  audio_channels_ = sfinfo.channels;
+  sample_rate_ = sfinfo.samplerate;
+	file_position_samples_ = 0;
+
+  // A dummy signal bank to be passed to the Initialize() function.
+  SignalBank s;
+  s.Initialize(1, 1, 1);
+
+	// Self-initialize by calling Module::Initialize() explicitly. 
+	// The Initialize() call in this subclass is overloaded to prevent it from
+	// being called drectly. 
+  return Module::Initialize(s);
+}
+
+bool ModuleFileInput::Initialize(const SignalBank& input) {
+  LOG_ERROR(_T("Do not call Initialize() on ModuleFileInput directly "
+               "instead call LoadFile() with a filename to load. "
+               "This will automatically initialize the module."));
+  return false;
+}
+
+void ModuleFileInput::Process(const SignalBank& input) {
+  LOG_ERROR(_T("Call Process() on ModuleFileInput instead of passing in "
+               "a SignalBank"));
+}
+
+bool ModuleFileInput::InitializeInternal(const SignalBank& input) {
+  if (!file_loaded_)
+    return false;
+  ResetInternal();
+	return true;
+}
+
+void ModuleFileInput::Process() {
+	sf_count_t read;
+  vector<float> buffer;
+  buffer.resize(buffer_length_ * audio_channels_);
+
+  while (true) {
+	  // Read buffersize bytes into buffer
+	  read = sf_readf_float(file_handle_, &buffer[0], buffer_length_);
+
+    // Place the contents of the buffer into the signal bank
+    int counter = 0;
+    for (int c = 0; c < audio_channels_; ++c) {
+      for (int i = 0; i < read; ++i) {
+        output_.set_sample(c, i, buffer[counter]);
+        ++counter;
+      }
+    }
+
+	  // If the number of saples read is less than the buffer length, the end 
+	  // of the file has been reached.
+	  if (read < buffer_length_) {
+		  // Zero samples at end
+		  for (int c = 0; c < audio_channels_; ++c) {
+        for (int i = read; i < buffer_length_; ++i) {
+          output_.set_sample(c, i, 0.0f);
+        }
+      }
+		  // When we're past the end of the buffer, stop looping.
+		  if (read == 0)
+        break;
+	  }
+
+	  // Update time
+	  output_.set_start_time(file_position_samples_);
+	  file_position_samples_ += read;
+
+    PushOutput();
+  }
+}
+}  // namespace aimc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trunk/src/Modules/Input/ModuleFileInput.h	Tue Feb 16 18:00:16 2010 +0000
@@ -0,0 +1,80 @@
+// Copyright 2006-2010, Willem van Engen, Thomas Walters
+//
+// AIM-C: A C++ implementation of the Auditory Image Model
+// http://www.acousticscale.org/AIMC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+/*! \file
+ *  \brief Audio file input
+ *
+ *  \author Willem van Engen <cnbh@willem.engen.nl>
+ *  \author Thomas Walters <tom@acousticscale.org>
+ *  \date created 2006/09/21
+ *  \version \$Id$
+ */
+
+#ifndef _AIMC_MODULES_INPUT_FILE_H_
+#define _AIMC_MODULES_INPUT_FILE_H_
+
+#include <sndfile.h>
+
+#include "Support/Module.h"
+#include "Support/Parameters.h"
+#include "Support/SignalBank.h"
+
+namespace aimc {
+class ModuleFileInput : public Module {
+ public:
+	ModuleFileInput(Parameters *pParam);
+	virtual ~ModuleFileInput();
+
+	/*! \brief Initializes this input device using an audio file
+	 *  \param sFilename Path of the file to load
+	 *  \return true on success, false on error
+	 */
+	bool LoadFile(const char *sFilename);
+
+  //! \brief Process the loaded file.
+  void Process();
+
+  //! \brief Dummy Initialize function. Call LoadFile instead.
+  virtual bool Initialize(const SignalBank &input);
+
+  //! \brief Dummy funciton to comply with the Module specification. Gives an 
+  //  error message when called.
+  virtual void Process(const SignalBank &input);
+
+ private:
+  //! \brief Prepare the module
+  //! \param input Input SignalBank
+  //! \param output true on success false on failure
+  virtual bool InitializeInternal(const SignalBank &input);
+
+  //! \brief Rewind to the start of the file
+  virtual void ResetInternal();
+
+	//! \brief File descriptor
+	SNDFILE *file_handle_;
+
+	//! \brief Current position in time of the file
+  int file_position_samples_;
+  bool file_loaded_;
+  int audio_channels_;
+  int buffer_length_;
+  float sample_rate_;
+};
+}  // namespace aimc
+
+#endif // _AIMC_MODULES_INPUT_FILE_H_
--- a/trunk/src/Modules/NAP/ModuleHCL.cc	Tue Feb 16 13:23:23 2010 +0000
+++ b/trunk/src/Modules/NAP/ModuleHCL.cc	Tue Feb 16 18:00:16 2010 +0000
@@ -50,11 +50,11 @@
   time_constant_ = 1.0f / (2.0f * M_PI * lowpass_cutoff_);
   channel_count_ = input.channel_count();
   output_.Initialize(input);
-  Reset();
+  ResetInternal();
   return true;
 }
 
-void ModuleHCL::Reset() {
+void ModuleHCL::ResetInternal() {
   xn_ = 0.0f;
   yn_ = 0.0f;
   yns_.clear();
--- a/trunk/src/Modules/NAP/ModuleHCL.h	Tue Feb 16 13:23:23 2010 +0000
+++ b/trunk/src/Modules/NAP/ModuleHCL.h	Tue Feb 16 18:00:16 2010 +0000
@@ -42,7 +42,6 @@
   virtual ~ModuleHCL();
 
   virtual void Process(const SignalBank &input);
-  virtual void Reset();
 
  private:
   /*! \brief Prepare the module
@@ -51,6 +50,8 @@
    */
   virtual bool InitializeInternal(const SignalBank &input);
 
+  virtual void ResetInternal();
+
   //! \brief Do lowpass filtering?
   bool do_lowpass_;
 
--- a/trunk/src/Modules/SAI/ModuleSAI.cc	Tue Feb 16 13:23:23 2010 +0000
+++ b/trunk/src/Modules/SAI/ModuleSAI.cc	Tue Feb 16 18:00:16 2010 +0000
@@ -111,7 +111,7 @@
   return true;
 }
 
-void ModuleSAI::Reset() {
+void ModuleSAI::ResetInternal() {
 }
 
 void ModuleSAI::Process(const SignalBank &input) {
--- a/trunk/src/Modules/SAI/ModuleSAI.h	Tue Feb 16 13:23:23 2010 +0000
+++ b/trunk/src/Modules/SAI/ModuleSAI.h	Tue Feb 16 18:00:16 2010 +0000
@@ -40,7 +40,6 @@
   ModuleSAI(Parameters *parameters);
   virtual ~ModuleSAI();
   void Process(const SignalBank &input);
-  void Reset();
 
  private:
   /*! \brief Prepare the module
@@ -49,6 +48,8 @@
    */
   bool InitializeInternal(const SignalBank &input);
 
+  virtual void ResetInternal();
+
   //! \brief Temporary buffer for constructing the current SAI frame
   SignalBank sai_temp_;
 
--- a/trunk/src/Support/Module.cc	Tue Feb 16 13:23:23 2010 +0000
+++ b/trunk/src/Support/Module.cc	Tue Feb 16 18:00:16 2010 +0000
@@ -78,6 +78,19 @@
   return true;
 }
 
+void Module::Reset() {
+  if (!initialized_)
+    return;
+
+  ResetInternal();
+
+  // Iterate through all the targets of this module, resetting
+  // them.
+  set<Module*>::const_iterator it;
+  for (it = targets_.begin(); it != targets_.end(); ++it)
+    (*it)->Reset();
+}
+
 bool Module::initialized() const {
   return initialized_;
 }
--- a/trunk/src/Support/Module.h	Tue Feb 16 13:23:23 2010 +0000
+++ b/trunk/src/Support/Module.h	Tue Feb 16 18:00:16 2010 +0000
@@ -72,8 +72,14 @@
    * any targets of the module if necessary.
    * \param input Input SignalBank.
    * \param output true on success, false on failure.
+   *
+   * Note that in most instances when creating a new module, it is better to 
+   * simply implement the pure virtual function InitializeInternal(), rather
+   * than refining a new Initialize. The only reason that Initialize() is made
+   * virtual is to deal with the edge case of input modules which do not take 
+   * a SignalBank as input, but rather generate their own input.
    */
-  bool Initialize(const SignalBank &input);
+  virtual bool Initialize(const SignalBank &input);
 
   /*! \brief
    */
@@ -98,10 +104,10 @@
    */
   virtual void Process(const SignalBank &input) = 0;
 
-  /*! \brief Reset the internal state of the module to that when it was
-   * initialised
+  /*! \brief Reset the internal state of this module and all its children to
+   *  their initial state.
    */
-  virtual void Reset() = 0;
+  void Reset() ;
 
   /*! \brief
    */
@@ -110,6 +116,8 @@
  protected:
   void PushOutput();
 
+  virtual void ResetInternal() = 0;
+
   virtual bool InitializeInternal(const SignalBank &input) = 0;
 
   bool initialized_;