::  
::  proposal:
::  
::      int lame_open(); 
::      // allocates internal structures
::  
::      int lame_set_param( int handle, LameParameter Parameter, int Value );
::      // assigns Lame's parameter a value
::
a) Not every variable is an integer. C programmer try to store everything
   (food, women, cars ;-) in an int, but from the state of good programming
   style this is brain dead and not far from FORTRAN 4.

b) Brain dead interfaces creates things like:

   double d = 3.14159265358979;
   float  f = d;
   func ( *(int*)&f );          // transmit float value through int
   func ( (int)stdout );        // fails on sizeof(void*) > sizeof(int)

c) It is wise to return the actual parameter

d) it is wise to return an status word (error code)

e) it is wise not to use in-band-signaling for error codes

f) Sometimes it is useful to change some parameters atomically
   (For RT systems this is often an indispensable need).

So we got something like:

        int lame_set_param ( 
                int            handle, 
                LameParameter  ParameterType, 
                ... );
        // assigns Lame's parameter a value

Examples:

        long double ld;
        double      d;
        int         i1;
        int         i2;
        FILE*       fp;

        ld = 44055.938461538;                   // NTSC PCM, lips synchr.
        printf ( "Input fs is %lf, ", ld );
        err = lame_set_param ( lh, Lame_LD_InputSampleFreq, &ld )
        printf ( "set to %lf.\n", ld );

        i1 = 128000;
        i2 = 256000;
        printf ( "VBR bitrate should be between %7.3f...%7.3f, ", i1*1.e-3, i2*1.e-3 );
        err = lame_set_param ( lh, Lame_I2_VBRBitrateRange, &i1, &i2 )
        printf ( "set to %7.3f...%7.3f\n", i1*1.e-3, i2*1.e-3 );

        fp = fopen ( "report", "w" );
        err = lame_set_param ( lh, Lame_fp_Reportfp, &fp );

Another question: Why not using a set of functions to setup parameters.
It is not more difficult, but less, it does not disable type checking and
link checking. 

This is also something I call: "cosmetic fake simplification".
It:

   * moves complexity instead of reducing (virtual hiding)
   * disables type checking
   * disables functionality checking by the linker
   * it clouds errors (compile/link time => run time or later)

Okay. It's C ;-)


::      int lame_init_params( int handle );
::      // fills up rest of needed parameters by default values
::
Not necessary. Can be done by lame_encode stuff.

lame_...._flags has an internal flag:

0: invalid, before open() or after close()
1: valid, open() was done, ready for setup
2: the first lame_encode_...() stuff was called (finalization of params)


::  
::      usual lame_encode() stuff
::  
::      void lame_close( int handle );
::      // frees all allocated internal structures
::  
::  
::  just enumerate all parameters LAME will use, we can allways append
::  new ones if needed. A 32 bit int should provide us enough internal 
::  parameters ;)
::  
::  typedef enum{
::      lp_bitrate,
::      lp_vbrmode,
::      lp_vbrquality,
::      lp_vbrmin,
::      lp_vbrmax,
::      lp_crc,
::      :
::  } LameParameter;
::
Another point is: It is not wise to mix
  -vbr -b  and -cbr -b
I would use three parameters for -vbr -b, -vbr -B and -cbr -b.
  
::  
::  // different channel modes
::  #define CM_MONO 1
::  #define CM_LR_STEREO 2
::  #define CM_J_STEREO 3
::  #define CM_MS_STEREO 4
::  ...
::  
::  Example setup sequence:
::  
::      handle = lame_open();
::  
::      lame_set_param( handle, lp_bitrate, 128 );
::      lame_set_param( handle, lp_crc, FALSE );
::      lame_set_param( handle, lp_original, FALSE );
::      lame_set_param( handle, lp_channelmode, CM_J_STEREO );
::      lame_set_param( handle, lp_quality, 2 );
::  
::      lame_set_param( handle, lp_lowpass, 5500 );
::      lame_set_param( handle, lp_lowpasswidth, 500 );
::      lame_set_param( handle, lp_highpass, 100 );
::  
::      lame_set_param( handle, lp_resample, 11025 );
::  
::      lame_set_param( handle, lp_voice, TRUE );
::  
::      lame_init_params( handle );
::  
::      <encoding>
::  
::      lame_close( handle ); 
::  
::  This way there is no need to parse any strings, we don't pass
::  any pointers, the setup routine would just be a big switch/case.
::
An additional demultiplexer/multiplexer.

::  
handle = lame_open ();

lame_set_cbr_bitrate  ( handle, 128000 );
lame_set_crc          ( handle, disable );
lame_set_genuine      ( handle, false );
lame_set_channel_mode ( handle, channelmode_jstereo );
lame_set_quality      ( handle, 100-2*100/9 );          // arbitrary values are scaled 
(bad=0,best=100)
lame_set_lowpass      ( handle, 5500.0 );
lame_set_lowpass_width( handle,  500.0 );
lame_set_lowpass_width_ratio ( handle,  0.0909 );
lame_set_highpass     ( handle,  100.0 );

lame_set_output_samplefreq ( handle, 11025.0 );

lame_set_presets      ( handle, preset_voice );

<encoding>

lame_close ( handle ); 


Handles have advantages and disadvantages:

- you need an internal pointer array, with affects the maximum number of
  handles:

  lame_global_flags *Table [20];

  lame_open() searches a free slot and allocates memory.
  A forget lame_close() makes difficult to find problems.

- no type security. Noone avoids things like:

  lame_set_highpass     ( 44100/1000,  100.0 );

+ you can't access the structure itself.


- this can also be achieved via a simple trick.
  You use different structure definitions for the interface and for the lib.

  interface:

  typedef enum {
      valid_setup   = 1,        // ready for setup
      valid_encode  = 2         // ready for encoding
                                // otherwise invalid
   } valid_t;

#ifndef ____LAME_LIB

  typedef struct {
      valid_t  valid; 
  } LAME;

#else

  typedef struct {
      valid_t        valid; 
      long double    input_sample_freq;
      long double    output_sample_freq;
      unsigned       quality;           // unsigned is better to ease boundary checks
      bool           crc;
      unsigned long  cbr_bitrate;       // bps, not Gbps or thinks like that
      unsigned long  vbr_min_bitrate;
      unsigned long  vbr_max_bitrate;
      ...
  } LAME;

#endif

    LAME*  lame_open           ( void );
    int    lame_set_crc        ( LAME*, enable_t );
    int    lame_set_genuine    ( LAME*, bool );
    int    lame_set_lowpass    ( LAME*, double );
    int    lame_close          ( LAME* );
    double lame_report_lowpass ( const LAME* );   // I hate set and get


-- 
Mit freundlichen Grüßen
Frank Klemm
 
eMail | [EMAIL PROTECTED]       home: [EMAIL PROTECTED]
phone | +49 (3641) 64-2721    home: +49 (3641) 390545
sMail | R.-Breitscheid-Str. 43, 07747 Jena, Germany

--
MP3 ENCODER mailing list ( http://geek.rcc.se/mp3encoder/ )

Reply via email to