home *** CD-ROM | disk | FTP | other *** search
/ World of A1200 / World_Of_A1200.iso / datafiles / text / c_manual / devices / audiodevice / example2.c < prev    next >
C/C++ Source or Header  |  1995-02-27  |  13KB  |  455 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:    Example2.c                  181 41  LIDINGO    */
  9. /* Author:  Anders Bjerin               SWEDEN             */
  10. /* Date:    92-04-21                                       */
  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 program is very similar to the previous example,  */
  21. /* but this time are we using double buffered sounds, and */
  22. /* there will therefore not be any annoying "clicks"      */
  23. /* between the notes.                                     */
  24. /*                                                        */
  25. /* The technique with double buffered sound is that while */
  26. /* the first sound is played the second sound is already  */
  27. /* sent to the audio device. When the first sound         */
  28. /* terminates the second sound can immediately start      */
  29. /* without any delay. While the second sound is being     */
  30. /* played the first sound is prepared and sent and so     */
  31. /* on... Because there is never any delay between the     */
  32. /* sounds there will never be any annoying clicks.        */
  33.  
  34.  
  35. #include <exec/types.h>        /* STRPTR         */
  36. #include <exec/memory.h>       /* MEMF_CHIP      */
  37. #include <devices/audio.h>     /* Audio Device   */
  38.  
  39.  
  40.  
  41. /* The audio channels: (Sadly these constants */
  42. /* have not been defined in any header file.) */ 
  43.  
  44. /* Values: */
  45. #define LEFT0B   0
  46. #define RIGHT0B  1
  47. #define RIGHT1B  2
  48. #define LEFT1B   3
  49.  
  50. /* Bit fields: */
  51. #define LEFT0F   (1<<LEFT0B)
  52. #define RIGHT0F  (1<<RIGHT0B)
  53. #define RIGHT1F  (1<<RIGHT1B)
  54. #define LEFT1F   (1<<LEFT1B)
  55.  
  56. /* Sound priorities: */
  57. #define SOUND_UNSTOPPABLE  127
  58. #define SOUND_EMERGENCIES   95
  59. #define SOUND_ATTENTION     85
  60. #define SOUND_SPEECH        75
  61. #define SOUND_INFORMATION   60
  62. #define SOUND_MUSIC          0
  63. #define SOUND_EFFECT       -35
  64. #define SOUND_BACKGROUND   -90
  65. #define SOUND_SILENCE     -128
  66.  
  67. /* The clock constant: */
  68. #define NTSC_CLOCK    3579545 /* American Amigas - 60Hz */
  69. #define PAL_CLOCK     3546895 /* European Amigas - 50Hz */
  70.  
  71.  
  72.  
  73. /* Some common notes (their frequencies are */
  74. /* defined later on in this program):       */
  75. #define NOTE_A   0
  76. #define NOTE_Ax  1
  77. #define NOTE_B   2
  78. #define NOTE_C   3
  79. #define NOTE_Cx  4
  80. #define NOTE_D   5
  81. #define NOTE_Dx  6
  82. #define NOTE_E   7
  83. #define NOTE_F   8
  84. #define NOTE_Fx  9
  85. #define NOTE_G  10
  86. #define NOTE_Gx 11
  87.  
  88. /* An octave consists of 12 notes: */
  89. #define OCTAVE  12
  90.  
  91. /* Define min/max-volumes: */
  92. #define MAXVOLUME  64
  93. #define MINVOLUME   0
  94.  
  95. /* Our square waveform data consists of two samples: */
  96. /* (Waveform data must alwyas be an even number of   */
  97. /* byte long.)                                       */
  98. #define SQUARE_DATA_LENGTH       2
  99.  
  100.  
  101.  
  102. /* Declare a pointer to our reply port: */
  103. struct MsgPort *replymp = NULL;
  104.  
  105. /* Declare two audio request pointers: (Since we are going */
  106. /* to use two sound requests at the same time we need two  */
  107. /* audio requests.)                                        */
  108. struct IOAudio *audio_req[ 2 ];
  109.  
  110.  
  111.  
  112. /* Our list of preffered channel combinations: */
  113. /* (First we try to reserve the first channel, */
  114. /* then the second, third and finally fourth   */
  115. /* audio channel.)                             */
  116. UBYTE allocation_array[]=
  117. {
  118.   LEFT0F,
  119.   RIGHT0F,
  120.   RIGHT1F,
  121.   LEFT1F
  122. };
  123.  
  124. /* Declare a pointer to some soundwave data: */
  125. BYTE *square_wave = NULL;
  126.  
  127.  
  128. /* The notes (defined above) frequencies. These frequencies      */
  129. /* represent notes which are one octave higher than the middle   */
  130. /* octave on a piano. To change octave, simply double/half these */
  131. /* values. Ex, A=880, one octave lower A=440, one octave higher  */
  132. /* A=1760.                                                       */
  133. /*                                                               */
  134. /* Instead of changing the frequencies you can of course double  */
  135. /* or half the amount of samled waveform data. If you double the */
  136. /* amount of sampled waveformdata you will move down one octave  */
  137. /* and vice versa. In this example when we caluculate the period */
  138. /* value we use the length of the vaweform as one parameter.     */
  139. /* Therefore, if you change the length of the waveform the same  */
  140. /* frequencies will be used.                                     */ 
  141.  
  142. UWORD note_frequency[ OCTAVE ]=
  143. {
  144.    880.0, /* A  */
  145.    932.3, /* A# */
  146.    987.8, /* B  */
  147.   1046.5, /* C  */
  148.   1108.7, /* C# */
  149.   1174.7, /* D  */
  150.   1244.5, /* D# */
  151.   1318.5, /* E  */
  152.   1396.9, /* F  */
  153.   1480.0, /* F# */
  154.   1568.0, /* G  */
  155.   1661.2  /* G# */
  156. };
  157.  
  158.  
  159.  
  160. /* Declare our functions: */
  161. void main();
  162. void clean_up( STRPTR text );
  163.  
  164.  
  165.  
  166. void main()
  167. {
  168.   /* Error messages: */
  169.   BYTE error;
  170.  
  171.   /* The channel we have received: */
  172.   UBYTE channel;
  173.  
  174.   /* Used in the loops: */
  175.   int note, loop;
  176.  
  177.   /* Which request is being played and which */
  178.   /* is waiting to be played:                */
  179.   int playing;
  180.   int waiting;
  181.  
  182.   /* Used when we copy the first request */
  183.   /* block to the second one:            */
  184.   BYTE *first_ptr;
  185.   BYTE *second_ptr;
  186.  
  187.  
  188.  
  189.   /* Get a reply port: (No name, priority 0) */
  190.   replymp = (struct MsgPort *)
  191.     CreatePort( NULL, 0 );
  192.   if( !replymp )
  193.     clean_up( "Could not create the reply port!" );
  194.  
  195.  
  196.  
  197.   /* Allocate and preinitialize two audio request blocks: */
  198.   for( loop = 0; loop < 2; loop++ )
  199.   {
  200.     audio_req[ loop ] = (struct IOAudio *)
  201.       CreateExtIO( replymp, sizeof( struct IOAudio ) );
  202.     if( !audio_req[ loop ] )
  203.       clean_up( "Not enough memory for the IOAudio structure!" );
  204.   }
  205.  
  206.  
  207.   /* Open the Audio Device: (We will try to   */
  208.   /* reserve a sound channel later on. We use */
  209.   /* the first request block, and we will     */
  210.   /* later copy everything to the second      */
  211.   /* request block.                           */
  212.   error = OpenDevice( AUDIONAME, 0, audio_req[ 0 ], 0 );
  213.   if( error )
  214.   {
  215.     /* Clear the "io_Device" flag since we have not opened the device: */
  216.     audio_req[ 0 ]->ioa_Request.io_Device = NULL;
  217.   
  218.     /* Quit: */
  219.     clean_up( "Could not open the Audio Device!" );
  220.   }
  221.  
  222.  
  223.  
  224.   /* Reserve a channel with help of the first request block: */
  225.  
  226.   /* Try to reserve a channel: */
  227.   audio_req[ 0 ]->ioa_Request.io_Command = ADCMD_ALLOCATE;
  228.  
  229.   /* Set sound priority: (We are going to play some music.) */
  230.   audio_req[ 0 ]->ioa_Request.io_Message.mn_Node.ln_Pri = SOUND_MUSIC;
  231.  
  232.   /* Do not wait for any channels to be free, */
  233.   /* return immediately, successfully or not: */
  234.   audio_req[ 0 ]->ioa_Request.io_Flags = ADIOF_NOWAIT;
  235.  
  236.   /* Give the request block a pointer to our allocation array: */
  237.   audio_req[ 0 ]->ioa_Data = allocation_array;
  238.   
  239.   /* Set the length of the allocation array: */
  240.   audio_req[ 0 ]->ioa_Length = sizeof( allocation_array );
  241.          
  242.   /* Do our request: */
  243.   BeginIO( audio_req[ 0 ] );
  244.  
  245.   /* Wait for the request to be completed: */
  246.   error = WaitIO( audio_req[ 0 ] );
  247.  
  248.   /* Everything OK? */
  249.   if( error )
  250.     clean_up( "No channel available!" );
  251.  
  252.  
  253.  
  254.   /* Check which channel we received: */
  255.   channel = (UBYTE) audio_req[ 0 ]->ioa_Request.io_Unit;
  256.  
  257.   if( channel & LEFT0F )
  258.     printf( "First left channel!\n" );
  259.  
  260.   if( channel & RIGHT0F )
  261.     printf( "First right channel!\n" );
  262.  
  263.   if( channel & RIGHT1F )
  264.     printf( "Second right channel!\n" );
  265.  
  266.   if( channel & LEFT1F )
  267.     printf( "Second left channel!\n" );
  268.  
  269.  
  270.  
  271.   /* Allocate some memory where we can store the waveform we   */
  272.   /* want to use. Note that it must be Chip memory, and placed */
  273.   /* on a word boundary!                                       */
  274.   square_wave = (BYTE *) AllocMem( SQUARE_DATA_LENGTH, MEMF_CHIP );
  275.   if( !square_wave )
  276.     clean_up( "Could not allocate enough memory for the square wave!" );  
  277.  
  278.   /* Initialize the waveform: (This is the smallest    */
  279.   /* waveform you can use, and undouptly the easiest.) */
  280.   square_wave[ 0 ] = 127;
  281.   square_wave[ 1 ] = -127;
  282.  
  283.  
  284.  
  285.   /* Initialize the first requestblock: */
  286.  
  287.   /* Give the request block a pointer to the waveform: */
  288.   audio_req[ 0 ]->ioa_Data = square_wave;
  289.  
  290.   /* Set the length of the waveform:    */
  291.   /* (Must be an even number of bytes.) */
  292.   audio_req[ 0 ]->ioa_Length = SQUARE_DATA_LENGTH;
  293.  
  294.   /* Play the waveform 100 times: */
  295.   audio_req[ 0 ]->ioa_Cycles = 200;
  296.  
  297.   /* Going to play a tune: */
  298.   audio_req[ 0 ]->ioa_Request.io_Command = CMD_WRITE;
  299.  
  300.   /* Use the volume and period fields of the request block: */
  301.   /* (If we do not set this flag the previous volume and    */
  302.   /* period values will be used.)                           */
  303.   audio_req[ 0 ]->ioa_Request.io_Flags = ADIOF_PERVOL;
  304.  
  305.   /* Medium volume: */
  306.   audio_req[ 0 ]->ioa_Volume = 32;
  307.  
  308.   /* Set the period: */
  309.   audio_req[ 0 ]->ioa_Period =
  310.     PAL_CLOCK / note_frequency[ 0 ] / SQUARE_DATA_LENGTH;
  311.  
  312.  
  313.  
  314.   /* Copy the first request block to the secon one: (byte by byte) */
  315.  
  316.   /* Get the start addresses of both request blocks: */
  317.   first_ptr = (BYTE *) audio_req[ 0 ];
  318.   second_ptr = (BYTE *) audio_req[ 1 ];
  319.  
  320.   /* Copy byte by byte: */
  321.   for( loop = 0; loop < sizeof( struct IOAudio ); loop++ )
  322.   {
  323.     /* Copy: */
  324.     *second_ptr = *first_ptr;
  325.     
  326.     /* Next byte: */
  327.     first_ptr++;
  328.     second_ptr++;
  329.   }
  330.  
  331.  
  332.  
  333.   /* Tell the user to be prepared: */
  334.   printf( "Here comes some notes with no irretating clicking noice!\n" );
  335.  
  336.   /* Start to play the sound with the first request, */
  337.   /* and let the second request wait:                */
  338.   playing = 0;
  339.   waiting = 1;
  340.  
  341.   /* Start to play a note: */
  342.   BeginIO( audio_req[ playing ] );
  343.  
  344.   /* Set a mark: */
  345.   printf( "*" );
  346.  
  347.   /* Play the rest of the octave: */
  348.   for( note = 1; note < OCTAVE; note++ )
  349.   {
  350.     /* Set the period: */
  351.     audio_req[ waiting ]->ioa_Period =
  352.       PAL_CLOCK / note_frequency[ note ] / SQUARE_DATA_LENGTH;
  353.  
  354.     /* Play another note: (This sound will be put in */
  355.     /* a queue, and will first be played when the    */
  356.     /* other sound has been completed)               */
  357.     BeginIO( audio_req[ waiting ] );
  358.  
  359.     /* Wait for the previous note to be completed: */
  360.     error = WaitIO( audio_req[ playing ] );
  361.  
  362.     /* Set a mark: */
  363.     printf( "*" );
  364.  
  365.     /* Was the note successfully played? */
  366.     if( error )
  367.     {
  368.       /* Wait for the other request which is    */
  369.       /* already in the queue, to be completed: */
  370.       WaitIO( audio_req[ playing ] );
  371.  
  372.       /* Quit: */
  373.       clean_up( "Error!" );
  374.     }
  375.  
  376.     /* Switch: */
  377.     if( playing )
  378.     {
  379.       playing = 0;
  380.       waiting = 1;
  381.     }
  382.     else
  383.     {
  384.       playing = 1;
  385.       waiting = 0;
  386.     }
  387.   }
  388.  
  389.   /* Wait for the last note to be completed: */
  390.   WaitIO( audio_req[ playing ] );
  391.  
  392.  
  393.  
  394.   /* Clean up and quit: */
  395.   clean_up( "The End!" );
  396. }
  397.  
  398.  
  399.  
  400. /* Close and return everything that has been */
  401. /* opened and allocated before we quit:      */
  402.  
  403. void clean_up( STRPTR text )
  404. {
  405.   /* Temporary loop variable: */
  406.   int loop;
  407.  
  408.  
  409.  
  410.   /* If we have a request block and it does not contain   */
  411.   /* any errors we know that a channel has been allocated */
  412.   /* and must be deallocated:                             */
  413.   if( audio_req[ 0 ] && !(audio_req[ 0 ]->ioa_Request.io_Error) )
  414.   {
  415.     /* Free the channel: */
  416.     audio_req[ 0 ]->ioa_Request.io_Command = ADCMD_FREE;
  417.  
  418.     /* We are allowed to use the function DoIO() for */
  419.     /* this request since it will not change any     */
  420.     /* values that are vital for us:                 */ 
  421.     DoIO( audio_req[ 0 ] );
  422.     
  423.     /* The lock is automatically unlocked when we */
  424.     /* free the audio channel.                    */
  425.   }
  426.  
  427.   /* Empty the reply port: */
  428.   while( GetMsg( replymp ) )
  429.     printf( "Collected a message at the reply port.\n" );
  430.   
  431.   /* If we have a request block and the "io_Device" field  */
  432.   /* is not zero, we know that the device has successfully */
  433.   /* been opened and must now be closed:                   */ 
  434.   if( audio_req[ 0 ] && audio_req[ 0 ]->ioa_Request.io_Device )
  435.     CloseDevice( audio_req[ 0 ] );
  436.  
  437.   /* Remove the replyport: */
  438.   if( replymp )
  439.     DeletePort( replymp);
  440.  
  441.   /* Dealocate the IOAudio structures: */
  442.   for( loop = 0; loop < 2; loop++ )
  443.     if( audio_req[ loop ] )
  444.       DeleteExtIO( audio_req[ loop ], sizeof( struct IOAudio ) );
  445.  
  446.   /* Dealocate the square waveform: */
  447.   if( square_wave )
  448.     FreeMem( square_wave, SQUARE_DATA_LENGTH );
  449.  
  450.   /* Print the last message: */
  451.   printf( "%s\n", text );
  452.  
  453.   /* Quit: */
  454.   exit( 0 );
  455. }