home *** CD-ROM | disk | FTP | other *** search
/ World of A1200 / World_Of_A1200.iso / datafiles / text / c_manual / devices / audiodevice / example6.c < prev    next >
C/C++ Source or Header  |  1995-02-27  |  15KB  |  530 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:    Example6.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 program will play some notes (A to G#) with help    */
  21. /* of the Audio Device. It will use as many audio channels  */
  22. /* as possible, and we are modifying the hardware registers */
  23. /* directly instead of using the special Audio Device       */
  24. /* commands.                                                */ 
  25. /*                                                          */
  26. /* You are allowed to use the hardware registers directly   */
  27. /* if you make sure that no other task can steel them from  */
  28. /* you before you have cleared all necessary registers.     */
  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 <hardware/custom.h>   /* struct Custom  */
  36. #include <hardware/dmabits.h>  /* DMAF_SETCLR    */
  37.  
  38.  
  39.  
  40. /* The audio channels: (Sadly these constants */
  41. /* have not been defined in any header file.) */ 
  42.  
  43. /* Values: */
  44. #define LEFT0B   0
  45. #define RIGHT0B  1
  46. #define RIGHT1B  2
  47. #define LEFT1B   3
  48.  
  49. /* Bit fields: */
  50. #define LEFT0F   (1<<LEFT0B)
  51. #define RIGHT0F  (1<<RIGHT0B)
  52. #define RIGHT1F  (1<<RIGHT1B)
  53. #define LEFT1F   (1<<LEFT1B)
  54.  
  55. /* Sound priorities: */
  56. #define SOUND_UNSTOPPABLE  127
  57. #define SOUND_EMERGENCIES   95
  58. #define SOUND_ATTENTION     85
  59. #define SOUND_SPEECH        75
  60. #define SOUND_INFORMATION   60
  61. #define SOUND_MUSIC          0
  62. #define SOUND_EFFECT       -35
  63. #define SOUND_BACKGROUND   -90
  64. #define SOUND_SILENCE     -128
  65.  
  66. /* The clock constant: */
  67. #define NTSC_CLOCK    3579545 /* American Amigas - 60Hz */
  68. #define PAL_CLOCK     3546895 /* European Amigas - 50Hz */
  69.  
  70. /* Some common notes (their frequencies are */
  71. /* defined later on in this program):       */
  72. #define NOTE_A   0
  73. #define NOTE_Ax  1
  74. #define NOTE_B   2
  75. #define NOTE_C   3
  76. #define NOTE_Cx  4
  77. #define NOTE_D   5
  78. #define NOTE_Dx  6
  79. #define NOTE_E   7
  80. #define NOTE_F   8
  81. #define NOTE_Fx  9
  82. #define NOTE_G  10
  83. #define NOTE_Gx 11
  84.  
  85. /* An octave consists of 12 notes: */
  86. #define OCTAVE  12
  87.  
  88. /* Define min/max-volumes: */
  89. #define MAXVOLUME  64
  90. #define MINVOLUME   0
  91.  
  92. /* Our square waveform data consists of two samples: */
  93. /* (Waveform data must alwyas be an even number of   */
  94. /* byte long.)                                       */
  95. #define SQUARE_DATA_LENGTH       2
  96.  
  97. /* Timer units (50 units / second): */
  98. #define SECONDS *50
  99.  
  100.  
  101.  
  102. /* Declare a pointer to our reply port: */
  103. struct MsgPort *replymp = NULL;
  104.  
  105. /* Declare a pointer to our audio request block: */
  106. struct IOAudio *audio_req = NULL;
  107.  
  108. /* Declare a pointer to our lock: */
  109. struct IOAudio *audio_lock = NULL;
  110.  
  111.  
  112.  
  113. /* Our list of preffered channel combinations: */
  114. /* (We want as many channels as possible. The  */
  115. /* way I write it may look a bit strange, but  */
  116. /* it is actually easier to understand this    */
  117. /* code, than if we had removed all spaces.)   */
  118.  
  119. UBYTE desired_channels[]=
  120. {
  121.   LEFT0F | RIGHT0F | RIGHT1F | LEFT1F,
  122.   LEFT0F | RIGHT0F | RIGHT1F         ,
  123.   LEFT0F | RIGHT0F           | LEFT1F,
  124.   LEFT0F | RIGHT0F                   ,
  125.   LEFT0F           | RIGHT1F | LEFT1F,
  126.   LEFT0F           | RIGHT1F         ,
  127.   LEFT0F                     | LEFT1F,
  128.   LEFT0F                             ,
  129.            RIGHT0F | RIGHT1F | LEFT1F,
  130.            RIGHT0F | RIGHT1F         ,
  131.            RIGHT0F           | LEFT1F,
  132.            RIGHT0F                   ,
  133.                      RIGHT1F | LEFT1F,
  134.                      RIGHT1F         ,
  135.                                LEFT1F,
  136. };
  137.  
  138.  
  139.  
  140. /* Declare a pointer to some soundwave data: */
  141. BYTE *square_wave = NULL;
  142.  
  143.  
  144.  
  145. /* The notes (defined above) frequencies. These frequencies      */
  146. /* represent notes which are one octave higher than the middle   */
  147. /* octave on a piano. To change octave, simply double/half these */
  148. /* values. Ex, A=880, one octave lower A=440, one octave higher  */
  149. /* A=1760.                                                       */
  150. /*                                                               */
  151. /* Instead of changing the frequencies you can of course double  */
  152. /* or half the amount of samled waveform data. If you double the */
  153. /* amount of sampled waveformdata you will move down one octave  */
  154. /* and vice versa. In this example when we caluculate the period */
  155. /* value we use the length of the vaweform as one parameter.     */
  156. /* Therefore, if you change the length of the waveform the same  */
  157. /* frequencies will be used.                                     */ 
  158.  
  159. UWORD note_frequency[ OCTAVE ]=
  160. {
  161.    880.0, /* A  */
  162.    932.3, /* A# */
  163.    987.8, /* B  */
  164.   1046.5, /* C  */
  165.   1108.7, /* C# */
  166.   1174.7, /* D  */
  167.   1244.5, /* D# */
  168.   1318.5, /* E  */
  169.   1396.9, /* F  */
  170.   1480.0, /* F# */
  171.   1568.0, /* G  */
  172.   1661.2  /* G# */
  173. };
  174.  
  175.  
  176.  
  177. /* These structure are defined in the headerfile "hardware/custom.h" */
  178. /* and are automatically connected to the hardware registers. We do  */
  179. /* therefore not need to initialize them.                            */
  180.  
  181. extern UWORD far dmacon;            /* DMA control     */
  182. extern struct AudChannel far aud[]; /* Audio channels. */
  183.  
  184. /* Since the hardware data most certainly will not be within reach  */
  185. /* for normal (small) pointers, they must both be declared as far.  */
  186.  
  187.  
  188.  
  189. /* Declare our functions: */
  190. void main();
  191. void clean_up( STRPTR text );
  192.  
  193.  
  194.  
  195. void main()
  196. {
  197.   /* Error messages: */
  198.   BYTE error;
  199.  
  200.   /* The channel we have received: */
  201.   UBYTE channels;
  202.  
  203.   /* Current note: */
  204.   int note;
  205.  
  206.   /* Pointer to the audio register:      */
  207.   /* (If we have successfuly reserved    */
  208.   /* the sound channel we initialize the */
  209.   /* corresponding pointer, else it      */
  210.   /* remains NULL.)                      */
  211.   struct AudChannel *left0_audio_register = NULL;
  212.   struct AudChannel *left1_audio_register = NULL;
  213.   struct AudChannel *right0_audio_register = NULL;
  214.   struct AudChannel *right1_audio_register = NULL;
  215.  
  216.  
  217.  
  218.   /* Get a reply port: (No name, priority 0) */
  219.   replymp = (struct MsgPort *)
  220.     CreatePort( NULL, 0 );
  221.   if( !replymp )
  222.     clean_up( "Could not create the reply port!" );
  223.  
  224.  
  225.  
  226.   /* Allocate and preinitialize an audio request block: */
  227.   audio_req = (struct IOAudio *)
  228.     CreateExtIO( replymp, sizeof( struct IOAudio ) );
  229.   if( !audio_req )
  230.     clean_up( "Not enough memory for the IOAudio structure!" );
  231.  
  232.  
  233.  
  234.   /* Allocate memory for the lock: */
  235.   audio_lock = (struct IOAudio *)
  236.     CreateExtIO( replymp, sizeof( struct IOAudio ) );
  237.   if( !audio_lock )
  238.     clean_up( "Not enough memory for the Lock!" );
  239.  
  240.  
  241.  
  242.   /* Set sound priority: */
  243.   audio_req->ioa_Request.io_Message.mn_Node.ln_Pri = SOUND_EFFECT;
  244.  
  245.   /* Give the audio structure our replyport: */
  246.   audio_req->ioa_Request.io_Message.mn_ReplyPort = replymp;
  247.  
  248.   /* Tell the Audio Device which channels we preffere: */
  249.   audio_req->ioa_Data = desired_channels;
  250.  
  251.   /* The size of our list of desired channels: */
  252.   audio_req->ioa_Length = sizeof( desired_channels );
  253.  
  254.  
  255.  
  256.   /* Open the Audio Device and at the same time try to */
  257.   /* reserve the channel(s):                           */
  258.   error = OpenDevice( AUDIONAME, 0, audio_req, 0 );
  259.   if( error )
  260.   {
  261.     /* Clear the "io_Device" flag since we have not opened the device: */
  262.     audio_req->ioa_Request.io_Device = NULL;
  263.   
  264.     /* Quit: */
  265.     clean_up( "Could not open the Audio Device!" );
  266.   }
  267.  
  268.  
  269.  
  270.   /* Check which channel we received: */
  271.   channels = (UBYTE) audio_req->ioa_Request.io_Unit;
  272.  
  273.   if( channels & LEFT0F )
  274.   {
  275.     printf( "First left sound channel.\n" );
  276.     left0_audio_register = &aud[ LEFT0B ];
  277.   }
  278.  
  279.   if( channels & RIGHT0F )
  280.   {
  281.     printf( "First right sound chanel.\n" );
  282.     right0_audio_register = &aud[ RIGHT0B ];
  283.   }
  284.  
  285.   if( channels & RIGHT1F )
  286.   {
  287.     printf( "Second right sound channel.\n" );
  288.     right1_audio_register = &aud[ RIGHT1B ];
  289.   }
  290.  
  291.   if( channels & LEFT1F )
  292.   {
  293.     printf( "Second left sound channel.\n" );
  294.     left1_audio_register = &aud[ LEFT1B ];
  295.   }
  296.  
  297.  
  298.  
  299.   /* Directly after we have received a channel we lock it: */
  300.  
  301.   /* We want to lock some channels: */
  302.   audio_lock->ioa_Request.io_Command = ADCMD_LOCK;
  303.  
  304.   /* The lock should use our reply port: */
  305.   audio_lock->ioa_Request.io_Message.mn_ReplyPort = replymp;
  306.  
  307.   /* Use the same audio device: */
  308.   audio_lock->ioa_Request.io_Device = audio_req->ioa_Request.io_Device;
  309.  
  310.   /* Lock all our channels: */
  311.   audio_lock->ioa_Request.io_Unit = audio_req->ioa_Request.io_Unit;
  312.  
  313.   /* Allocate: */
  314.   audio_lock->ioa_AllocKey = audio_req->ioa_AllocKey;
  315.  
  316.   /* Set the lock: (SendIO() is OK to use) */
  317.   SendIO( audio_lock );
  318.  
  319.   /* Check if the channel has been stolen: */
  320.   if( CheckIO( audio_lock ) )
  321.     clean_up( "Our channel was stolen!" );
  322.  
  323.  
  324.  
  325.   /* Allocate some memory where we can store the waveform we   */
  326.   /* want to use. Note that it must be Chip memory, and placed */
  327.   /* on a word boundary!                                       */
  328.   square_wave = (BYTE *) AllocMem( SQUARE_DATA_LENGTH, MEMF_CHIP );
  329.   if( !square_wave )
  330.     clean_up( "Could not allocate enough memory for the square wave!" );  
  331.  
  332.   /* Initialize the waveform: (This is the smallest    */
  333.   /* waveform you can use, and undouptly the easiest.) */
  334.   square_wave[ 0 ] = 127;
  335.   square_wave[ 1 ] = -127;
  336.  
  337.  
  338.  
  339.   
  340.   /* We will now initialize all hardware registers of the */
  341.   /* sound channels we successfully reserved.             */
  342.  
  343.   /* First left sound channel: */
  344.   if( left0_audio_register )
  345.   {
  346.     /* Pointer to the waveform: */
  347.     left0_audio_register->ac_ptr = (UWORD *) square_wave;
  348.  
  349.     /* Set the lenght of the waveform */
  350.     left0_audio_register->ac_len = SQUARE_DATA_LENGTH;
  351.  
  352.     /* Set the period value: */
  353.     left0_audio_register->ac_per =
  354.       PAL_CLOCK / note_frequency[ 0 ] / SQUARE_DATA_LENGTH;
  355.  
  356.     /* Maximum volume: */
  357.     left0_audio_register->ac_vol = MAXVOLUME;
  358.   }
  359.  
  360.  
  361.  
  362.   /* First right sound channel: */
  363.   if( right0_audio_register )
  364.   {
  365.     /* Pointer to the waveform: */
  366.     right0_audio_register->ac_ptr = (UWORD *) square_wave;
  367.  
  368.     /* Set the lenght of the waveform */
  369.     right0_audio_register->ac_len = SQUARE_DATA_LENGTH;
  370.  
  371.     /* Set the period value: */
  372.     right0_audio_register->ac_per =
  373.       PAL_CLOCK / note_frequency[ 0 ] / SQUARE_DATA_LENGTH;
  374.  
  375.     /* Maximum volume: */
  376.     right0_audio_register->ac_vol = MAXVOLUME;
  377.   }
  378.  
  379.  
  380.  
  381.   /* Second right sound channel: */
  382.   if( right1_audio_register )
  383.   {
  384.     /* Pointer to the waveform: */
  385.     right1_audio_register->ac_ptr = (UWORD *) square_wave;
  386.  
  387.     /* Set the lenght of the waveform */
  388.     right1_audio_register->ac_len = SQUARE_DATA_LENGTH;
  389.  
  390.     /* Set the period value: */
  391.     right1_audio_register->ac_per =
  392.       PAL_CLOCK / note_frequency[ 0 ] / SQUARE_DATA_LENGTH;
  393.  
  394.     /* Maximum volume: */
  395.     right1_audio_register->ac_vol = MAXVOLUME;
  396.   }
  397.   
  398.  
  399.  
  400.   /* Second left sound channel: */
  401.   if( left1_audio_register )
  402.   {
  403.     /* Pointer to the waveform: */
  404.     left1_audio_register->ac_ptr = (UWORD *) square_wave;
  405.  
  406.     /* Set the lenght of the waveform */
  407.     left1_audio_register->ac_len = SQUARE_DATA_LENGTH;
  408.  
  409.     /* Set the period value: */
  410.     left1_audio_register->ac_per =
  411.     PAL_CLOCK / note_frequency[ 0 ] / SQUARE_DATA_LENGTH;
  412.  
  413.     /* Maximum volume: */
  414.     left1_audio_register->ac_vol = MAXVOLUME;
  415.   }
  416.  
  417.  
  418.  
  419.   /* Now all values have been set as desired, now tell the */
  420.   /* hardware that we want to have some music!:            */
  421.  
  422.   dmacon = DMAF_SETCLR | channels;
  423.  
  424.  
  425.   /* Tell the user to be prepared: */
  426.   printf( "Here comes some notes: (A to G#)\n" );
  427.  
  428.   /* Take a small pause: */
  429.   Delay( 1 SECONDS );
  430.  
  431.   /* Play one octave: */
  432.   for( note=1; note < OCTAVE; note++ )
  433.   {
  434.     /* Check if the channel has been stolen: */
  435.     if( CheckIO( audio_lock ) )
  436.       clean_up( "Someone wants one (or more) of our sound channels!" );
  437.  
  438.     /* Change the period value: */
  439.     left0_audio_register->ac_per =
  440.       PAL_CLOCK / note_frequency[ note ] / SQUARE_DATA_LENGTH;
  441.  
  442.     right0_audio_register->ac_per =
  443.       PAL_CLOCK / note_frequency[ note ] / SQUARE_DATA_LENGTH;
  444.  
  445.     right1_audio_register->ac_per =
  446.       PAL_CLOCK / note_frequency[ note ] / SQUARE_DATA_LENGTH;
  447.  
  448.     left1_audio_register->ac_per =
  449.       PAL_CLOCK / note_frequency[ note ] / SQUARE_DATA_LENGTH;
  450.  
  451.     /* Remember that you may only write to these hardware    */
  452.     /* registers and not read them. If you try to read these */
  453.     /* registers the values may be corrupted, and the sound  */
  454.     /* may be destroyed. When you are using this type of     */
  455.     /* hardware registers you should therefore never try to  */
  456.     /* use commands like +=, -=, *= etc...                   */
  457.  
  458.  
  459.  
  460.     /* Print a mark: */
  461.     printf( "*" );
  462.  
  463.     /* Take a small pause: */
  464.     Delay( 1 SECONDS );
  465.   }
  466.  
  467.  
  468.   /* Clean up and quit: */
  469.   clean_up( "The End!" );
  470. }
  471.  
  472.  
  473.  
  474. /* Close and return everything that has been */
  475. /* opened and allocated before we quit:      */
  476.  
  477. void clean_up( STRPTR text )
  478. {
  479.   /* If we have an audio request block, and it does */
  480.   /* not contain any errors, we must free its sound */
  481.   /* channels:                                      */
  482.   if( audio_req && !(audio_req->ioa_Request.io_Error) )
  483.   {
  484.     /* Free the channel(s): */
  485.     audio_req->ioa_Request.io_Command = ADCMD_FREE;
  486.  
  487.     /* We are allowed to use the function DoIO() for */
  488.     /* this request since it will not change any     */
  489.     /* values that are vital for us:                 */ 
  490.     DoIO( audio_req );
  491.     
  492.     /* The lock is automatically unlocked when we */
  493.     /* free the audio channel.                    */
  494.   }
  495.  
  496.   /* Empty the reply port: */
  497.   while( GetMsg( replymp ) )
  498.     printf( "Collected a message at the reply port.\n" );
  499.   
  500.   /* If we have a request block and the "io_Device" field  */
  501.   /* is not zero, we know that the device has successfully */
  502.   /* been opened and must now be closed:                   */ 
  503.   if( audio_req && audio_req->ioa_Request.io_Device )
  504.     CloseDevice( audio_req );
  505.  
  506.   /* Remove the replyport: */
  507.   if( replymp )
  508.     DeletePort( replymp);
  509.  
  510.   /* Dealocate the IOAudio structure: */
  511.   if( audio_req )
  512.     DeleteExtIO( audio_req, sizeof( struct IOAudio ) );
  513.  
  514.   /* Dealocate the lock: */
  515.   if( audio_lock )
  516.     DeleteExtIO( audio_lock, sizeof( struct IOAudio ) );
  517.  
  518.   /* Dealocate the square waveform: */
  519.   if( square_wave )
  520.     FreeMem( square_wave, SQUARE_DATA_LENGTH );
  521.  
  522.   /* Print the last message: */
  523.   printf( "%s\n", text );
  524.  
  525.   /* Quit: */
  526.   exit( 0 );
  527. }
  528.  
  529.  
  530.