Using SSFF in C++ programs

Overview

The C++ routines for the SSFF library provide a more elegant and effective interface than the C routines do. The SSFF system lends itself naturally to object-orientation and information hiding.

Interface description

The base class for reading and writing SSFF files is defined as follows: (only public member functions are shown. Constructor and destructor also omitted for brevity)

class SSFF
{
public:
  SSFF();
   SSFF();

  int Write_Open( char* File, char** Var_List, char** Col_List=NULL,
                  int Num_Recs=1, int Format=FORMAT_SSFF );
  int Read_Open( char* File, int Num_Recs=1 );  
  void Close();
  
  char* Locate_Generic( char* Name  );
  char* Locate_Field( char* Name, int* Type=NULL,
                      int *Size=NULL, int* Width=NULL );
  
  inline int Seek(int Rec_Num){  return SSFF_Seek( Hdr, Rec_Num ); };
  inline int Write( int Num_Recs=1 ){  return SSFF_Write( Hdr, Num_Recs ); }; 
  inline int Read( int Num_Recs=1 ){   return SSFF_Read( Hdr, Num_Recs ); };
      
  // some access functions
  float Start_Time();
  float Record_Freq();
  SSFF_Generic* Get_First_Generic();
  SSFF_Column* Get_First_Column();
};

Most of the member functions perform exactly the same function as their C counterparts. For example, the Write_Open() member function does what the SSFF_Write_Open() function does, with the exception that pointer to the header structure does not have to be handled explicitly. Also, TRUE is returned if the opening is successful, and FALSE otherwise.

The other member functions that have SSFF C equivalents are Read_Open(), Close(), Locate_Generic(), Locate_Field(), Seek(), Write() and Read(). Notice that you do not have to pass the header pointer as the first argument. This is all handled internally.

The member functions that provide extra functionality are:
float SSFF::Start_Time()

Returns the start time of the file in seconds. Allows this information to be obtained without the need for the programmer to query the header structure directly.
float SSFF::Record_Freq()

Returns the sampling frequency of the data file.
SSFF_Generic* SSFF::Get_First_Generic()

Returns a pointer to the first generic variable in the list, allowing the information to be obtained without direct reference to the structure header.
SSFF_Column* SSFF::Get_First_Column()

Returns a pointer to the first field definition. Gives the same value as the C construct Hdr->Cols as discussed in section 3.3.

Note that several of the member functions have default values defined for parameters. In all cases, these defaults are set to the most commonly used values.

Predefined data formats

Using the SSFF class as a base, it is possible to define new classes which cater for each standard format documented in section 3.4. The member function Write_Open() is overloaded to eliminate the need to supply a Col_List argument. Field location functions that return the correct type are also defined.

Consider the definition of the class SSFF_Sample_Data in ssff_formats.h:

class SSFF_Sampled_Data : public SSFF
{
 public:
  int Write_Open( char* File, char** Var_List, 
                 int Num_Recs=1, int Format=FORMAT_SSFF )
    { return SSFF::Write_Open( File, 
                              Var_List, 
                              SSFF_Sampled_Data_Cols, 
                              Num_Recs, 
                              Format ); /

  short* Locate_samples()
    { return (short*) Locate_Field( "samples", NULL, NULL, NULL ); }
};

So, by using the predefined column array SSFF_Sampled_Data_Cols, the member function Write_Open() is able to eliminate the need to specify this information as a parameter. Also note that each field now has a member function associated with it that returns the pointer to the data coerced into the correct type.

There exists a class definition for every one of the standard formats defined in ssff_formats.h. To work out the name of the class to use, start with the original name of the column variable (for example, SSFF_Synth_Cols) and remove the trailing _Cols from the name (SSFF_Synth).

To locate a field within the file, start with the name of the original field (for example, Pitch, type FLOAT, dimension 1) and get the appropriate member function by adding Locate_ to the start (float* SSFF_Synth::Locate_Pitch())

Adding extra signal classes

Adding extra signal classes is very easy. If the new format is intended to be a standard, then the definition should go in the ssff_formats.h file. Consider that we want to add a new class called Thingo with a field Widget, of type SSFF_FLOAT and dimension of one.

Define the column list as a static array, in the same fashion as the other arrays in ssff_formats.h. Don't forget the NULL at the end of the list!

static char *SSFF_Thingo_Cols[] = 
     { "Column WIdget FLOAT 1",
       NULL/;

Define a new class which encapsulates this format:

class SSFF_Thingo : public SSFF
{
public:
    int Write_Open( char* File, char** Var_List, int Num_Recs=1, 
                    int Format=FORMAT_SSFF )
    { return SSFF::Write_Open( File, 
                               Var_List, 
                               SSFF_Formant_Cols, 
                               Num_Recs, 
                               Format ); /

    float* Locate_Formant()
    { return (float*) Locate_Field( "Formant", 
                                    NULL, NULL, NULL ); /
};