home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of A1200
/
World_Of_A1200.iso
/
datafiles
/
text
/
c_manual
/
devices
/
audiodevice
/
example5.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-27
|
15KB
|
482 lines
/***********************************************************/
/* */
/* 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 );
}