home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************/
- /* */
- /* Amiga C Encyclopedia (ACE) V3.0 Amiga C Club (ACC) */
- /* ------------------------------- ------------------ */
- /* */
- /* Book: ACM Devices Amiga C Club */
- /* Chapter: AudioDevice Tulevagen 22 */
- /* File: Example5.c 181 41 LIDINGO */
- /* Author: Anders Bjerin SWEDEN */
- /* Date: 92-04-24 */
- /* Version: 1.00 */
- /* */
- /* Copyright 1992, Anders Bjerin - Amiga C Club (ACC) */
- /* */
- /* Registered members may use this program freely in their */
- /* own commercial/noncommercial programs/articles. */
- /* */
- /***********************************************************/
-
- /* This example demonstrates how you can play sounds */
- /* in STEREO. First we play a sound in the left channel, */
- /* then we switch to the right, and then back again, and */
- /* so on... */
- /* */
- /* In this example are we reserving the audio channels */
- /* at the same time as we open the audio device. We use */
- /* two audio requests, one for the left channel and the */
- /* other one for the right channel. */
-
-
-
- #include <exec/types.h> /* STRPTR */
- #include <exec/memory.h> /* MEMF_CHIP */
- #include <devices/audio.h> /* Audio Device */
- #include <math.h> /* sine() etc... */
-
- /* When you are using mathematical functions like sin(), cos() */
- /* sqrt() etc... you must include the "math.h" header file, or */
- /* the compiler will not know what values the functions are */
- /* going to return. he compiler assumes then that they return */
- /* integers, which is wrong (they return float of double */
- /* values) and this will cause many errors in the calculations. */
-
-
-
- /* The audio channels: (Sadly these constants */
- /* have not been defined in any header file.) */
-
- /* Values: */
- #define LEFT0B 0
- #define RIGHT0B 1
- #define RIGHT1B 2
- #define LEFT1B 3
-
- /* Bit fields: */
- #define LEFT0F (1<<LEFT0B)
- #define RIGHT0F (1<<RIGHT0B)
- #define RIGHT1F (1<<RIGHT1B)
- #define LEFT1F (1<<LEFT1B)
-
- /* Sound priorities: */
- #define SOUND_UNSTOPPABLE 127
- #define SOUND_EMERGENCIES 95
- #define SOUND_ATTENTION 85
- #define SOUND_SPEECH 75
- #define SOUND_INFORMATION 60
- #define SOUND_MUSIC 0
- #define SOUND_EFFECT -35
- #define SOUND_BACKGROUND -90
- #define SOUND_SILENCE -128
-
- /* The clock constant: */
- #define NTSC_CLOCK 3579545 /* American Amigas - 60Hz */
- #define PAL_CLOCK 3546895 /* European Amigas - 50Hz */
-
- /* Define min/max-volumes: */
- #define MAXVOLUME 64
- #define MINVOLUME 0
-
- /* Some common notes (their frequencies are */
- /* defined later on in this program): */
- #define NOTE_A 0
- #define NOTE_Ax 1
- #define NOTE_B 2
- #define NOTE_C 3
- #define NOTE_Cx 4
- #define NOTE_D 5
- #define NOTE_Dx 6
- #define NOTE_E 7
- #define NOTE_F 8
- #define NOTE_Fx 9
- #define NOTE_G 10
- #define NOTE_Gx 11
-
- /* An octave consists of 12 notes: */
- #define OCTAVE 12
-
- /* Our sine wave will contain 16 values: */
- #define SINE_DATA_LENGTH 16
-
-
-
- /* Declare a pointer to our reply port: */
- struct MsgPort *replymp = NULL;
-
- /* Declare two audio request block pointers. One for the */
- /* left channel, and the other on for the right channel: */
- struct IOAudio *left_audio_req = NULL;
- struct IOAudio *right_audio_req = NULL;
-
-
-
- /* Two lists of preffered channels. On for the */
- /* left channels, and the other one for right */
- /* channels: */
-
- UBYTE left_allocation_array[] = { LEFT0F, LEFT1F };
- UBYTE right_allocation_array[] = { RIGHT0F, RIGHT1F };
-
-
-
- /* The notes (defined above) frequencies. These frequencies */
- /* represent notes which are one octave higher than the middle */
- /* octave on a piano. To change octave, simply double/half these */
- /* values. Ex, A=880, one octave lower A=440, one octave higher */
- /* A=1760. */
- /* */
- /* Instead of changing the frequencies you can of course double */
- /* or half the amount of samled waveform data. If you double the */
- /* amount of sampled waveformdata you will move down one octave */
- /* and vice versa. In this example when we caluculate the period */
- /* value we use the length of the vaweform as one parameter. */
- /* Therefore, if you change the length of the waveform the same */
- /* frequencies will be used. */
-
- UWORD note_frequency[ OCTAVE ]=
- {
- 880.0, /* A */
- 932.3, /* A# */
- 987.8, /* B */
- 1046.5, /* C */
- 1108.7, /* C# */
- 1174.7, /* D */
- 1244.5, /* D# */
- 1318.5, /* E */
- 1396.9, /* F */
- 1480.0, /* F# */
- 1568.0, /* G */
- 1661.2 /* G# */
- };
-
-
-
- /* Declare a pointer to the sine waveform: */
- BYTE *sine_wave = NULL;
-
-
-
- /* Declare our functions: */
- void main();
- void clean_up( STRPTR text );
-
-
-
- void main()
- {
- /* Error messages: */
- BYTE error;
-
- /* Used in the loops: */
- int loop;
-
- /* Current note played: */
- int note;
-
-
-
- /* Get a reply port: (No name, priority 0) */
- replymp = (struct MsgPort *)
- CreatePort( NULL, 0 );
- if( !replymp )
- clean_up( "Could not create the reply port!" );
-
-
-
- /* We are going to use two audio requests, one for each channel. */
- /* Since both requests must be linked to the audio device we */
- /* "open" the device twice, one for each request. We could of */
- /* course open one audio channel at the same time as we open the */
- /* audio device. We would then copy the whole request to the */
- /* other one. This is necessary since the first request has been */
- /* initilized to fit the audio device, and if you want to use */
- /* the ther request as well, it must have the same values. Once */
- /* we have copied the request we then have to reserve the other */
- /* channel by using the ADCMD_ALLOCATE command. As you surely */
- /* understand, it is much easier to "open" the audio device */
- /* twice. (Just remember, before your program terminates, to */
- /* close it for both requests!) */
-
-
-
- /* This time will we try to reserve a sound */
- /* channel at the same time when we open the */
- /* audio device. To do this we must: */
- /* 1. Set the sound priority. */
- /* 2. Give it an array of desired channels. */
- /* 3. Set the lenght of the array. */
- /* */
- /* We do not have to set the ADCMD_ALLOCATE */
- /* flag since if the io_Length is not zero */
- /* the device will automatically assume that */
- /* we whant to reserve a sound channel. The */
- /* ADIOF_NOWAIT flag is automatically set when */
- /* you open the audio device and reserve a */
- /* sound channel at the same time. */
-
- /* LEFT CHANNEL */
-
- /* Allocate and preinitialize the left audio request block: */
- left_audio_req = (struct IOAudio *)
- CreateExtIO( replymp, sizeof( struct IOAudio ) );
- if( !left_audio_req )
- clean_up( "Not enough memory for the left IOAudio structure!" );
-
- /* Set sound priority: (We are going to play music.) */
- left_audio_req->ioa_Request.io_Message.mn_Node.ln_Pri = SOUND_MUSIC;
-
- /* Give the request block a pointer to our allocation array: */
- left_audio_req->ioa_Data = left_allocation_array;
-
- /* Set the length of the allocation array: */
- left_audio_req->ioa_Length = sizeof( left_allocation_array );
-
- /* Open the Audio Device and allocate a left sound */
- /* channel at the same time: */
- error = OpenDevice( AUDIONAME, 0, left_audio_req, 0 );
- if( error )
- {
- /* Clear the "io_Device" flag since we have not opened the device: */
- left_audio_req->ioa_Request.io_Device = NULL;
-
- /* Quit: */
- clean_up( "Could not open the Audio Device for the left channel!" );
- }
-
-
- /* RIGHT CHANNEL */
-
- /* Allocate and preinitialize the right audio request block: */
- right_audio_req = (struct IOAudio *)
- CreateExtIO( replymp, sizeof( struct IOAudio ) );
- if( !right_audio_req )
- clean_up( "Not enough memory for the right IOAudio structure!" );
-
- /* Set sound priority: (We are going to play music.) */
- right_audio_req->ioa_Request.io_Message.mn_Node.ln_Pri = SOUND_MUSIC;
-
- /* Give the request block a pointer to our allocation array: */
- right_audio_req->ioa_Data = right_allocation_array;
-
- /* Set the length of the allocation array: */
- right_audio_req->ioa_Length = sizeof( right_allocation_array );
-
- /* Open the Audio Device and allocate a right sound */
- /* channel at the same time: */
- error = OpenDevice( AUDIONAME, 0, right_audio_req, 0 );
- if( error )
- {
- /* Clear the "io_Device" flag since we have not opened the device: */
- right_audio_req->ioa_Request.io_Device = NULL;
-
- /* Quit: */
- clean_up( "Could not open the Audio Device for the right channel!" );
- }
-
-
- /* Allocate some chip memory were we can store the sine wave: */
- /* (All memory allocated by AllocMem() will alwyas start on a */
- /* word boundary.) */
- sine_wave = (BYTE *) AllocMem( SINE_DATA_LENGTH, MEMF_CHIP );
-
- /* Have we got the memory? */
- if( !sine_wave )
- clean_up( "Not enough memory for the sine wave!" );
-
- /* Initialize the sine waveform: */
- for( loop = 0; loop < SINE_DATA_LENGTH; loop++ )
- sine_wave[ loop ] =
- 127 * sin( loop * 2 * PI / SINE_DATA_LENGTH );
-
-
-
- /* Prepare to play sound with the left channel: */
-
- /* Give the request block a pointer to the waveform: */
- left_audio_req->ioa_Data = sine_wave;
-
- /* Set the length of the waveform: */
- /* (Must be an even number of bytes.) */
- left_audio_req->ioa_Length = SINE_DATA_LENGTH;
-
- /* Play the sound 400 times: */
- left_audio_req->ioa_Cycles = 400;
-
- /* Going to play a tune: */
- left_audio_req->ioa_Request.io_Command = CMD_WRITE;
-
- /* Use the volume and period fields of the request block: */
- /* (If we do not set this flag the previous volume and */
- /* period values will be used.) */
- left_audio_req->ioa_Request.io_Flags = ADIOF_PERVOL;
-
- /* Medium volume: */
- left_audio_req->ioa_Volume = 32;
-
-
-
- /* Prepare to play sound with the right channel: */
-
- /* Give the request block a pointer to the waveform: */
- right_audio_req->ioa_Data = sine_wave;
-
- /* Set the length of the waveform: */
- /* (Must be an even number of bytes.) */
- right_audio_req->ioa_Length = SINE_DATA_LENGTH;
-
- /* Play the sound 400 times: */
- right_audio_req->ioa_Cycles = 400;
-
- /* Going to play a tune: */
- right_audio_req->ioa_Request.io_Command = CMD_WRITE;
-
- /* Use the volume and period fields of the request block: */
- /* (If we do not set this flag the previous volume and */
- /* period values will be used.) */
- right_audio_req->ioa_Request.io_Flags = ADIOF_PERVOL;
-
- /* Medium volume: */
- right_audio_req->ioa_Volume = 32;
-
-
-
- /* Tell the user to be prepared: */
- printf( "Now some STEREO sound!\n" );
-
- /* Play one octave: */
- for( note=0; note < OCTAVE; note++ )
- {
- /* Left channel: */
-
- /* Set the period: */
- left_audio_req->ioa_Period =
- PAL_CLOCK / note_frequency[ note ] / SINE_DATA_LENGTH;
-
- /* Set a mark: */
- printf( "Left\n" );
-
- /* Start to play a note: */
- BeginIO( left_audio_req );
-
- /* Wait for the note to be completed: */
- error = WaitIO( left_audio_req );
-
- /* Was the note successfully played? */
- if( error )
- clean_up( "Error while playing on the left channel!" );
-
-
- /* Right channel: */
-
- /* Set the period: */
- right_audio_req->ioa_Period =
- PAL_CLOCK / note_frequency[ note ] / SINE_DATA_LENGTH;
-
- /* Set a mark: */
- printf( "Right\n", right_audio_req->ioa_Period );
-
- /* Start to play a note: */
- BeginIO( right_audio_req );
-
- /* Wait for the note to be completed: */
- error = WaitIO( right_audio_req );
-
- /* Was the note successfully played? */
- if( error )
- clean_up( "Error while playing on the right channel!" );
- }
-
-
-
-
- /* Clean up and quit: */
- clean_up( "The End!" );
- }
-
-
-
- /* Close and return everything that has been */
- /* opened and allocated before we quit: */
-
- void clean_up( STRPTR text )
- {
- /* If we have a request block and it does not contain */
- /* any errors we know that a channel has been allocated */
- /* (and is not stolen) and must be deallocated: */
-
- /* Free the left channel: */
- if( left_audio_req && !(left_audio_req->ioa_Request.io_Error) )
- {
- /* Free the channel: */
- left_audio_req->ioa_Request.io_Command = ADCMD_FREE;
-
- /* We are allowed to use the function DoIO() for */
- /* this request since it will not change any */
- /* values that are vital for us: */
- DoIO( left_audio_req );
-
- /* The lock is automatically unlocked when we */
- /* free the audio channel. */
- }
-
-
- /* Free the right channel: */
- if( right_audio_req && !(right_audio_req->ioa_Request.io_Error) )
- {
- /* Free the channel: */
- right_audio_req->ioa_Request.io_Command = ADCMD_FREE;
-
- /* We are allowed to use the function DoIO() for */
- /* this request since it will not change any */
- /* values that are vital for us: */
- DoIO( right_audio_req );
-
- /* The lock is automatically unlocked when we */
- /* free the audio channel. */
- }
-
-
-
- /* Empty the reply port: */
- while( GetMsg( replymp ) )
- printf( "Collected a message at the reply port.\n" );
-
- /* If we have a request block and the "io_Device" field */
- /* is not zero, we know that the device has successfully */
- /* been opened and must now be closed. */
-
- /* Close the audio device for the left channel: */
- if( left_audio_req && left_audio_req->ioa_Request.io_Device )
- CloseDevice( left_audio_req );
-
- /* Close the audio device for the right channel: */
- if( right_audio_req && right_audio_req->ioa_Request.io_Device )
- CloseDevice( right_audio_req );
-
-
-
- /* Remove the replyport: */
- if( replymp )
- DeletePort( replymp);
-
- /* Dealocate the left IOAudio structure: */
- if( left_audio_req )
- DeleteExtIO( left_audio_req, sizeof( struct IOAudio ) );
-
- /* Dealocate the right IOAudio structure: */
- if( right_audio_req )
- DeleteExtIO( right_audio_req, sizeof( struct IOAudio ) );
-
- /* Dealocate the sine waveform: */
- if( sine_wave )
- FreeMem( sine_wave, SINE_DATA_LENGTH );
-
- /* Print the last message: */
- printf( "%s\n", text );
-
- /* Quit: */
- exit( 0 );
- }
-
-
-