home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of A1200
/
World_Of_A1200.iso
/
datafiles
/
text
/
c_manual
/
devices
/
audiodevice
/
example2.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-27
|
13KB
|
455 lines
/***********************************************************/
/* */
/* Amiga C Encyclopedia (ACE) V3.0 Amiga C Club (ACC) */
/* ------------------------------- ------------------ */
/* */
/* Book: ACM Devices Amiga C Club */
/* Chapter: AudioDevice Tulevagen 22 */
/* File: Example2.c 181 41 LIDINGO */
/* Author: Anders Bjerin SWEDEN */
/* Date: 92-04-21 */
/* 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 program is very similar to the previous example, */
/* but this time are we using double buffered sounds, and */
/* there will therefore not be any annoying "clicks" */
/* between the notes. */
/* */
/* The technique with double buffered sound is that while */
/* the first sound is played the second sound is already */
/* sent to the audio device. When the first sound */
/* terminates the second sound can immediately start */
/* without any delay. While the second sound is being */
/* played the first sound is prepared and sent and so */
/* on... Because there is never any delay between the */
/* sounds there will never be any annoying clicks. */
#include <exec/types.h> /* STRPTR */
#include <exec/memory.h> /* MEMF_CHIP */
#include <devices/audio.h> /* Audio Device */
/* 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 */
/* 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
/* Define min/max-volumes: */
#define MAXVOLUME 64
#define MINVOLUME 0
/* Our square waveform data consists of two samples: */
/* (Waveform data must alwyas be an even number of */
/* byte long.) */
#define SQUARE_DATA_LENGTH 2
/* Declare a pointer to our reply port: */
struct MsgPort *replymp = NULL;
/* Declare two audio request pointers: (Since we are going */
/* to use two sound requests at the same time we need two */
/* audio requests.) */
struct IOAudio *audio_req[ 2 ];
/* Our list of preffered channel combinations: */
/* (First we try to reserve the first channel, */
/* then the second, third and finally fourth */
/* audio channel.) */
UBYTE allocation_array[]=
{
LEFT0F,
RIGHT0F,
RIGHT1F,
LEFT1F
};
/* Declare a pointer to some soundwave data: */
BYTE *square_wave = NULL;
/* 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 our functions: */
void main();
void clean_up( STRPTR text );
void main()
{
/* Error messages: */
BYTE error;
/* The channel we have received: */
UBYTE channel;
/* Used in the loops: */
int note, loop;
/* Which request is being played and which */
/* is waiting to be played: */
int playing;
int waiting;
/* Used when we copy the first request */
/* block to the second one: */
BYTE *first_ptr;
BYTE *second_ptr;
/* Get a reply port: (No name, priority 0) */
replymp = (struct MsgPort *)
CreatePort( NULL, 0 );
if( !replymp )
clean_up( "Could not create the reply port!" );
/* Allocate and preinitialize two audio request blocks: */
for( loop = 0; loop < 2; loop++ )
{
audio_req[ loop ] = (struct IOAudio *)
CreateExtIO( replymp, sizeof( struct IOAudio ) );
if( !audio_req[ loop ] )
clean_up( "Not enough memory for the IOAudio structure!" );
}
/* Open the Audio Device: (We will try to */
/* reserve a sound channel later on. We use */
/* the first request block, and we will */
/* later copy everything to the second */
/* request block. */
error = OpenDevice( AUDIONAME, 0, audio_req[ 0 ], 0 );
if( error )
{
/* Clear the "io_Device" flag since we have not opened the device: */
audio_req[ 0 ]->ioa_Request.io_Device = NULL;
/* Quit: */
clean_up( "Could not open the Audio Device!" );
}
/* Reserve a channel with help of the first request block: */
/* Try to reserve a channel: */
audio_req[ 0 ]->ioa_Request.io_Command = ADCMD_ALLOCATE;
/* Set sound priority: (We are going to play some music.) */
audio_req[ 0 ]->ioa_Request.io_Message.mn_Node.ln_Pri = SOUND_MUSIC;
/* Do not wait for any channels to be free, */
/* return immediately, successfully or not: */
audio_req[ 0 ]->ioa_Request.io_Flags = ADIOF_NOWAIT;
/* Give the request block a pointer to our allocation array: */
audio_req[ 0 ]->ioa_Data = allocation_array;
/* Set the length of the allocation array: */
audio_req[ 0 ]->ioa_Length = sizeof( allocation_array );
/* Do our request: */
BeginIO( audio_req[ 0 ] );
/* Wait for the request to be completed: */
error = WaitIO( audio_req[ 0 ] );
/* Everything OK? */
if( error )
clean_up( "No channel available!" );
/* Check which channel we received: */
channel = (UBYTE) audio_req[ 0 ]->ioa_Request.io_Unit;
if( channel & LEFT0F )
printf( "First left channel!\n" );
if( channel & RIGHT0F )
printf( "First right channel!\n" );
if( channel & RIGHT1F )
printf( "Second right channel!\n" );
if( channel & LEFT1F )
printf( "Second left channel!\n" );
/* Allocate some memory where we can store the waveform we */
/* want to use. Note that it must be Chip memory, and placed */
/* on a word boundary! */
square_wave = (BYTE *) AllocMem( SQUARE_DATA_LENGTH, MEMF_CHIP );
if( !square_wave )
clean_up( "Could not allocate enough memory for the square wave!" );
/* Initialize the waveform: (This is the smallest */
/* waveform you can use, and undouptly the easiest.) */
square_wave[ 0 ] = 127;
square_wave[ 1 ] = -127;
/* Initialize the first requestblock: */
/* Give the request block a pointer to the waveform: */
audio_req[ 0 ]->ioa_Data = square_wave;
/* Set the length of the waveform: */
/* (Must be an even number of bytes.) */
audio_req[ 0 ]->ioa_Length = SQUARE_DATA_LENGTH;
/* Play the waveform 100 times: */
audio_req[ 0 ]->ioa_Cycles = 200;
/* Going to play a tune: */
audio_req[ 0 ]->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.) */
audio_req[ 0 ]->ioa_Request.io_Flags = ADIOF_PERVOL;
/* Medium volume: */
audio_req[ 0 ]->ioa_Volume = 32;
/* Set the period: */
audio_req[ 0 ]->ioa_Period =
PAL_CLOCK / note_frequency[ 0 ] / SQUARE_DATA_LENGTH;
/* Copy the first request block to the secon one: (byte by byte) */
/* Get the start addresses of both request blocks: */
first_ptr = (BYTE *) audio_req[ 0 ];
second_ptr = (BYTE *) audio_req[ 1 ];
/* Copy byte by byte: */
for( loop = 0; loop < sizeof( struct IOAudio ); loop++ )
{
/* Copy: */
*second_ptr = *first_ptr;
/* Next byte: */
first_ptr++;
second_ptr++;
}
/* Tell the user to be prepared: */
printf( "Here comes some notes with no irretating clicking noice!\n" );
/* Start to play the sound with the first request, */
/* and let the second request wait: */
playing = 0;
waiting = 1;
/* Start to play a note: */
BeginIO( audio_req[ playing ] );
/* Set a mark: */
printf( "*" );
/* Play the rest of the octave: */
for( note = 1; note < OCTAVE; note++ )
{
/* Set the period: */
audio_req[ waiting ]->ioa_Period =
PAL_CLOCK / note_frequency[ note ] / SQUARE_DATA_LENGTH;
/* Play another note: (This sound will be put in */
/* a queue, and will first be played when the */
/* other sound has been completed) */
BeginIO( audio_req[ waiting ] );
/* Wait for the previous note to be completed: */
error = WaitIO( audio_req[ playing ] );
/* Set a mark: */
printf( "*" );
/* Was the note successfully played? */
if( error )
{
/* Wait for the other request which is */
/* already in the queue, to be completed: */
WaitIO( audio_req[ playing ] );
/* Quit: */
clean_up( "Error!" );
}
/* Switch: */
if( playing )
{
playing = 0;
waiting = 1;
}
else
{
playing = 1;
waiting = 0;
}
}
/* Wait for the last note to be completed: */
WaitIO( audio_req[ playing ] );
/* 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 )
{
/* Temporary loop variable: */
int loop;
/* If we have a request block and it does not contain */
/* any errors we know that a channel has been allocated */
/* and must be deallocated: */
if( audio_req[ 0 ] && !(audio_req[ 0 ]->ioa_Request.io_Error) )
{
/* Free the channel: */
audio_req[ 0 ]->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( audio_req[ 0 ] );
/* 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: */
if( audio_req[ 0 ] && audio_req[ 0 ]->ioa_Request.io_Device )
CloseDevice( audio_req[ 0 ] );
/* Remove the replyport: */
if( replymp )
DeletePort( replymp);
/* Dealocate the IOAudio structures: */
for( loop = 0; loop < 2; loop++ )
if( audio_req[ loop ] )
DeleteExtIO( audio_req[ loop ], sizeof( struct IOAudio ) );
/* Dealocate the square waveform: */
if( square_wave )
FreeMem( square_wave, SQUARE_DATA_LENGTH );
/* Print the last message: */
printf( "%s\n", text );
/* Quit: */
exit( 0 );
}