home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
-
- A simple SAMP writer. This program creates a simple square wave and then
- saves it as a SAMP file. This demonstrates the use of the EXTRAVector for
- setting various parameters of a wave, such as sample rate, size, loop
- points, etc.
-
- This file uses puts(), so make sure that you launch it from a CLI/Shell.
- Also, this code is NOT optimized. It is for educational use only ( and
- we all know what _that_ means :-)
-
- by Jeff Glatt and Jim Fiore, dissidents.
-
- General compile/link instructions below. Note: the forms shown are certainly
- not the most efficient! Also, note that SampInterface.o is different for
- the two systems. To create your version, just assemble SampInterface.asm
- with your system's assembler ( for non-Manx, make sure you take out the
- reference to 'far code far data' at the top of the .asm file. )
-
- ( Manx 3.6 )
- cc +P samp_writer.c
- ln samp_writer.o SampInterface.o -lml32 -lcl32
-
- ( Lattice 5.05 )
- lc -b0 -ff samp_writer.c
- blink lib:c.o samp_writer.o SAMPInterface.o to samp_writer lib lib:lcmffp.lib lib:lc.lib
-
- *****************************************************************************/
-
- #ifdef AZTEC_C
- #define NARGS /* no arguments in function decs */
- #define NO_PRAGMAS
- #endif
-
- #include "stdio.h"
- #include "math.h"
-
- #ifdef LATTICE
- #include "stdlib.h"
- #include "mffp.h"
- #endif
-
- #include "exec/types.h"
- #include "exec/memory.h"
- #include "libraries/dos.h"
- #include "libraries/dosextens.h"
-
- #ifdef LATTICE
- #include "proto/all.h"
- #else
- #include "functions.h"
- #endif
-
- /*============ Include files for dissidents' custom libraries ===========*/
-
- #include "Samp.h"
-
-
- /*==================== For dissidents samp.library =====================*/
-
- extern LONG SAMPError; /* found in SAMPInterface.asm */
- struct SAMPBase *SAMPBase = 0L;
- struct SAMPInfo *libSAMPinfo = 0L;
-
- #define PLAY_CHANS 4
- UBYTE play_map[ 128 * PLAY_CHANS ]; /* let NumOfChans = 4 */
-
- /* Normally we would use MakeTransTable() to make a transpose table for a
- desired sample period and with the desired # of steps up and down. We would
- then stuff the returned *(ULONG) in our SampleHeader64's TransTable field.
- We would do all this if our application wanted to playback the waveform
- using the lookup table method as described in the samp doc. MakeTransTable
- would automatically link this new table into our T_List (the handle being
- this next variable). Then when we pass this handle to WriteWaves, the samp
- library automatically retrieves the correct table and sets the wave's sample
- period and rate accordingly. Since we aren't going to playback the wave we
- create, we'll dispense with the table, and leave our SampleHeader64's
- TransTable field NULL. WriteWaves() will then expect us to set the waveHeader's
- sample rate and period via our EXTRAvector.
- */
-
- struct TransposeNode *T_List = 0L;
-
- /* Declare 1 SampleHeader64 struct for saving the wave as a SAMP */
- #define MAXSAMPLES 1L
- #define NAMESIZE 16
-
- struct SampleHeader64 samp_head[ MAXSAMPLES ];
-
-
- /*================== A goofy little structure for the wave =============*/
-
- struct WaveData {
- UBYTE *Name;
- ULONG Period;
- ULONG WaveSize;
- SHORT *WaveStart;
- ULONG LoopStart;
- ULONG LoopEnd;
- UBYTE LoopMode; };
-
- UBYTE global_name[ NAMESIZE ] = {"My Brain Hertz"};
-
- struct WaveData Prof_R_J_Gumby = {
- /* *Name */ global_name,
- /* Period */ 0,
- /* WaveSize */ 0,
- /* *WaveStart */ 0,
- /* LoopStart */ 0,
- /* LoopEnd */ 0,
- /* LoopMode */ 0 };
-
- struct WaveData *wave = &Prof_R_J_Gumby;
-
- /* Professor Gumby says "I hit my head on the cupboard! I can't see anything!" */
-
-
-
-
- /*====================== The C Application begins here ==================*/
-
-
- #ifdef NARGS
- void exit_all();
- BOOL WriteExtraVector();
- BOOL make_wave();
- long main();
- #else
- void exit_all( void );
- BOOL WriteExtraVector( struct SampleHeader64 *, struct SAMPinfo *, struct waveHeader * );
- BOOL make_wave( void );
- long main( long, char ** );
- #endif
-
- main( argc, argv )
- LONG argc;
- BYTE *argv[];
- {
- UBYTE *address;
-
- /* Open the SAMP reader/writer library */
-
- if( !( SAMPBase = (struct SAMPBase *)OpenLibrary("samp.library", 0L) ) )
- {
- puts("need samp.library");
- exit( FALSE );
- }
-
- if( make_wave() )
- {
- /* At this point, we can do whatever we need with the wave data. So,
- we'll save this guy back as a new SAMP wave. */
-
- /* Open the output file, always called "outfile" */
- if( !( libSAMPinfo = OpenSampWrite( "outfile" ) ) )
- {
- address = SAMPErrorMsg( SAMPError );
- puts( address );
- exit_all();
- }
-
- /* Set a few output fields of SAMPinfo, depending on need */
- libSAMPinfo->MaxChars = NAMESIZE;
- libSAMPinfo->SampleFormat = 16; /* bits */
- libSAMPinfo->NumOfWaves = 1;
- libSAMPinfo->PlayMode = INDEPENDENT;
- libSAMPinfo->NumOfChans = 4;
-
- /* Alter a few elements of the playMap, just so we can verify that this
- works. */
- play_map[0] = 1;
- play_map[5] = 1;
-
- if( !WriteMHDR( 0L, &play_map[0] ) )
- {
- puts("Error writing MHDR");
- CloseSamp();
- exit_all();
- }
-
- if( !WriteNames( NAMESIZE, &global_name[0] ) )
- {
- puts("Error writing Names");
- CloseSamp();
- exit_all();
- }
-
- /* EXTRA Vector will allow us to set the waveHeader structure per wave */
- libSAMPinfo->EXTRA = (APTR)WriteExtraVector;
-
- if( !WriteWaves( 0L, 1L, &samp_head[0], &T_List ) )
- {
- puts("Error writing Waves");
- CloseSamp();
- exit_all();
- }
-
- CloseSamp();
-
- FreeTTables( &T_List );
-
- }
-
- exit_all();
-
- } /********** end of main() ********/
-
-
-
-
-
- /**************************** exit_all() ***********************************
-
- General clean up routine which closes SAMP lib and deallocs wave mem.
-
- *****************************************************************************/
-
- void exit_all()
- {
- if( wave->WaveStart ) FreeMem( wave->WaveStart, 2 * wave->WaveSize );
- if( SAMPBase ) CloseLibrary( SAMPBase );
- exit( FALSE );
- }
-
-
-
-
- /******************************** make_wave() *****************************
-
- This routine creates a 16 bit cheesoid square wave, and assigns the
- data required for the SAMP format conversion to a WaveData structure ( an
- arbitrary structure of our design, just for this little example ). The
- data elements ( loop points, period, etc. ) are pretty much arbitrary here.
- Note that each sample point is 16 bits, hence 2 bytes, and all sizes are
- in terms of sample points. It is just as easy to store sizes, loops, and
- such in terms of bytes...that's up to you! :-)
-
- ( Why is this wave so cheesey? Well for starters, it's not band-limited.
- Aliasing anyone? )
-
- returns FALSE if error.
-
- *****************************************************************************/
-
- BOOL make_wave()
- {
- UBYTE x, y;
- SHORT *ptr;
-
- wave->WaveSize = 10000; /* make this 10K points long ( 20K bytes ) */
- wave->Period = 50000; /* 50000 nSecs = 20K Hz sampling rate */
- wave->LoopStart = 200; /* Loop from the 200th point to the 8000th */
- wave->LoopEnd = 8000;
- wave->LoopMode = 0; /* 'Forward only' type loop */
-
- if( !(ptr = AllocMem( 2 * wave->WaveSize, MEMF_PUBLIC )) )
- {
- puts("Can't make wave");
- return( 0 );
- }
-
- wave->WaveStart = ptr;
-
- /* make 200 cycles of a cheesey 400 Hz square wave of 18K peak.
- 200 cycles at 50 points each = 10K points */
-
- for( x = 0; x < 200; x++ )
- {
- for( y = 0; y < 25; y++ ) /* positive halfwave */
- *ptr++ = 18000;
-
- for( y = 0; y < 25; y++ ) /* negative halfwave */
- *ptr++ = -18000;
- }
-
- return( 1 ); /* all is good */
-
- } /******* end of make_wave() **********/
-
-
-
-
-
- /**************************** WriteExtraVector() ****************************
-
- This is the routine passed to the EXTRA field of the SAMPinfo structure,
- for writing SAMP files. This allows us to set a variety of parameters
- describing the SAMP file and its waves. Here, we just set a few of the
- generally desirable elements. Because our SampleHeader64's TransTable field
- was left NULL, the library was not able to set the waveHeader's sample
- period and rate for us. We must do that here. Also, we did not setup the
- rest of the SampleHeader64 fields, (i.e. size, loop start and end), so we
- have to setup the waveHeader fields instead of the library.
-
- *****************************************************************************/
-
- BOOL WriteExtraVector( sample_header, samp_info, wave_header )
- struct SampleHeader64 *sample_header;
- struct SAMPinfo *samp_info;
- struct waveHeader *wave_header;
- {
- /* The waveHeader structure uses all offsets and sizes in terms of bytes.
- Since our example WaveData structure stores everything in terms of
- sample points ( 2 bytes per point ), conversion is required.
-
- Note: if the TransTable field of the SampleHeader64 structure is 0,
- ( ie, you didn't use a TransTable - see samp_readout example )
- then you _must_ set the waveHeader's sample Rate and Period in this
- vector ( as seen below ). */
-
- wave_header->WaveSize = wave->WaveSize * 2; /* words to bytes */
- wave_header->Period = wave->Period;
- wave_header->Rate = 1E9 / ( wave->Period ); /* nanosecs to Hz */
- wave_header->LoopStart = wave->LoopStart * 2; /* words to bytes */
- wave_header->LoopEnd = wave->LoopEnd * 2; /* words to bytes */
- wave_header->LoopType = wave->LoopMode;
-
- sample_header->OneShotAddr = (BYTE *)(wave->WaveStart); /* where the data is */
-
- return( 0 ); /* continue, all good */
- }
-
- /*************************** DAT'S ALL FOLKS.... ****************************/
-