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

  1. /***********************************************************/
  2. /*                                                         */
  3. /* Amiga C Encyclopedia (ACE) V3.0      Amiga C Club (ACC) */
  4. /* -------------------------------      ------------------ */
  5. /*                                                         */
  6. /* Book:    ACM Devices                 Amiga C Club       */
  7. /* Chapter: AudioDevice                 Tulevagen 22       */
  8. /* File:    Example5.c                  181 41  LIDINGO    */
  9. /* Author:  Anders Bjerin               SWEDEN             */
  10. /* Date:    92-04-24                                       */
  11. /* Version: 1.00                                           */
  12. /*                                                         */
  13. /*   Copyright 1992, Anders Bjerin - Amiga C Club (ACC)    */
  14. /*                                                         */
  15. /* Registered members may use this program freely in their */
  16. /*     own commercial/noncommercial programs/articles.     */
  17. /*                                                         */
  18. /***********************************************************/
  19.  
  20. /* This example demonstrates how you can play sounds     */
  21. /* in STEREO. First we play a sound in the left channel, */
  22. /* then we switch to the right, and then back again, and */
  23. /* so on...                                              */
  24. /*                                                       */
  25. /* In this example are we reserving the audio channels   */
  26. /* at the same time as we open the audio device. We use  */
  27. /* two audio requests, one for the left channel and the  */
  28. /* other one for the right channel.                      */
  29.  
  30.  
  31.  
  32. #include <exec/types.h>        /* STRPTR         */
  33. #include <exec/memory.h>       /* MEMF_CHIP      */
  34. #include <devices/audio.h>     /* Audio Device   */
  35. #include <math.h>              /* sine() etc...  */
  36.  
  37. /* When you are using mathematical functions like sin(), cos()  */
  38. /* sqrt() etc... you must include the "math.h" header file, or  */
  39. /* the compiler will not know what values the functions are     */
  40. /* going to return. he compiler assumes then that they return   */
  41. /* integers, which is wrong (they return float of double        */
  42. /* values) and this will cause many errors in the calculations. */
  43.  
  44.  
  45.  
  46. /* The audio channels: (Sadly these constants */
  47. /* have not been defined in any header file.) */ 
  48.  
  49. /* Values: */
  50. #define LEFT0B   0
  51. #define RIGHT0B  1
  52. #define RIGHT1B  2
  53. #define LEFT1B   3
  54.  
  55. /* Bit fields: */
  56. #define LEFT0F   (1<<LEFT0B)
  57. #define RIGHT0F  (1<<RIGHT0B)
  58. #define RIGHT1F  (1<<RIGHT1B)
  59. #define LEFT1F   (1<<LEFT1B)
  60.  
  61. /* Sound priorities: */
  62. #define SOUND_UNSTOPPABLE  127
  63. #define SOUND_EMERGENCIES   95
  64. #define SOUND_ATTENTION     85
  65. #define SOUND_SPEECH        75
  66. #define SOUND_INFORMATION   60
  67. #define SOUND_MUSIC          0
  68. #define SOUND_EFFECT       -35
  69. #define SOUND_BACKGROUND   -90
  70. #define SOUND_SILENCE     -128
  71.  
  72. /* The clock constant: */
  73. #define NTSC_CLOCK    3579545 /* American Amigas - 60Hz */
  74. #define PAL_CLOCK     3546895 /* European Amigas - 50Hz */
  75.  
  76. /* Define min/max-volumes: */
  77. #define MAXVOLUME  64
  78. #define MINVOLUME   0
  79.  
  80. /* Some common notes (their frequencies are */
  81. /* defined later on in this program):       */
  82. #define NOTE_A   0
  83. #define NOTE_Ax  1
  84. #define NOTE_B   2
  85. #define NOTE_C   3
  86. #define NOTE_Cx  4
  87. #define NOTE_D   5
  88. #define NOTE_Dx  6
  89. #define NOTE_E   7
  90. #define NOTE_F   8
  91. #define NOTE_Fx  9
  92. #define NOTE_G  10
  93. #define NOTE_Gx 11
  94.  
  95. /* An octave consists of 12 notes: */
  96. #define OCTAVE  12
  97.  
  98. /* Our sine wave will contain 16 values: */
  99. #define SINE_DATA_LENGTH 16
  100.  
  101.  
  102.  
  103. /* Declare a pointer to our reply port: */
  104. struct MsgPort *replymp = NULL;
  105.  
  106. /* Declare two audio request block pointers. One for the */
  107. /* left channel, and the other on for the right channel: */
  108. struct IOAudio *left_audio_req = NULL;
  109. struct IOAudio *right_audio_req = NULL;
  110.  
  111.  
  112.  
  113. /* Two lists of preffered channels. On for the */
  114. /* left channels, and the other one for right  */
  115. /* channels:                                   */
  116.  
  117. UBYTE left_allocation_array[] = { LEFT0F, LEFT1F };
  118. UBYTE right_allocation_array[] = { RIGHT0F, RIGHT1F };
  119.  
  120.  
  121.  
  122. /* The notes (defined above) frequencies. These frequencies      */
  123. /* represent notes which are one octave higher than the middle   */
  124. /* octave on a piano. To change octave, simply double/half these */
  125. /* values. Ex, A=880, one octave lower A=440, one octave higher  */
  126. /* A=1760.                                                       */
  127. /*                                                               */
  128. /* Instead of changing the frequencies you can of course double  */
  129. /* or half the amount of samled waveform data. If you double the */
  130. /* amount of sampled waveformdata you will move down one octave  */
  131. /* and vice versa. In this example when we caluculate the period */
  132. /* value we use the length of the vaweform as one parameter.     */
  133. /* Therefore, if you change the length of the waveform the same  */
  134. /* frequencies will be used.                                     */ 
  135.  
  136. UWORD note_frequency[ OCTAVE ]=
  137. {
  138.    880.0, /* A  */
  139.    932.3, /* A# */
  140.    987.8, /* B  */
  141.   1046.5, /* C  */
  142.   1108.7, /* C# */
  143.   1174.7, /* D  */
  144.   1244.5, /* D# */
  145.   1318.5, /* E  */
  146.   1396.9, /* F  */
  147.   1480.0, /* F# */
  148.   1568.0, /* G  */
  149.   1661.2  /* G# */
  150. };
  151.  
  152.  
  153.  
  154. /* Declare a pointer to the sine waveform: */
  155. BYTE *sine_wave = NULL;
  156.  
  157.  
  158.  
  159. /* Declare our functions: */
  160. void main();
  161. void clean_up( STRPTR text );
  162.  
  163.  
  164.  
  165. void main()
  166. {
  167.   /* Error messages: */
  168.   BYTE error;
  169.  
  170.   /* Used in the loops: */
  171.   int loop;
  172.  
  173.   /* Current note played: */
  174.   int note;
  175.  
  176.  
  177.  
  178.   /* Get a reply port: (No name, priority 0) */
  179.   replymp = (struct MsgPort *)
  180.     CreatePort( NULL, 0 );
  181.   if( !replymp )
  182.     clean_up( "Could not create the reply port!" );
  183.  
  184.  
  185.  
  186.   /* We are going to use two audio requests, one for each channel. */
  187.   /* Since both requests must be linked to the audio device we     */
  188.   /* "open" the device twice, one for each request. We could of    */
  189.   /* course open one audio channel at the same time as we open the */
  190.   /* audio device. We would then copy the whole request to the     */
  191.   /* other one. This is necessary since the first request has been */
  192.   /* initilized to fit the audio device, and if you want to use    */
  193.   /* the ther request as well, it must have the same values. Once  */
  194.   /* we have copied the request we then have to reserve the other  */
  195.   /* channel by using the ADCMD_ALLOCATE command. As you surely    */
  196.   /* understand, it is much easier to "open" the audio device      */
  197.   /* twice. (Just remember, before your program terminates, to     */
  198.   /* close it for both requests!)                                  */
  199.  
  200.  
  201.  
  202.   /* This time will we try to reserve a sound    */
  203.   /* channel at the same time when we open the   */
  204.   /* audio device. To do this we must:           */
  205.   /*   1. Set the sound priority.                */
  206.   /*   2. Give it an array of desired channels.  */
  207.   /*   3. Set the lenght of the array.           */
  208.   /*                                             */
  209.   /* We do not have to set the ADCMD_ALLOCATE    */
  210.   /* flag since if the io_Length is not zero     */
  211.   /* the device will automatically assume that   */
  212.   /* we whant to reserve a sound channel. The    */
  213.   /* ADIOF_NOWAIT flag is automatically set when */
  214.   /* you open the audio device and reserve a     */
  215.   /* sound channel at the same time.             */
  216.  
  217.   /* LEFT CHANNEL */
  218.  
  219.   /* Allocate and preinitialize the left audio request block: */
  220.   left_audio_req = (struct IOAudio *)
  221.     CreateExtIO( replymp, sizeof( struct IOAudio ) );
  222.   if( !left_audio_req )
  223.     clean_up( "Not enough memory for the left IOAudio structure!" );
  224.  
  225.   /* Set sound priority: (We are going to play music.) */
  226.   left_audio_req->ioa_Request.io_Message.mn_Node.ln_Pri = SOUND_MUSIC;
  227.  
  228.   /* Give the request block a pointer to our allocation array: */
  229.   left_audio_req->ioa_Data = left_allocation_array;
  230.   
  231.   /* Set the length of the allocation array: */
  232.   left_audio_req->ioa_Length = sizeof( left_allocation_array );
  233.          
  234.   /* Open the Audio Device and allocate a left sound */
  235.   /* channel at the same time:                       */
  236.   error = OpenDevice( AUDIONAME, 0, left_audio_req, 0 );
  237.   if( error )
  238.   {
  239.     /* Clear the "io_Device" flag since we have not opened the device: */
  240.     left_audio_req->ioa_Request.io_Device = NULL;
  241.  
  242.     /* Quit: */
  243.     clean_up( "Could not open the Audio Device for the left channel!" );
  244.   }
  245.  
  246.  
  247.   /* RIGHT CHANNEL */
  248.  
  249.   /* Allocate and preinitialize the right audio request block: */
  250.   right_audio_req = (struct IOAudio *)
  251.     CreateExtIO( replymp, sizeof( struct IOAudio ) );
  252.   if( !right_audio_req )
  253.     clean_up( "Not enough memory for the right IOAudio structure!" );
  254.  
  255.   /* Set sound priority: (We are going to play music.) */
  256.   right_audio_req->ioa_Request.io_Message.mn_Node.ln_Pri = SOUND_MUSIC;
  257.  
  258.   /* Give the request block a pointer to our allocation array: */
  259.   right_audio_req->ioa_Data = right_allocation_array;
  260.   
  261.   /* Set the length of the allocation array: */
  262.   right_audio_req->ioa_Length = sizeof( right_allocation_array );
  263.          
  264.   /* Open the Audio Device and allocate a right sound */
  265.   /* channel at the same time:                       */
  266.   error = OpenDevice( AUDIONAME, 0, right_audio_req, 0 );
  267.   if( error )
  268.   {
  269.     /* Clear the "io_Device" flag since we have not opened the device: */
  270.     right_audio_req->ioa_Request.io_Device = NULL;
  271.  
  272.     /* Quit: */
  273.     clean_up( "Could not open the Audio Device for the right channel!" );
  274.   }
  275.  
  276.  
  277.   /* Allocate some chip memory were we can store the sine wave: */
  278.   /* (All memory allocated by AllocMem() will alwyas start on a */
  279.   /* word boundary.)                                            */
  280.   sine_wave = (BYTE *) AllocMem( SINE_DATA_LENGTH, MEMF_CHIP );
  281.  
  282.   /* Have we got the memory? */
  283.   if( !sine_wave )
  284.     clean_up( "Not enough memory for the sine wave!" );  
  285.  
  286.   /* Initialize the sine waveform: */
  287.   for( loop = 0; loop < SINE_DATA_LENGTH; loop++ )
  288.     sine_wave[ loop ] =
  289.       127 * sin( loop * 2 * PI / SINE_DATA_LENGTH );
  290.  
  291.  
  292.  
  293.   /* Prepare to play sound with the left channel: */
  294.  
  295.   /* Give the request block a pointer to the waveform: */
  296.   left_audio_req->ioa_Data = sine_wave;
  297.  
  298.   /* Set the length of the waveform:    */
  299.   /* (Must be an even number of bytes.) */
  300.   left_audio_req->ioa_Length = SINE_DATA_LENGTH;
  301.  
  302.   /* Play the sound 400 times: */
  303.   left_audio_req->ioa_Cycles = 400;
  304.  
  305.   /* Going to play a tune: */
  306.   left_audio_req->ioa_Request.io_Command = CMD_WRITE;
  307.  
  308.   /* Use the volume and period fields of the request block: */
  309.   /* (If we do not set this flag the previous volume and    */
  310.   /* period values will be used.)                           */
  311.   left_audio_req->ioa_Request.io_Flags = ADIOF_PERVOL;
  312.  
  313.   /* Medium volume: */
  314.   left_audio_req->ioa_Volume = 32;
  315.  
  316.  
  317.  
  318.   /* Prepare to play sound with the right channel: */
  319.  
  320.   /* Give the request block a pointer to the waveform: */
  321.   right_audio_req->ioa_Data = sine_wave;
  322.  
  323.   /* Set the length of the waveform:    */
  324.   /* (Must be an even number of bytes.) */
  325.   right_audio_req->ioa_Length = SINE_DATA_LENGTH;
  326.  
  327.   /* Play the sound 400 times: */
  328.   right_audio_req->ioa_Cycles = 400;
  329.  
  330.   /* Going to play a tune: */
  331.   right_audio_req->ioa_Request.io_Command = CMD_WRITE;
  332.  
  333.   /* Use the volume and period fields of the request block: */
  334.   /* (If we do not set this flag the previous volume and    */
  335.   /* period values will be used.)                           */
  336.   right_audio_req->ioa_Request.io_Flags = ADIOF_PERVOL;
  337.  
  338.   /* Medium volume: */
  339.   right_audio_req->ioa_Volume = 32;
  340.  
  341.  
  342.  
  343.   /* Tell the user to be prepared: */
  344.   printf( "Now some STEREO sound!\n" );
  345.  
  346.   /* Play one octave: */
  347.   for( note=0; note < OCTAVE; note++ )
  348.   {
  349.     /* Left channel: */
  350.  
  351.     /* Set the period: */
  352.     left_audio_req->ioa_Period =
  353.       PAL_CLOCK / note_frequency[ note ] / SINE_DATA_LENGTH;
  354.  
  355.     /* Set a mark: */
  356.     printf( "Left\n" );
  357.  
  358.     /* Start to play a note: */
  359.     BeginIO( left_audio_req );
  360.     
  361.     /* Wait for the note to be completed: */
  362.     error = WaitIO( left_audio_req );
  363.  
  364.     /* Was the note successfully played? */
  365.     if( error )
  366.       clean_up( "Error while playing on the left channel!" );
  367.  
  368.  
  369.     /* Right channel: */
  370.  
  371.     /* Set the period: */
  372.     right_audio_req->ioa_Period =
  373.       PAL_CLOCK / note_frequency[ note ] / SINE_DATA_LENGTH;
  374.  
  375.     /* Set a mark: */
  376.     printf( "Right\n", right_audio_req->ioa_Period );
  377.  
  378.     /* Start to play a note: */
  379.     BeginIO( right_audio_req );
  380.     
  381.     /* Wait for the note to be completed: */
  382.     error = WaitIO( right_audio_req );
  383.  
  384.     /* Was the note successfully played? */
  385.     if( error )
  386.       clean_up( "Error while playing on the right channel!" );
  387.   }
  388.  
  389.  
  390.  
  391.  
  392.   /* Clean up and quit: */
  393.   clean_up( "The End!" );
  394. }
  395.  
  396.  
  397.  
  398. /* Close and return everything that has been */
  399. /* opened and allocated before we quit:      */
  400.  
  401. void clean_up( STRPTR text )
  402. {
  403.   /* If we have a request block and it does not contain   */
  404.   /* any errors we know that a channel has been allocated */
  405.   /* (and is not stolen) and must be deallocated:         */
  406.  
  407.   /* Free the left channel: */
  408.   if( left_audio_req && !(left_audio_req->ioa_Request.io_Error) )
  409.   {
  410.     /* Free the channel: */
  411.     left_audio_req->ioa_Request.io_Command = ADCMD_FREE;
  412.  
  413.     /* We are allowed to use the function DoIO() for */
  414.     /* this request since it will not change any     */
  415.     /* values that are vital for us:                 */ 
  416.     DoIO( left_audio_req );
  417.     
  418.     /* The lock is automatically unlocked when we */
  419.     /* free the audio channel.                    */
  420.   }
  421.  
  422.  
  423.   /* Free the right channel: */
  424.   if( right_audio_req && !(right_audio_req->ioa_Request.io_Error) )
  425.   {
  426.     /* Free the channel: */
  427.     right_audio_req->ioa_Request.io_Command = ADCMD_FREE;
  428.  
  429.     /* We are allowed to use the function DoIO() for */
  430.     /* this request since it will not change any     */
  431.     /* values that are vital for us:                 */ 
  432.     DoIO( right_audio_req );
  433.     
  434.     /* The lock is automatically unlocked when we */
  435.     /* free the audio channel.                    */
  436.   }
  437.  
  438.  
  439.  
  440.   /* Empty the reply port: */
  441.   while( GetMsg( replymp ) )
  442.     printf( "Collected a message at the reply port.\n" );
  443.   
  444.   /* If we have a request block and the "io_Device" field  */
  445.   /* is not zero, we know that the device has successfully */
  446.   /* been opened and must now be closed.                   */ 
  447.  
  448.   /* Close the audio device for the left channel: */
  449.   if( left_audio_req && left_audio_req->ioa_Request.io_Device )
  450.     CloseDevice( left_audio_req );
  451.  
  452.   /* Close the audio device for the right channel: */
  453.   if( right_audio_req && right_audio_req->ioa_Request.io_Device )
  454.     CloseDevice( right_audio_req );
  455.  
  456.  
  457.  
  458.   /* Remove the replyport: */
  459.   if( replymp )
  460.     DeletePort( replymp);
  461.  
  462.   /* Dealocate the left IOAudio structure: */
  463.   if( left_audio_req )
  464.     DeleteExtIO( left_audio_req, sizeof( struct IOAudio ) );
  465.  
  466.   /* Dealocate the right IOAudio structure: */
  467.   if( right_audio_req )
  468.     DeleteExtIO( right_audio_req, sizeof( struct IOAudio ) );
  469.  
  470.   /* Dealocate the sine waveform: */
  471.   if( sine_wave )
  472.     FreeMem( sine_wave, SINE_DATA_LENGTH );
  473.  
  474.   /* Print the last message: */
  475.   printf( "%s\n", text );
  476.  
  477.   /* Quit: */
  478.   exit( 0 );
  479. }
  480.  
  481.  
  482.