home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 390.lha / SampLibrary / samp_writer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-01  |  9.3 KB  |  324 lines

  1. /****************************************************************************
  2.  
  3.     A simple SAMP writer. This program creates a simple square wave and then
  4.     saves it as a SAMP file. This demonstrates the use of the EXTRAVector for
  5.     setting various parameters of a wave, such as  sample rate, size, loop
  6.     points, etc. 
  7.  
  8.     This file uses puts(), so make sure that you launch it from a CLI/Shell.
  9.     Also, this code is NOT optimized. It is for educational use only ( and
  10.     we all know what _that_ means :-)
  11.  
  12.     by Jeff Glatt and Jim Fiore, dissidents.
  13.  
  14.     General compile/link instructions below. Note: the forms shown are certainly
  15.     not the most efficient! Also, note that SampInterface.o is different for
  16.     the two systems. To create your version, just assemble SampInterface.asm
  17.     with your system's assembler ( for non-Manx, make sure you take out the
  18.     reference to 'far code  far data' at the top of the .asm file. )
  19.  
  20.     ( Manx 3.6 )
  21.     cc +P samp_writer.c
  22.     ln samp_writer.o SampInterface.o -lml32 -lcl32
  23.  
  24.     ( Lattice 5.05 )
  25.     lc -b0 -ff samp_writer.c
  26.     blink lib:c.o samp_writer.o SAMPInterface.o to samp_writer lib lib:lcmffp.lib lib:lc.lib
  27.  
  28. *****************************************************************************/
  29.  
  30. #ifdef AZTEC_C
  31. #define NARGS      /* no arguments in function decs */
  32. #define NO_PRAGMAS
  33. #endif
  34.  
  35. #include "stdio.h"
  36. #include "math.h"
  37.  
  38. #ifdef LATTICE
  39. #include "stdlib.h"
  40. #include "mffp.h"
  41. #endif
  42.  
  43. #include "exec/types.h"
  44. #include "exec/memory.h"
  45. #include "libraries/dos.h"
  46. #include "libraries/dosextens.h"
  47.  
  48. #ifdef LATTICE
  49. #include "proto/all.h"
  50. #else
  51. #include "functions.h"
  52. #endif
  53.  
  54. /*============ Include files for dissidents' custom libraries ===========*/
  55.  
  56. #include "Samp.h"
  57.  
  58.  
  59. /*==================== For dissidents samp.library =====================*/
  60.  
  61. extern LONG SAMPError;            /* found in SAMPInterface.asm */
  62. struct SAMPBase               *SAMPBase = 0L;
  63. struct SAMPInfo                    *libSAMPinfo = 0L;
  64.  
  65. #define PLAY_CHANS 4
  66. UBYTE  play_map[ 128 * PLAY_CHANS ];  /* let NumOfChans = 4 */
  67.  
  68. /* Normally we would use MakeTransTable() to make a transpose table for a
  69.     desired sample period and with the desired # of steps up and down. We would
  70.     then stuff the returned *(ULONG) in our SampleHeader64's TransTable field.
  71.     We would do all this if our application wanted to playback the waveform
  72.     using the lookup table method as described in the samp doc. MakeTransTable
  73.     would automatically link this new table into our T_List (the handle being
  74.     this next variable). Then when we pass this handle to WriteWaves, the samp
  75.     library automatically retrieves the correct table and sets the wave's sample
  76.     period and rate accordingly. Since we aren't going to playback the wave we
  77.     create, we'll dispense with the table, and leave our SampleHeader64's
  78.     TransTable field NULL. WriteWaves() will then expect us to set the waveHeader's
  79.     sample rate and period via our EXTRAvector.
  80. */
  81.  
  82. struct TransposeNode          *T_List = 0L;
  83.  
  84. /* Declare 1 SampleHeader64 struct for saving the wave as a SAMP */
  85. #define  MAXSAMPLES 1L
  86. #define  NAMESIZE   16
  87.  
  88. struct SampleHeader64 samp_head[ MAXSAMPLES ];
  89.  
  90.  
  91. /*================== A goofy little structure for the wave =============*/
  92.  
  93. struct WaveData {
  94.    UBYTE *Name;
  95.    ULONG Period;
  96.    ULONG WaveSize;
  97.    SHORT *WaveStart;
  98.     ULONG LoopStart;
  99.     ULONG LoopEnd;
  100.    UBYTE LoopMode; };
  101.  
  102. UBYTE global_name[ NAMESIZE ] = {"My Brain Hertz"};
  103.  
  104. struct WaveData Prof_R_J_Gumby = {
  105.  /* *Name */           global_name,
  106.  /* Period */          0,
  107.  /* WaveSize */        0,
  108.  /* *WaveStart */      0,
  109.  /* LoopStart */       0,
  110.  /* LoopEnd */         0,
  111.  /* LoopMode */        0 };
  112.  
  113. struct WaveData *wave = &Prof_R_J_Gumby;
  114.  
  115. /* Professor Gumby says "I hit my head on the cupboard! I can't see anything!" */
  116.  
  117.  
  118.  
  119.  
  120. /*====================== The C Application begins here ==================*/
  121.  
  122.  
  123. #ifdef NARGS
  124. void  exit_all();
  125. BOOL  WriteExtraVector();
  126. BOOL    make_wave();
  127. long  main();
  128. #else
  129. void  exit_all( void );
  130. BOOL  WriteExtraVector( struct SampleHeader64 *, struct SAMPinfo *, struct waveHeader * );
  131. BOOL    make_wave( void );
  132. long  main( long, char ** );
  133. #endif
  134.  
  135. main( argc, argv )
  136. LONG argc;
  137. BYTE *argv[];
  138. {
  139.     UBYTE *address;
  140.  
  141.    /* Open the SAMP reader/writer library */
  142.  
  143.     if( !( SAMPBase = (struct SAMPBase *)OpenLibrary("samp.library", 0L) ) )
  144.     {
  145.         puts("need samp.library");
  146.         exit( FALSE );
  147.     }
  148.  
  149.     if( make_wave() )
  150.     {
  151.         /* At this point, we can do whatever we need with the wave data. So,
  152.             we'll save this guy back as a new SAMP wave. */
  153.  
  154.         /* Open the output file, always called "outfile" */
  155.         if( !( libSAMPinfo = OpenSampWrite( "outfile" ) ) )
  156.         {
  157.             address = SAMPErrorMsg( SAMPError );
  158.             puts( address );
  159.             exit_all();
  160.         }
  161.  
  162.         /* Set a few output fields of SAMPinfo, depending on need */
  163.         libSAMPinfo->MaxChars = NAMESIZE;
  164.         libSAMPinfo->SampleFormat = 16;  /* bits */
  165.         libSAMPinfo->NumOfWaves = 1;
  166.         libSAMPinfo->PlayMode = INDEPENDENT;
  167.         libSAMPinfo->NumOfChans = 4;
  168.  
  169.         /* Alter a few elements of the playMap, just so we can verify that this
  170.             works. */
  171.         play_map[0] = 1;
  172.         play_map[5] = 1;
  173.  
  174.         if( !WriteMHDR( 0L, &play_map[0] ) )
  175.         {
  176.             puts("Error writing MHDR");
  177.             CloseSamp();
  178.             exit_all();
  179.         }
  180.  
  181.         if( !WriteNames( NAMESIZE, &global_name[0] ) )
  182.         {
  183.             puts("Error writing Names");
  184.             CloseSamp();
  185.             exit_all();
  186.         }
  187.  
  188.         /* EXTRA Vector will allow us to set the waveHeader structure per wave */
  189.         libSAMPinfo->EXTRA = (APTR)WriteExtraVector;
  190.  
  191.         if( !WriteWaves( 0L, 1L, &samp_head[0], &T_List ) )
  192.         {
  193.             puts("Error writing Waves");
  194.             CloseSamp();
  195.             exit_all();
  196.         }
  197.  
  198.         CloseSamp();
  199.  
  200.         FreeTTables( &T_List );
  201.  
  202.     }
  203.  
  204.     exit_all();
  205.  
  206. }   /********** end of main() ********/
  207.  
  208.  
  209.  
  210.  
  211.  
  212. /****************************  exit_all() ***********************************
  213.  
  214.     General clean up routine which closes SAMP lib and deallocs wave mem.
  215.  
  216. *****************************************************************************/
  217.  
  218. void exit_all()
  219. {
  220.     if( wave->WaveStart ) FreeMem( wave->WaveStart, 2 * wave->WaveSize );
  221.     if( SAMPBase )        CloseLibrary( SAMPBase );
  222.     exit( FALSE );
  223. }
  224.  
  225.  
  226.  
  227.  
  228. /******************************** make_wave() *****************************
  229.  
  230.     This routine creates a 16 bit cheesoid square wave, and assigns the 
  231.     data required for the SAMP format conversion to a WaveData structure ( an
  232.     arbitrary structure of our design, just for this little example ). The
  233.     data elements ( loop points, period, etc. ) are pretty much arbitrary here.
  234.     Note that each sample point is 16 bits, hence 2 bytes, and all sizes are
  235.     in terms of sample points. It is just as easy to store sizes, loops, and 
  236.     such in terms of bytes...that's up to you! :-)
  237.  
  238.     ( Why is this wave so cheesey? Well for starters, it's not band-limited.
  239.     Aliasing anyone? )
  240.  
  241.     returns FALSE if error.
  242.  
  243. *****************************************************************************/
  244.  
  245. BOOL make_wave()
  246. {
  247.     UBYTE  x, y;
  248.     SHORT  *ptr;
  249.  
  250.     wave->WaveSize = 10000;       /* make this 10K points long ( 20K bytes ) */
  251.     wave->Period = 50000;        /* 50000 nSecs = 20K Hz sampling rate */
  252.     wave->LoopStart = 200;        /* Loop from the 200th point to the 8000th */
  253.     wave->LoopEnd = 8000;
  254.     wave->LoopMode = 0;            /* 'Forward only' type loop */
  255.  
  256.     if( !(ptr = AllocMem( 2 * wave->WaveSize, MEMF_PUBLIC )) )
  257.     {
  258.         puts("Can't make wave");
  259.         return( 0 );
  260.     }
  261.  
  262.     wave->WaveStart = ptr;
  263.  
  264.     /* make 200 cycles of a cheesey 400 Hz square wave of 18K peak.
  265.         200 cycles at 50 points each = 10K points */
  266.  
  267.     for( x = 0; x < 200; x++ )
  268.     {
  269.         for( y = 0; y < 25; y++ )   /* positive halfwave */
  270.             *ptr++ = 18000;
  271.  
  272.         for( y = 0; y < 25; y++ )   /* negative halfwave */
  273.             *ptr++ = -18000;
  274.     }
  275.  
  276.     return( 1 );  /* all is good */
  277.  
  278. } /******* end of make_wave() **********/
  279.  
  280.  
  281.  
  282.  
  283.  
  284. /****************************  WriteExtraVector() ****************************
  285.  
  286.     This is the routine passed to the EXTRA field of the SAMPinfo structure,
  287.     for writing SAMP files. This allows us to set a variety of parameters
  288.     describing the SAMP file and its waves. Here, we just set a few of the 
  289.     generally desirable elements. Because our SampleHeader64's TransTable field
  290.     was left NULL, the library was not able to set the waveHeader's sample
  291.     period and rate for us. We must do that here. Also, we did not setup the
  292.     rest of the SampleHeader64 fields, (i.e. size, loop start and end), so we
  293.     have to setup the waveHeader fields instead of the library.
  294.  
  295. *****************************************************************************/
  296.  
  297. BOOL WriteExtraVector( sample_header, samp_info, wave_header )
  298. struct SampleHeader64 *sample_header;
  299. struct SAMPinfo *samp_info;
  300. struct waveHeader *wave_header;
  301. {
  302.     /* The waveHeader structure uses all offsets and sizes in terms of bytes.
  303.         Since our example WaveData structure stores everything in terms of
  304.         sample points ( 2 bytes per point ), conversion is required.
  305.  
  306.         Note: if the TransTable field of the SampleHeader64 structure is 0,
  307.         ( ie, you didn't use a TransTable - see samp_readout example )
  308.         then you _must_ set the waveHeader's sample Rate and Period in this
  309.         vector ( as seen below ). */
  310.  
  311.    wave_header->WaveSize = wave->WaveSize * 2;   /* words to bytes */
  312.     wave_header->Period = wave->Period;
  313.     wave_header->Rate = 1E9 / ( wave->Period );   /* nanosecs to Hz */
  314.     wave_header->LoopStart = wave->LoopStart * 2; /* words to bytes */
  315.     wave_header->LoopEnd = wave->LoopEnd * 2;     /* words to bytes */
  316.     wave_header->LoopType = wave->LoopMode;
  317.  
  318.     sample_header->OneShotAddr = (BYTE *)(wave->WaveStart);  /* where the data is */
  319.  
  320.     return( 0 ); /* continue, all good */
  321. }
  322.  
  323. /*************************** DAT'S ALL FOLKS.... ****************************/
  324.