changeset 237:af02b6addf7a

- Added support for movies!
author tomwalters
date Thu, 21 Oct 2010 01:46:39 +0000
parents 4fb328f81012
children 7d58df46329f
files SConstruct src/Configurations/SAI_movie.aimcconfig src/Main/AIMCopy.cc src/Modules/Output/Graphics/Devices/GraphicsOutputDevice.cc src/Modules/Output/Graphics/Devices/GraphicsOutputDevice.h src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceCairo.cc src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceCairo.h src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.cc src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.h src/Modules/Output/Graphics/Devices/GraphicsOutputDevicewxGLCanvas.cc src/Modules/Output/Graphics/GraphAxisSpec.cc src/Modules/Output/Graphics/GraphicsView.cc src/Modules/Output/Graphics/GraphicsView.h src/Modules/Output/Graphics/GraphicsViewTime.cc src/Modules/Output/Graphics/GraphicsViewTime.h src/Modules/SSI/ModuleSSI.cc swig/aim_modules.i swig/example.py swig/setup.py
diffstat 19 files changed, 254 insertions(+), 230 deletions(-) [+]
line wrap: on
line diff
--- a/SConstruct	Tue Oct 19 19:48:37 2010 +0000
+++ b/SConstruct	Thu Oct 21 01:46:39 2010 +0000
@@ -137,7 +137,7 @@
 elif compiler == 'gcc':
   env['STRIP'] = 'strip'
   env.AppendUnique(CPPFLAGS = ['-Wall'])
-  env.AppendUnique(CPPFLAGS = ['-O2',])# '-fomit-frame-pointer'])
+  env.AppendUnique(CPPFLAGS = ['-O1',])# '-fomit-frame-pointer'])
   if env['symbols']:
     env.AppendUnique(CPPFLAGS = ['-g'])
   if env['mingw']:
--- a/src/Configurations/SAI_movie.aimcconfig	Tue Oct 19 19:48:37 2010 +0000
+++ b/src/Configurations/SAI_movie.aimcconfig	Thu Oct 21 01:46:39 2010 +0000
@@ -27,6 +27,5 @@
 graph.y.max=0.5
 graph.freq.label=Cochlear Channel
 graph.x.label=Time Interval
-graph.type=colormap
-output.images=true
+graph.type=line
 ENDPARAMS
--- a/src/Main/AIMCopy.cc	Tue Oct 19 19:48:37 2010 +0000
+++ b/src/Main/AIMCopy.cc	Thu Oct 21 01:46:39 2010 +0000
@@ -111,6 +111,7 @@
       LOG_ERROR(_T("Failed to initialize tree."));
       return false;
     }
+    tree_.Reset();
   } else {
     LOG_ERROR(_T("No input files in script."));
     return false;
@@ -167,8 +168,8 @@
     aimc::LOG_INFO(_T("%s -> %s"),
                   script_[i].first.c_str(),
                   script_[i].second.c_str());
+    tree_.Process();
     tree_.Reset();
-    tree_.Process();
   }
   return true;
 }
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDevice.cc	Tue Oct 19 19:48:37 2010 +0000
+++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDevice.cc	Thu Oct 21 01:46:39 2010 +0000
@@ -20,8 +20,8 @@
 
 namespace aimc {
 
-GraphicsOutputDevice::GraphicsOutputDevice(Parameters *pParam) {
-  m_pParam = pParam;
+GraphicsOutputDevice::GraphicsOutputDevice(Parameters *parameters) {
+  parameters_ = parameters;
 }
 
 void GraphicsOutputDevice::gVertex3f(float x,
@@ -49,8 +49,8 @@
 
 void GraphicsOutputDevice::gText2f(float x,
                                    float y,
-                                   const char *sStr,
-                                   bool bRotated) {
-  gText3f(x, y, 0, sStr, bRotated);
+                                   const char *text_string,
+                                   bool rotated) {
+  gText3f(x, y, 0, text_string, rotated);
 }
 }  // namespace aimc
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDevice.h	Tue Oct 19 19:48:37 2010 +0000
+++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDevice.h	Thu Oct 21 01:46:39 2010 +0000
@@ -1,4 +1,4 @@
-// Copyright 2006, Willem van Engen
+// Copyright 2006-2010, Willem van Engen, Thomas Walters
 //
 // AIM-C: A C++ implementation of the Auditory Image Model
 // http://www.acousticscale.org/AIMC
@@ -81,12 +81,15 @@
    *
    *  \sa Module::Initialize()
    */
-  virtual bool Initialize(unsigned int iVerticesMax) { return true; };
+
   /*! \overload
    *  This function reloads the parameters; make sure to have at least the
    *  function with maximum parameters called once.
    */
-  virtual bool Initialize() { return true; };
+  virtual bool Initialize(Parameters *global_parameters) {
+    global_parameters_ = global_parameters;
+    return true;
+  };
 
   /*! \brief Create a new drawing
    *  Run this before any other drawing command.
@@ -184,7 +187,8 @@
   //! \brief True when animation is running
   bool m_bRunning;
   //! \brief Parameter store
-  Parameters *m_pParam;
+  Parameters *parameters_;
+  Parameters *global_parameters_;
 
   //! \brief Pixel Formats
   enum PixelFormat {AIM_PIX_FMT_RGB24_32, AIM_PIX_FMT_RGB24_24};
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceCairo.cc	Tue Oct 19 19:48:37 2010 +0000
+++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceCairo.cc	Thu Oct 21 01:46:39 2010 +0000
@@ -1,4 +1,4 @@
-// Copyright 2007, Thomas Walters
+// Copyright 2007-2010, Thomas Walters, Willem van Engen
 //
 // AIM-C: A C++ implementation of the Auditory Image Model
 // http://www.acousticscale.org/AIMC
@@ -32,6 +32,8 @@
 #include <stdio.h>
 #include <math.h>
 
+#include "cairo-quartz.h"
+
 #include "Modules/Output/Graphics/Devices/GraphicsOutputDeviceCairo.h"
 
 namespace aimc {
@@ -42,47 +44,58 @@
   m_iFileNumber = 0;
   m_iVertexType = VertexTypeNone;
   m_bUseMemoryBuffer=false;
-  m_pParam->DefaultString("output.img.format", ".png");
+  parameters_->DefaultString("output.img.format", ".png");
 }
 
-bool GraphicsOutputDeviceCairo::Initialize(const char *sDir) {
-  Init();
-
-  //! \todo Output to file if sDir is a file, to directory with
-  //! multiple images if it's a directory.
-  strncpy(m_sDir, sDir, sizeof(m_sDir)/sizeof(m_sDir[0]));
+bool GraphicsOutputDeviceCairo::Initialize(string directory) {
+  directory_ = directory;
+  InititalzeInternal();
 
   /* Try to open an image to see if everything is allright. We want to avoid
    * errors in the main Process()ing loop. */
-  if ( !OpenFile(0) ) {
+  /*if (!OpenFile(0)) {
     //! \todo Better error message that is more specific about the cause.
     LOG_ERROR(_T("Could not open output directory '%s' using graphics format '%s'."),
-      m_sDir, m_pParam->DefaultString("output.img.format", ".png") );
+      directory_.c_str(), parameters_->DefaultString("output.img.format", "png"));
     return false;
   }
-  CloseFile();
+  CloseFile();*/
 
   return true;
 }
 
-bool GraphicsOutputDeviceCairo::Initialize() {
+/*bool GraphicsOutputDeviceCairo::Initialize() {
     Init();
     m_bUseMemoryBuffer = true;
     return(true);
-}
+}*/
 
-void GraphicsOutputDeviceCairo::Init() {
-   AIM_ASSERT(m_pParam);
-  /*
-   * Set parameters
-   */
-  m_pParam->GetString("output.img.color.background");
+void GraphicsOutputDeviceCairo::InititalzeInternal() {
+   AIM_ASSERT(parameters_);
 
-  m_bInvertColors = m_pParam->GetBool("output.img.color.invert");
+  parameters_->DefaultString("output.img.color.background", "black");
 
-  // Output size!
-  m_iWidth = m_pParam->GetUInt("output.img.width");
-  m_iHeight = m_pParam->GetUInt("output.img.height");
+  m_bInvertColors = parameters_->DefaultBool("output.img.color.invert", "false");
+
+  // Output size.
+  m_iWidth = parameters_->DefaultInt("output.img.width", 800);
+  m_iHeight = parameters_->DefaultInt("output.img.height", 600);
+  
+  // Cairo's RGB24 format has 32-bit pixels with the upper 8 bits unused.
+  // This is not the same as the plotutils PNG format. This information is transferred by the
+  // function GetPixelFormat. The pixel format is dealt with by the reciever.
+  m_cSurface = cairo_quartz_surface_create(CAIRO_FORMAT_RGB24,
+                                          m_iWidth,
+                                          m_iHeight);
+  m_cCr = cairo_create(m_cSurface);
+  cairo_scale(m_cCr, (float)m_iWidth, (float)m_iHeight);
+  // Now setup things for this plotter.
+  cairo_select_font_face(m_cCr,
+                         parameters_->DefaultString("output.img.fontname",
+                                                    "HersheySans"),
+                         CAIRO_FONT_SLANT_NORMAL,
+                         CAIRO_FONT_WEIGHT_BOLD);
+  cairo_set_font_size (m_cCr, 0.02);
 }
 
 unsigned char* GraphicsOutputDeviceCairo::GetBuffer() {
@@ -93,25 +106,27 @@
 }
 
 bool GraphicsOutputDeviceCairo::OpenFile(unsigned int index) {
-  const char *strPlottype = m_pParam->GetString("output.img.format");
+  const char *strPlottype = parameters_->GetString("output.img.format");
   if (!m_bUseMemoryBuffer) {
     struct stat fileinfo;
     // Get filename without trailing slash
-    strncpy(m_sFilename, m_sDir, sizeof(m_sFilename)/sizeof(m_sFilename[0]));
+    char filename[PATH_MAX];
+    strncpy(filename, directory_.c_str(), sizeof(filename)/sizeof(filename[0]));
 #ifdef _WINDOWS
-    if (m_sFilename[strlen(m_sFilename)-1]=='\\') {
-      m_sFilename[strlen(m_sFilename)-1]='\0';
+    if (filename[strlen(filename)-1]=='\\') {
+      filename[strlen(filename)-1]='\0';
     }
 #else
-    if (m_sFilename[strlen(m_sFilename)-1]=='/') {
-      m_sFilename[strlen(m_sFilename)-1]='\0';
+    if (filename[strlen(filename)-1]=='/') {
+      filename[strlen(filename)-1]='\0';
     }
 #endif
     // Enumerate files it m_sDir is a directory.
-    if (stat(m_sFilename, &fileinfo) == 0 && (fileinfo.st_mode & S_IFDIR)) {
+    if (stat(filename, &fileinfo) == 0 && (fileinfo.st_mode & S_IFDIR)) {
       // We have a directory: enumerate with index
-      snprintf(m_sFilename, sizeof(m_sFilename)/sizeof(m_sFilename[0]),"%s%06d.%s",
-               m_sDir,
+      snprintf(filename, sizeof(filename) / sizeof(filename[0]),
+               "%s%06d.%s",
+               directory_.c_str(),
                index,
                strPlottype);
       // If type is 'auto', fallback to 'png'
@@ -119,46 +134,34 @@
         strPlottype = "png";
     } else {
       // We have a (probably non-existant) file. Auto-detect type by extension if requested
-      strncpy(m_sFilename, m_sDir, sizeof(m_sFilename)/sizeof(m_sFilename[0]));
-      char *pDot = strrchr(m_sFilename, '.');
+      strncpy(filename,
+              directory_.c_str(),
+              sizeof(filename)/sizeof(filename[0]));
+      char *pDot = strrchr(filename, '.');
       if (!pDot) {
         LOG_ERROR(_T("Please supply extension on filename when using 'auto' format: '%s'"),
-                  m_sFilename);
+                  filename);
         return false;
       }
       strPlottype = &pDot[1];
     }
+    image_filename_ = filename;
     m_bOutputFile= true; //! \todo Should check that it's possible to write to the file
   }
-  // Cairo's RGB24 format has 32-bit pixels with the upper 8 bits unused.
-  // This is not the same as the plotutils PNG format. This information is transferred by the
-  // function GetPixelFormat. The pixel format is dealt with by the reciever.
-  m_cSurface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
-                                           m_iWidth,
-                                           m_iHeight);
-  m_cCr = cairo_create (m_cSurface);
-  cairo_scale(m_cCr, (float)m_iWidth, (float)m_iHeight);
-  // Now setup things for this plotter.
-  cairo_select_font_face(m_cCr,
-                         m_pParam->GetString("output.img.fontname"),
-                         CAIRO_FONT_SLANT_NORMAL,
-                         CAIRO_FONT_WEIGHT_BOLD);
-  cairo_set_font_size (m_cCr, 0.015);
+
   return true;
 }
 
 void GraphicsOutputDeviceCairo::CloseFile() {
-  // Plotting library
-  if (m_iPlotHandle>0) {
-      cairo_destroy(m_cCr);
-    m_iPlotHandle = 0;
-  }
   // And the output file
   if (m_bOutputFile) {
-    cairo_surface_write_to_png(m_cSurface, m_sFilename);
+    cairo_surface_write_to_png(m_cSurface, image_filename_.c_str());
     m_bOutputFile = false;
   }
-  cairo_surface_destroy(m_cSurface);
+  cairo_set_source_rgb (m_cCr, 0.0, 0.0, 0.0);
+  cairo_paint (m_cCr);
+  //cairo_destroy(m_cCr);
+  //cairo_surface_destroy(m_cSurface);
 }
 
 GraphicsOutputDeviceCairo::~GraphicsOutputDeviceCairo() {
@@ -198,9 +201,9 @@
 
 void GraphicsOutputDeviceCairo::gColor3f(float r, float g, float b) {
   if (m_bInvertColors) {
-    r = 1-r;
-    g = 1-g;
-    b = 1-b;
+    r = 1.0 - r;
+    g = 1.0 - g;
+    b = 1.0 - b;
   }
   cairo_set_source_rgb (m_cCr, r, g, b);
 }
@@ -211,14 +214,14 @@
     if (m_bIsFirstVertex) {
       m_bIsFirstVertex = false;
       //pl_fmove(x, y);
-      cairo_move_to(m_cCr, x, 1-y);
+      cairo_move_to(m_cCr, x, 1.0 - y);
     } else {
       //pl_fcont(x, y);
-      cairo_line_to(m_cCr, x, 1-y);
+      cairo_line_to(m_cCr, x, 1.0 - y);
     }
     break;
   case VertexTypeQuad:
-    /* Store vertices until we got four in a row.
+    /* Store vertices until we have four in a row.
      * The order of vertices when processing quads is:
      *    1-----3-----5
      *    |     |     |
@@ -226,11 +229,17 @@
      */
     if (m_iPrevVertexCount >= 3) {
       // Plot this quad
-      cairo_move_to(m_cCr, m_aPrevX[0], 1-m_aPrevY[0]);
-      cairo_line_to(m_cCr, m_aPrevX[1], 1-m_aPrevY[1]);
+      //cairo_set_source_rgb(m_cCr, 0.2, 1 - m_aPrevY[0], m_aPrevX[0]);
+      cairo_rectangle (m_cCr, m_aPrevX[2],
+                       1 - m_aPrevY[2], m_aPrevX[2] - m_aPrevX[0],
+                       y - m_aPrevY[2]);
+      cairo_fill (m_cCr);
+      
+      /*cairo_move_to(m_cCr, , );
+      cairo_line_to(m_cCr, , 1 - m_aPrevY[1]);
       cairo_line_to(m_cCr, x, y);
-      cairo_line_to(m_cCr, m_aPrevX[2], 1-m_aPrevY[2]);
-      cairo_close_path (m_cCr);
+      cairo_line_to(m_cCr, m_aPrevX[2], 1 - m_aPrevY[2]);*/
+ 
 
       // Last vertices of this quad are the first of the next
       m_aPrevX[0] = m_aPrevX[2];
@@ -267,7 +276,7 @@
   //cairo_text_extents_t te;
   if (bRotated) {
     cairo_rotate(m_cCr, M_PI/2);
-    cairo_move_to(m_cCr, x ,1-y);
+    //cairo_move_to(m_cCr, x ,1-y);
     cairo_show_text(m_cCr, sStr);
     //cairo_identity_matrix(m_cCr);
     cairo_rotate(m_cCr, -M_PI/2);
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceCairo.h	Tue Oct 19 19:48:37 2010 +0000
+++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceCairo.h	Thu Oct 21 01:46:39 2010 +0000
@@ -47,12 +47,12 @@
  */
 class GraphicsOutputDeviceCairo : public GraphicsOutputDevice {
  public:
-  GraphicsOutputDeviceCairo(Parameters *pParam);
+  GraphicsOutputDeviceCairo(Parameters *parameters);
   virtual ~GraphicsOutputDeviceCairo();
 
   /*! \brief Initializes this output device, prepares plotting tools.
    *  \param sDir Directory or filename where to put images, max length is
-   *         _MAX_PATH. Must end with slash!!!
+   *         _MAX_PATH. Must end with slash.
    *  \return true on success, false on failure.
    *
    *  sDir can be either a filename, in which case the output will be
@@ -63,8 +63,7 @@
    *  As usual, make sure to call this function before any other. If this
    *  Initialize() failed, you shouldn't try the other functions either.
    */
-  bool Initialize(const char *sDir);
-  bool Initialize();
+  bool Initialize(string directory);
   void gGrab();
   void gBeginLineStrip();
   void gBeginQuadStrip();
@@ -80,7 +79,7 @@
   /*! \brief Internal initialisation
    *
    */
-  void Init();
+  void InititalzeInternal();
 
   /*! \brief Open the file with given index for output
    *  \param index File number to open
@@ -95,10 +94,8 @@
 
   //! \brief Set to true if the input file can be written to
   bool m_bOutputFile;
-  //! \brief The Cairo plotter
-  int m_iPlotHandle;
   //! \brief Output directory
-  char m_sDir[FILENAME_MAX];
+  string directory_;
   //! \brief Current file number
   unsigned int m_iFileNumber;
   //! \brief true if this is the first vertex after gBegin()
@@ -126,7 +123,7 @@
   cairo_t *m_cCr;
 
   //! \brief Internal store for the input filename
-  char m_sFilename[FILENAME_MAX];
+  string image_filename_;
 
   unsigned int m_iWidth;
   unsigned int m_iHeight;
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.cc	Tue Oct 19 19:48:37 2010 +0000
+++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.cc	Thu Oct 21 01:46:39 2010 +0000
@@ -50,84 +50,90 @@
 
 namespace aimc {
 
-GraphicsOutputDeviceMovie::GraphicsOutputDeviceMovie(Parameters *pParam)
-  : GraphicsOutputDeviceCairo(pParam) {  // or GraphicsOutputDevicePlotutils
-  m_sMovieFile[0] = '\0';
-  m_sSoundFile[0] = '\0';
+GraphicsOutputDeviceMovie::GraphicsOutputDeviceMovie(Parameters *parameters)
+  : GraphicsOutputDeviceCairo(parameters) {
+  sound_filename_.clear();
+  movie_filename_.clear();
 }
 
-bool GraphicsOutputDeviceMovie::Initialize(const char *sSoundFile,
-                                           const char *sMovieFile) {
+bool GraphicsOutputDeviceMovie::Initialize(Parameters *global_parameters) {
+  global_parameters_ = global_parameters;
+  sound_filename_ = global_parameters->GetString("input_filename");
+  string file_suffix = parameters_->DefaultString("filename_suffix", ".mov");
+  movie_filename_ = global_parameters->GetString("output_filename_base")
+                    + file_suffix;
+  
   FILE *f;
-  AIM_ASSERT(sSoundFile);
-  AIM_ASSERT(sMovieFile);
 
   // Check sound file exists
-  if ((f = fopen(sSoundFile, "r")) == NULL) {
+  if ((f = fopen(sound_filename_.c_str(), "r")) == NULL) {
     LOG_ERROR(_T("Couldn't open sound file '%s' for movie creation."),
-             sSoundFile);
+             sound_filename_.c_str());
+    sound_filename_.clear();
     return false;
   }
   fclose(f);
-  strcpy(m_sSoundFile, sSoundFile);
 
   // Check movie output file can be made
-  if ( (f=fopen(sMovieFile, "w"))==NULL ) {
+  if ((f = fopen(movie_filename_.c_str(), "w")) == NULL) {
     LOG_ERROR(_T("Couldn't open movie file '%s' to write to."),
-             sMovieFile);
+             movie_filename_.c_str());
+    movie_filename_.clear();
     return false;
   }
   fclose(f);
-  strcpy(m_sMovieFile, sMovieFile);
 
   // Get a temporary image output directory
   //! \warning Not really safe ... but windows has no mkdtemp()
   //! \todo Make build system check for mkdtemp() to use it when available. See TODO.txt.
-  char *sTmpDir = NULL;
 #ifdef _WINDOWS
-  if ((sTmpDir = _tempnam(NULL, AIM_NAME))
-      && _mkdir(sTmpDir) >= 0) {
-    strcpy(m_sDir, sTmpDir);
-    strcat(m_sDir, "\\"); // Make sure to end with trailing slash
-  } else
-#else
-  strcpy(m_sDir, "/tmp/"AIM_NAME"-movie.XXXXXX");
-  if (mkdtemp(m_sDir)) {
-    strcat(m_sDir, "/"); // Make sure to end with trailing slash
-  } else
-#endif
-  {
+  char *temp_dir = NULL;
+  if ((temp_dir = _tempnam(NULL, AIM_NAME))
+      && _mkdir(temp_dir) >= 0) {
+    directory_ = temp_dir;
+    directory_ += "\\"; // Make sure to end with trailing slash
+  } else  {
     LOG_ERROR(_T("Couldn't create a temporary directory for movie output."));
-    if (sTmpDir) free(sTmpDir);
+    if (temp_dir) {
+      free(temp_dir);
+    }
     return false;
   }
-  if (sTmpDir) {
-    free(sTmpDir);
+  if (temp_dir) {
+    free(temp_dir);
   }
-
-  // We want png for movie conversion
-  //! \bug This may change the user preference in GUI, hmm what to do? See TODO.txt
-  m_pParam->SetString("output.img.format", "png");
-  //if ( !GraphicsOutputDevicePlotutils::Initialize(m_sDir) ) {
-  if ( !GraphicsOutputDeviceCairo::Initialize(m_sDir) ) {
+#else
+  char temp_dir[PATH_MAX];
+  strcpy(temp_dir, "/tmp/"AIM_NAME"-movie.XXXXXX");
+  if (mkdtemp(temp_dir)) {
+    directory_ = temp_dir;
+    directory_ += "/"; // Make sure to end with trailing slash    
+  } else {
+    LOG_ERROR(_T("Couldn't create a temporary directory for movie output."));
     return false;
   }
-
+#endif
+  
+  // We want png for movie conversion
+  parameters_->SetString("output.img.format", "png");
+  if ( !GraphicsOutputDeviceCairo::Initialize(directory_) ) {
+    return false;
+  }
   return true;
 }
 
 void GraphicsOutputDeviceMovie::Start() {
-  //GraphicsOutputDevicePlotutils::Start();
   GraphicsOutputDeviceCairo::Start();
-  // Just output a single frame to get audio/video in sync, put params in there
+  // Output a couple of frames to get audio/video in sync, put params in there.
+  gGrab();
+  PlotParameterScreen();
+  gRelease();
   gGrab();
   PlotParameterScreen();
   gRelease();
 }
 
 void GraphicsOutputDeviceMovie::Stop() {
-  // Make sure Plotutils is really done writing.
-  //GraphicsOutputDevicePlotutils::Stop();
   GraphicsOutputDeviceCairo::Stop();
   CloseFile();
 
@@ -136,33 +142,28 @@
 #else
   printf("Generating movie ... \n");
 #endif
-  AIM_ASSERT(m_pParam);
-  // Convert images and sound file to a movie
-  //! \warning Movie files are overwritten without warning
-  //! \bug ffmpeg only works with colour images, not with bw. So make sure to not use bw only in drawing..
-  // Always convert to audio stream of 44.1kHz or problems may occur in playing or conversio.
-  float fFps = 1000.0 / m_pParam->GetFloat("output.frameperiod");
+  AIM_ASSERT(parameters_);
+  // Convert images and sound file to a movie.
+  //! \warning Movie files are overwritten without warning.
   char sffmpegPath[1024];
-  if (!m_pParam->IsSet("output.ffmpeg_path")) {
+  if (!parameters_->IsSet("output.ffmpeg_path")) {
   strcpy(sffmpegPath,"ffmpeg");
   } else {
-    strcpy(sffmpegPath, m_pParam->GetString("output.ffmpeg_path"));
+    strcpy(sffmpegPath, parameters_->GetString("output.ffmpeg_path"));
   }
   char sCodecOptions[1024];
-  if (!m_pParam->IsSet("output.ffmpeg_codec_options")) {
+  if (!parameters_->IsSet("output.ffmpeg_codec_options")) {
     strcpy(sCodecOptions,"");
   } else {
-    strcpy(sCodecOptions, m_pParam->GetString("output.ffmpeg_codec_options"));
+    strcpy(sCodecOptions, parameters_->GetString("output.ffmpeg_codec_options"));
   }
-
+  float frame_rate = global_parameters_->DefaultFloat("frame_rate", -1.0);
   char sCmdLine[1024]; //!\todo check that snprintf does not want a larger buffer
   snprintf(sCmdLine, sizeof(sCmdLine)/sizeof(sCmdLine[0]),
     "%s -r %.2f -y -i \"%s\" -i \"%s%%06d.png\" "
-    "-title \"%s\" -comment \"Generated by "AIM_NAME" "AIM_VERSION_STRING"\" "
     "-sameq -r %.2f -ar 44100 -acodec pcm_s16le %s \"%s\"",
-    sffmpegPath, fFps, m_sSoundFile, m_sDir,
-    m_pParam->GetString("output.movie.title"),
-    fFps, sCodecOptions, m_sMovieFile);
+    sffmpegPath, frame_rate, sound_filename_.c_str(), directory_.c_str(),
+    frame_rate, sCodecOptions, movie_filename_.c_str());
     printf(sCmdLine);
     printf("\n");
   if (system(sCmdLine)) {
@@ -199,7 +200,7 @@
 #else
   DIR *dir;
   struct dirent *dirent;
-  if (!(dir = opendir(m_sDir))) {
+  if (!(dir = opendir(directory_.c_str()))) {
     LOG_ERROR(_T("Couldn't remove files in temporary directory."));
     return;
   }
@@ -207,22 +208,22 @@
     snprintf(sCmdLine,
              sizeof(sCmdLine)/sizeof(sCmdLine[0]),
              "%s%s",
-             m_sDir,
+             directory_.c_str(),
              dirent->d_name);
     unlink(sCmdLine);
   }
   closedir(dir);
-  rmdir(m_sDir);
+  rmdir(directory_.c_str());
 #endif
 }
 
 void GraphicsOutputDeviceMovie::PlotParameterScreen() {
-  AIM_ASSERT(m_pParam);
+  AIM_ASSERT(parameters_);
   char sStr[50];
   int lineno = 1;
 
-  float fMarL = m_pParam->GetFloat(_S("graph.margin.left"));
-  float fMarT = m_pParam->GetFloat(_S("graph.margin.top"));
+  float fMarL = parameters_->GetFloat(_S("graph.margin.left"));
+  float fMarT = parameters_->GetFloat(_S("graph.margin.top"));
   float fTextHeight = 1.0f / 50.0f * 1.2; // change this when fontsizing is there!
 
   gText2f(fMarL, 1-(fMarT+fTextHeight*lineno++),
@@ -249,7 +250,7 @@
     snprintf(sStr,
              sizeof(sStr)/sizeof(sStr[0]), _S("%s=%s"),
              pPlotParams[i],
-             m_pParam->GetString(pPlotParams[i]));
+             parameters_->GetString(pPlotParams[i]));
     gText2f(fMarL,
             1-(fMarT+fTextHeight*lineno++),
             sStr);
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.h	Tue Oct 19 19:48:37 2010 +0000
+++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.h	Thu Oct 21 01:46:39 2010 +0000
@@ -27,7 +27,7 @@
 #ifndef __GRAPHICS_OUTPUT_DEVICE_MOVIE_H__
 #define __GRAPHICS_OUTPUT_DEVICE_MOVIE_H__
 
-//#include "Modules/Output/Graphics/Devices/GraphicsOutputDevicePlotutils.h"
+#include <string>
 #include "Modules/Output/Graphics/Devices/GraphicsOutputDeviceCairo.h"
 
 namespace aimc {
@@ -39,7 +39,7 @@
  // GraphicsOutputDevicePlotutils is also possible here
 class GraphicsOutputDeviceMovie : public GraphicsOutputDeviceCairo {
  public:
-  GraphicsOutputDeviceMovie(Parameters *pParam);
+  GraphicsOutputDeviceMovie(Parameters *parameters);
   virtual ~GraphicsOutputDeviceMovie() { };
 
   /*! \brief Initializes this output device, prepares plotting tools.
@@ -50,7 +50,7 @@
    *  As usual, make sure to call this function before any other. If this
    *  Initialize() failed, you shouldn't try the other functions either.
    */
-  bool Initialize(const char *sSoundFile, const char *sMovieFile);
+  bool Initialize(Parameters *global_parameters);
 
   void Start();
   //! \brief This function now also generates the output movie.
@@ -68,9 +68,9 @@
   void PlotParameterScreen();
 
   //! \brief Name of the sound file to be merged with the video
-  char m_sSoundFile[PATH_MAX];
+  string sound_filename_;
   //! \brief Name of the movie file to produce
-  char m_sMovieFile[PATH_MAX];
+  string movie_filename_;
 };
 }  // namespace aimc
 #endif /* __GRAPHICS_OUTPUT_DEVICE_MOVIE_H__ */
--- a/src/Modules/Output/Graphics/Devices/GraphicsOutputDevicewxGLCanvas.cc	Tue Oct 19 19:48:37 2010 +0000
+++ b/src/Modules/Output/Graphics/Devices/GraphicsOutputDevicewxGLCanvas.cc	Thu Oct 21 01:46:39 2010 +0000
@@ -269,7 +269,7 @@
     }  else if (strstr(extensions, "GL_EXT_compiled_vertex_array")) {
       m_glLockArraysEXT = (LOCAL_PFNGLLOCKARRAYSEXTPROC)GL_GET_PROC_ADDRESS("glLockArraysEXT");
       m_glUnlockArraysEXT = (LOCAL_PFNGLUNLOCKARRAYSEXTPROC)GL_GET_PROC_ADDRESS("glUnlockArraysEXT");
-      if(!m_glLockArraysEXT || !m_glUnlockArraysEXT)
+      if (!m_glLockArraysEXT || !m_glUnlockArraysEXT)
         AIM_ERROR(_T("OpenGL error on GL_EXT_compiled_vertex_array"));
       else
         m_bVertexArrayLock = true;
--- a/src/Modules/Output/Graphics/GraphAxisSpec.cc	Tue Oct 19 19:48:37 2010 +0000
+++ b/src/Modules/Output/Graphics/GraphAxisSpec.cc	Thu Oct 21 01:46:39 2010 +0000
@@ -70,23 +70,20 @@
   snprintf(sParamName, sizeof(sParamName)/sizeof(sParamName[0]),
           "%s.min",
           sPrefix);
-  if (parameters->IsSet(sParamName)) {
-    if (strcmp(parameters->GetString(sParamName), "auto") == 0)
-      m_fMin = fMin;
-    else
-      m_fMin = parameters->GetFloat(sParamName);
-  }
+  if (strcmp(parameters->DefaultString(sParamName, "auto"), "auto") == 0)
+    m_fMin = fMin;
+  else
+    m_fMin = parameters->GetFloat(sParamName);
+  
 
   //!   - \c "<prefix>.max", the maximum value; a float or \c 'auto'
   snprintf(sParamName, sizeof(sParamName)/sizeof(sParamName[0]),
           "%s.max",
           sPrefix);
-  if (parameters->IsSet(sParamName)) {
-    if (strcmp(parameters->GetString(sParamName), "auto")==0)
-      m_fMax = fMax;
-    else
-      m_fMax = parameters->GetFloat(sParamName);
-  }
+  if (strcmp(parameters->DefaultString(sParamName, "auto"), "auto")==0)
+    m_fMax = fMax;
+  else
+    m_fMax = parameters->GetFloat(sParamName);
 
   // Make sure ranges are updated properly
   SetDisplayRange(m_fMin, m_fMax);
@@ -96,33 +93,31 @@
   snprintf(sParamName, sizeof(sParamName)/sizeof(sParamName[0]),
            "%s.scale",
            sPrefix);
-  if (parameters->IsSet(sParamName)) {
-    // Scale change, we updated min/max values already so no need to
-    Scale::ScaleType iThisScale;
-    const char *sVal = parameters->GetString(sParamName);
-    if (strcmp(sVal, "auto")==0)
-      iThisScale = iScale;
-    else if (strcmp(sVal, "linear")==0)
-      iThisScale = Scale::SCALE_LINEAR;
-    else if (strcmp(sVal, "erb")==0)
-      iThisScale = Scale::SCALE_ERB;
-    else if (strcmp(sVal, "log")==0)
-      iThisScale = Scale::SCALE_LOG;
-    else {
-      LOG_ERROR(_T("Unrecognized scale type in parameter '%s': '%s'"),
-                  sParamName,
-                  sVal);
-      return false;
-    }
-    SetDisplayScale(iThisScale);
+  // Scale change, we updated min/max values already so no need to
+  Scale::ScaleType iThisScale;
+  const char *sVal = parameters->DefaultString(sParamName, "auto");
+  if (strcmp(sVal, "auto")==0)
+    iThisScale = iScale;
+  else if (strcmp(sVal, "linear")==0)
+    iThisScale = Scale::SCALE_LINEAR;
+  else if (strcmp(sVal, "erb")==0)
+    iThisScale = Scale::SCALE_ERB;
+  else if (strcmp(sVal, "log")==0)
+    iThisScale = Scale::SCALE_LOG;
+  else {
+    LOG_ERROR(_T("Unrecognized scale type in parameter '%s': '%s'"),
+                sParamName,
+                sVal);
+    return false;
   }
+  SetDisplayScale(iThisScale);
+
 
   //!   - \c "<prefix>.label", the label; a string
   snprintf(sParamName, sizeof(sParamName)/sizeof(sParamName[0]),
            "%s.label",
            sPrefix);
-  if (parameters->IsSet(sParamName))
-    m_sLabel = parameters->GetString(sParamName); // Assumes strings remains valid
+  m_sLabel = parameters->DefaultString(sParamName, ""); // Assumes strings remains valid
 
   return true;
 }
--- a/src/Modules/Output/Graphics/GraphicsView.cc	Tue Oct 19 19:48:37 2010 +0000
+++ b/src/Modules/Output/Graphics/GraphicsView.cc	Thu Oct 21 01:46:39 2010 +0000
@@ -21,6 +21,7 @@
 
 #include "Modules/Output/Graphics/GraphicsView.h"
 #include "Modules/Output/Graphics/Devices/GraphicsOutputDevice.h"
+#include "Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.h"
 
 namespace aimc {
 
@@ -30,7 +31,7 @@
   module_type_ = "output";
   module_version_ = "$Id: $";
   
-  m_pDev = new GraphicsOutputDeviceCairo();
+  m_pDev = new GraphicsOutputDeviceMovie(parameters);
   m_bPlotLabels = false;
   m_pAxisX = new GraphAxisSpec();
   AIM_ASSERT(m_pAxisX);
@@ -48,13 +49,13 @@
     LOG_ERROR("Axis initialization failed");
     initialized_ = false;
   }
-  m_fMarginLeft = parameters_->GetFloat(_S("graph.margin.left"));
-  m_fMarginRight = parameters_->GetFloat(_S("graph.margin.right"));
-  m_fMarginTop = parameters_->GetFloat(_S("graph.margin.top"));
-  m_fMarginBottom = parameters_->GetFloat(_S("graph.margin.bottom"));
-  m_bPlotLabels = parameters_->GetBool(_S("graph.plotlabels"));
+  m_fMarginLeft = parameters_->DefaultFloat(_S("graph.margin.left"), 0.05);
+  m_fMarginRight = parameters_->DefaultFloat(_S("graph.margin.right"), 0.005);
+  m_fMarginTop = parameters_->DefaultFloat(_S("graph.margin.top"), 0.005);
+  m_fMarginBottom = parameters_->DefaultFloat(_S("graph.margin.bottom"), 0.05);
+  m_bPlotLabels = parameters_->DefaultBool(_S("graph.plotlabels"), true);
 
-  const char *sGraphType = parameters_->GetString(_S("graph.type"));
+  const char *sGraphType = parameters_->DefaultString(_S("graph.type"), "line");
   if (strcmp(sGraphType, _S("line"))==0)
     m_iGraphType = GraphTypeLine;
   else if (strcmp(sGraphType, _S("colormap"))==0)
@@ -66,7 +67,7 @@
     initialized_ = false;
   }
 
-  if (strcmp(parameters_->GetString(_S("graph.mindistance")),"auto") == 0)
+  if (strcmp(parameters_->DefaultString(_S("graph.mindistance"), "auto"),"auto") == 0)
     // -1 means detect later, based on type and Fire() argument
     m_fMinPlotDistance = -1;
   else
@@ -80,6 +81,9 @@
 }
 
 void GraphicsView::ResetInternal() {
+  if (m_pDev != NULL) {
+    m_pDev->Stop();
+  }
 }
 
 bool GraphicsView::InitializeInternal(const SignalBank &bank) {
@@ -95,7 +99,7 @@
                                y_min,
                                y_max,
                                Scale::SCALE_ERB)) {
-    LOG_ERROR("");
+    LOG_ERROR("Frequency axis init failed.");
     return false;
   }
 
@@ -106,17 +110,21 @@
                             x_min,
                             x_max,
                             Scale::SCALE_LINEAR)) {
-     LOG_ERROR("");
+     LOG_ERROR("Time axis init failed.");
      return false;
   }
 
   /* Inform graphics output of maximum number of vertices between
    * gBegin*() and gEnd(), for any type of plot. Colormap needs most.
    */
-  if (!m_pDev->Initialize(std::max<int>(10, bank.buffer_length() * 2 + 2))) {
-    LOG_ERROR("");
+  LOG_INFO("Initializing graphics output device.");
+  
+  if (!m_pDev->Initialize(global_parameters_)) {
+    LOG_ERROR("Graphics output device init failed.");
     return false;
   }
+  m_pDev->Start();
+  previous_start_time_ = 0;
   return true;
 }
 
@@ -145,6 +153,11 @@
     PlotData(bank[i], bank.sample_rate(), yOffs, heightMinMargin, xScaling);
   }
   m_pDev->gRelease();
+  
+  frame_rate_ = bank.sample_rate()
+                / (bank.start_time() - previous_start_time_);
+  previous_start_time_ = bank.start_time();
+  global_parameters_->SetFloat("frame_rate", frame_rate_);
 }
 
 void GraphicsView::SetAxisScale(Scale::ScaleType iHori,
--- a/src/Modules/Output/Graphics/GraphicsView.h	Tue Oct 19 19:48:37 2010 +0000
+++ b/src/Modules/Output/Graphics/GraphicsView.h	Thu Oct 21 01:46:39 2010 +0000
@@ -163,6 +163,8 @@
   float m_fPrevVal, m_fPrevX, m_fPrevY, m_fPrevHeight;
   //! \brief Number of times m_fValPrev was within range m_fMinPlotDistance
   int m_iPrevValEqual;
+  float frame_rate_;
+  int previous_start_time_;
 
   bool initialized_;
 };
--- a/src/Modules/Output/Graphics/GraphicsViewTime.cc	Tue Oct 19 19:48:37 2010 +0000
+++ b/src/Modules/Output/Graphics/GraphicsViewTime.cc	Thu Oct 21 01:46:39 2010 +0000
@@ -43,7 +43,7 @@
 }
 
 GraphicsViewTime *GraphicsViewTime::Clone(GraphicsOutputDevice *pDev) {
-  GraphicsViewTime *pView = new GraphicsViewTime(m_pParam);
+  GraphicsViewTime *pView = new GraphicsViewTime(parameters_);
   // Copy everything
   pView->m_pAxisX->SetDisplayRange(m_pAxisX->m_fMax, m_pAxisX->m_fMin);
   pView->m_pAxisX->SetDisplayScale(m_pAxisX->m_pScale->getType());
@@ -67,8 +67,8 @@
   m_pDev->gVertex2f(1.0f-m_fMarginRight, m_fMarginBottom);
   m_pDev->gEnd();
 
-  if (!m_bPlotLabels)
-    return;
+  //if (!m_bPlotLabels)
+  //  return;
 
   // Labels
   char sTxt[80];
@@ -88,9 +88,9 @@
   m_pDev->gText2f(m_fMarginLeft, 0.0025f, sTxt, false);
 
   // Frame time
-  //snprintf(sTxt, sizeof(sTxt)/sizeof(sTxt[0]), _S("t=%.0f ms"),
-  //         pBank->getSampleTime(0));
-  //m_pDev->gText2f(0.8f, 0.0025f, sTxt, false);
+  snprintf(sTxt, sizeof(sTxt)/sizeof(sTxt[0]), _S("t=%.0f ms"),
+           1000.0 * bank.start_time() / bank.sample_rate());
+  m_pDev->gText2f(0.8f, 0.0025f, sTxt, false);
 }
 
 void GraphicsViewTime::PlotData(const vector<float> &signal,
--- a/src/Modules/Output/Graphics/GraphicsViewTime.h	Tue Oct 19 19:48:37 2010 +0000
+++ b/src/Modules/Output/Graphics/GraphicsViewTime.h	Thu Oct 21 01:46:39 2010 +0000
@@ -35,10 +35,10 @@
 
 private:
   void PlotData(const vector<float> &signal,
-	float sample_rate,
-	float yOffset,
-	float height,
-	float xScale = 1.0);
+	              float sample_rate,
+	              float yOffset,
+	              float height,
+	              float xScale = 1.0);
   void PlotAxes(const vector<float> &signal);
   void PlotAxes(const SignalBank &pBank);
 };
--- a/src/Modules/SSI/ModuleSSI.cc	Tue Oct 19 19:48:37 2010 +0000
+++ b/src/Modules/SSI/ModuleSSI.cc	Thu Oct 21 01:46:39 2010 +0000
@@ -57,7 +57,7 @@
   // Time from the zero-lag line of the SAI from which to start searching
   // for a maximum in the input SAI's temporal profile.
   pitch_search_start_ms_ = parameters_->DefaultFloat(
-    "ssi.pitch_search_start_ms", 2.0f);
+      "ssi.pitch_search_start_ms", 2.0f);
 
   // Total width in cycles of the whole SSI
   ssi_width_cycles_ = parameters_->DefaultFloat("ssi.width_cycles", 10.0f);
@@ -99,6 +99,10 @@
                 ssi_width_samples_, cycles);
     ssi_width_cycles_ = cycles;
   }
+  for (int i = 0; i < input.channel_count(); ++i) {
+    output_.set_centre_frequency(i, input.centre_frequency(i));
+  }
+  
   output_.Initialize(channel_count_, ssi_width_samples_, sample_rate_);
   return true;
 }
@@ -159,6 +163,7 @@
 
   for (int ch = 0; ch < channel_count_; ++ch) {
     float centre_frequency = input.centre_frequency(ch);
+    float cycle_samples = sample_rate_ / centre_frequency;
     
     float channel_weight = 1.0f;
     int cutoff_index = buffer_length_ - 1;
@@ -166,31 +171,22 @@
       if (pitch_index < cutoff_index) {
         if (weight_by_cutoff_) {
           channel_weight = static_cast<float>(buffer_length_)
-                    / static_cast<float>(pitch_index);
+                           / static_cast<float>(pitch_index);
         }
         cutoff_index = pitch_index;
       }
     }
     
     // tanh(3) is about 0.995. Seems reasonable. 
-    float smooth_pitch_constant = smooth_offset_cycles_ * 3.0f;
+    float smooth_pitch_constant = 3.0f / smooth_offset_cycles_;
     float pitch_h = 0.0f;
     if (do_smooth_offset_) {
-      if (log_cycles_axis_) {
-        float gamma = gamma_min + (gamma_max - gamma_min)
-                                   * static_cast<float>(pitch_index)
-                                   / static_cast<float>(ssi_width_samples_);
-        pitch_h = pow(2.0f, gamma);
-      } else {
-        pitch_h = static_cast<float>(pitch_index) * ssi_width_cycles_
-            / static_cast<float>(ssi_width_samples_);
-      }
+      pitch_h = static_cast<float>(pitch_index) / cycle_samples;
     }
     
-    // Copy the buffer from input to output, addressing by h-value
+    // Copy the buffer from input to output, addressing by h-value.
     for (int i = 0; i < ssi_width_samples_; ++i) {
       float h;
-      float cycle_samples = sample_rate_ / centre_frequency;
       if (log_cycles_axis_) {
         float gamma = gamma_min + (gamma_max - gamma_min)
                                    * static_cast<float>(i)
@@ -213,7 +209,10 @@
       
       if (do_smooth_offset_ && do_pitch_cutoff_) {
         // Smoothing around the pitch cutoff line.
-        weight *= (1.0f + tanh(smooth_pitch_constant * (pitch_h - h))) / 2.0f;
+        float pitch_weight = (1.0f + tanh((pitch_h - h)
+                                          * smooth_pitch_constant)) / 2.0f;
+        weight *= pitch_weight;
+        //LOG_INFO("Channel %d, Sample %d. Pitch weight: %f", ch, i, pitch_weight);
       }
 
       if (weight_by_scaling_) {
--- a/swig/aim_modules.i	Tue Oct 19 19:48:37 2010 +0000
+++ b/swig/aim_modules.i	Thu Oct 21 01:46:39 2010 +0000
@@ -38,6 +38,7 @@
 #include "Modules/SSI/ModuleSSI.h"
 #include "Modules/Profile/ModuleSlice.h"
 #include "Modules/Profile/ModuleScaler.h"
+#include "Modules/Features/ModuleGaussians.h"
 %}
 
 %include "Support/Parameters.h"
@@ -77,3 +78,4 @@
 %include "Modules/SSI/ModuleSSI.h"
 %include "Modules/Profile/ModuleSlice.h"
 %include "Modules/Profile/ModuleScaler.h"
+%include "Modules/Features/ModuleGaussians.h"
--- a/swig/example.py	Tue Oct 19 19:48:37 2010 +0000
+++ b/swig/example.py	Thu Oct 21 01:46:39 2010 +0000
@@ -17,10 +17,11 @@
 # limitations under the License.
 
 import aimc
-params = aimc.Parameters()
+module_params = aimc.Parameters()
+global_params = aimc.Parameters()
 mod_gauss = aimc.ModuleGaussians(params)
 sig = aimc.SignalBank()
 sig.Initialize(115, 1, 44100)
-mod_gauss.Initialize(sig)
+mod_gauss.Initialize(sig, global_params)
 mod_gauss.Process(sig)
 
--- a/swig/setup.py	Tue Oct 19 19:48:37 2010 +0000
+++ b/swig/setup.py	Thu Oct 21 01:46:39 2010 +0000
@@ -29,6 +29,7 @@
                                    '../src/Support/SignalBank.cc', 
                                    '../src/Support/Module.cc',
                                    '../src/Modules/BMM/ModuleGammatone.cc',
+                                   '../src/Modules/Features/ModuleGaussians.cc',
                                    '../src/Modules/BMM/ModulePZFC.cc',
                                    '../src/Modules/NAP/ModuleHCL.cc',
                                    '../src/Modules/Strobes/ModuleParabola.cc',