home *** CD-ROM | disk | FTP | other *** search
/ Audio 4.94 - Over 11,000 Files / audio-11000.iso / mac / soundutl / rndmsndc.hqx / RandomSound.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-15  |  10.1 KB  |  327 lines

  1. /*
  2.  ***********************************************************************
  3.  *
  4.  * This is a whimsy set of functions that lets one play the sound
  5.  * picked at random from the sound folder.
  6.  * The sound folder name is supposed to be specified as a "Sound Folder"
  7.  * STR resource. Even if you bastard forgot to set this resource,
  8.  * the folder "Sounds" in the system folder would be assumed.
  9.  *
  10.  ***********************************************************************
  11.  */
  12.  
  13. /* MacHeaders Included */
  14.  
  15. #include <Folders.h>
  16. #include <Sound.h>
  17.  
  18. /*
  19.  *-----------------------------------------------------------------------------------
  20.  *                                 Some standard I/O classes
  21.  */
  22. class ParamBlockHdr
  23. {
  24.     char internal[12];                    // Managed by the File/Queue Managers exclusively
  25.     int (*completion_routine)(void * param_block);    // Completion routine
  26.     OSErr result;                        // Result code, =0 means OK, <0 means error
  27. public:
  28.     StringPtr name;                        // Pointer to some name
  29.     short VRefNum;                        // Vol ref number (if <0), drive ref number (if >0)
  30.                                         // or working dir reference number
  31.                                         
  32.     ParamBlockHdr(void);
  33.     ~ParamBlockHdr(void) {}
  34.     OSErr io_error(void) const        { return result; }
  35. };
  36.  
  37. ParamBlockHdr::ParamBlockHdr(void)
  38. {
  39.     completion_routine = nil;
  40.     result = 1;                            // Work is in progress
  41. }
  42.  
  43. class DIRInfo: public ParamBlockHdr
  44. {
  45. public:
  46.     short ioFRefNum;                    // File ref number
  47.     signed char ioFVersNum;                // Version number
  48.     signed char    filler1;                // Not used
  49.     short ioFDirIndex;                    // Index for the directory
  50.     signed char ioFlAttrib;                // File Attribute
  51.     signed char    filler2;                // Not used
  52.     DInfo ioDrUsrWds;                    // Finder Info
  53.     long ioDrDirId;                        // Directory ID
  54.     short ioDrNmFls;                    // No. files and directories inside this dir
  55.     short filler3[9];                    // Not used
  56.     long ioDrCrDat;                        // Creation date
  57.     long ioDrMdDat;                        // Modification date
  58.     long ioDrBkDat;                        // Backup date
  59.     DXInfo ioDrFndrInfo;                // Additional info for the finder
  60.     long ioDRParID;                        // Dir ID of the parent dir
  61.     
  62.     DIRInfo(const short vol_refno, const long parent_dirid, StringPtr dir_name);
  63.     DIRInfo(StringPtr dir_path_name);
  64.     ~DIRInfo(void) {}
  65.     
  66. };
  67.  
  68.                                     // Getting a directory info
  69.                                     // Dir is specified by the volume refno, 
  70.                                     // parent ID and its name
  71. DIRInfo::DIRInfo(const short vol_refno, const long parent_dirid, StringPtr dir_name)
  72. {
  73.     VRefNum = vol_refno;
  74.     name = dir_name;
  75.     ioFDirIndex = 0;                // not used here
  76.     ioDrDirId = parent_dirid;
  77.     do_well( PBGetCatInfo((CInfoPBRec *)this,FALSE) );
  78.     assert( io_error() == noErr );
  79. }
  80.  
  81.  
  82.                                     // Getting a directory info
  83.                                     // Directory is now specified as a path name
  84. DIRInfo::DIRInfo(StringPtr dir_path_name)
  85. {
  86.     FSSpec dir_record;
  87.     do_well( FSMakeFSSpec(0,0,dir_path_name,&dir_record) );
  88.     
  89.     VRefNum = dir_record.vRefNum;
  90.     name = dir_record.name;
  91.     ioFDirIndex = 0;                // not used here
  92.     ioDrDirId = dir_record.parID;
  93.     do_well( PBGetCatInfo((CInfoPBRec *)this,FALSE) );
  94.     assert( io_error() == noErr );
  95. }
  96.  
  97.  
  98. class FLInfo: public ParamBlockHdr
  99. {
  100. public:
  101.     short ioFRefNum;                    // File ref number
  102.     signed char ioFVersNum;                // Version number
  103.     signed char    filler1;                // Not used
  104.     short ioFDirIndex;                    // Index for the directory
  105.     signed char ioFlAttrib;                // File Attribute
  106.     signed char    ioFlVersNum;            // Version number
  107.     FInfo ioFlFndrInfo;                    // Finder Info
  108.     long ioDirId;                        // Directory ID
  109.     short ioFlStBlk;                    // First alloc block of data fork
  110.     long ioFlLgLen;                        // Logical end-of-file of data fork
  111.     long ioFlPyLen;                        // Physical end-of-file of data fork
  112.     short ioFlRStBlk;                    // First alloc block of resource fork
  113.     long ioFlRLgLen;                    // Logical end-of-file of resource fork
  114.     long ioFlRPyLen;                    // Physical end-of-file of resource fork
  115.     long ioFlCrDat;                        // Creation date
  116.     long ioFlMdDat;                        // Modification date
  117.     
  118.     Str63 file_name;
  119.     FLInfo(const short vol_refno, const long parent_dirid, const int index);
  120.     ~FLInfo(void) {}
  121.     
  122. };
  123.  
  124.                                     // Getting a file info 
  125.                                     // File is specified by the volume refno, 
  126.                                     // dir ID and the index
  127.                                     // Check io_error() for possible fnfErr
  128. FLInfo::FLInfo(const short vol_refno, const long parent_dirid, const int index)
  129. {
  130.     VRefNum = vol_refno;
  131.     name = file_name;
  132.     ioFDirIndex = index;
  133.     ioDirId = parent_dirid;
  134.  
  135.     OSErr err = PBHGetFInfo((HParamBlockRec *)this,FALSE);
  136.     if( err != noErr && err != fnfErr )
  137.       _error("Failed to get a file info for a file indexed %d; error code %d",index,
  138.                err);
  139. }
  140.  
  141. /*
  142.  *-----------------------------------------------------------------------------------
  143.  *                 Sound Directory class that contains all the info about
  144.  *                        the directory with sound files
  145.  */
  146.  
  147. class SoundDirectory
  148. {
  149.     short volume_refno;
  150.     long  dir_id;                // Directory ID of the Sound directory
  151.     long  no_files;                // No. of files and folders in the directory
  152.     void locate_sound_directory(void);
  153.     void locate_system_sound_directory(void);    // i.e. folder "Sounds" in the System Folder
  154.  
  155.                                 // Locate the file with given index and tries
  156.                                 // to open it as a resource. Returns the resource
  157.                                 // refnumber if succeeded, or -1
  158.     short locate_file_open_resource(const int file_no);
  159.     
  160.                                             // Pick a 'snd ' resource at random
  161.                                             // (if there are more than one)
  162.     Handle get_random_sound_rsc(void);
  163.  
  164. public:
  165.     SoundDirectory(void)    { volume_refno = 0; dir_id = -1; }
  166.     ~SoundDirectory(void) {}
  167.     void play_at_random(void);
  168. };
  169.  
  170. /*
  171.  *-----------------------------------------------------------------------------------
  172.  *                 Selecting a folder that contains sound files
  173.  */
  174.  
  175.  
  176.                                         // Try to read the resource "Sound Folder" in the
  177.                                         // STR resource group, and locate the named
  178.                                         // folder. If no such resource is specified,
  179.                                         // locate_system_sound_directory() is called
  180. void SoundDirectory::locate_sound_directory(void)
  181. {
  182.     Handle sound_dir_strp = GetNamedResource('STR ',"\pSound Folder");
  183.     if( sound_dir_strp == nil && ResError() == resNotFound )
  184.     {
  185.       locate_system_sound_directory();        // No resource was specified, use that
  186.       return;                                // in the system folder
  187.     }
  188.     
  189.     do_well( ResError() );
  190.     assert( sound_dir_strp != nil );
  191.     
  192.                                     // Then get the directory ID of the "Sounds"
  193.                                     // folder within it
  194.     HLock(sound_dir_strp);
  195.     DIRInfo sound_dir((StringPtr)*sound_dir_strp);
  196.     HUnlock(sound_dir_strp);
  197.     ReleaseResource(sound_dir_strp);
  198.     
  199.     assure( sound_dir.ioFlAttrib & 0x10, "The named thing is not a directory!");
  200.     volume_refno = sound_dir.VRefNum;
  201.     dir_id = sound_dir.ioDrDirId;
  202.     no_files = sound_dir.ioDrNmFls;
  203. //    message("Dir Id of the sound dir is %d, no. files %d",dir_id,no_files);
  204. }
  205.  
  206.  
  207.                                         // The present version locates the
  208.                                         // directory named Sounds inside the
  209.                                         // system folder
  210. void SoundDirectory::locate_system_sound_directory(void)
  211. {
  212.                                     // First locate the system directory
  213.     long system_dir_id;
  214.     do_well( ::FindFolder(kOnSystemDisk,kSystemFolderType,kDontCreateFolder,
  215.                          &volume_refno,&system_dir_id) );
  216.     
  217.                                     // Then get the directory ID of the "Sounds"
  218.                                     // folder within it
  219.     DIRInfo sound_dir(volume_refno, system_dir_id, "\pSounds");
  220.     assure( sound_dir.ioFlAttrib & 0x10, "The named thing is not a directory!");
  221.     dir_id = sound_dir.ioDrDirId;
  222.     no_files = sound_dir.ioDrNmFls;
  223. //    message("Dir Id of the sound dir is %d, no. files %d",dir_id,no_files);
  224. }
  225.  
  226.  
  227. /*
  228.  *-----------------------------------------------------------------------------------
  229.  *                     Picking a file at random and playing it
  230.  */
  231.  
  232.                                     // Locating a file in the sound dir with a
  233.                                     // specified index. The program then tries
  234.                                     // to open it as a resource. Returns the resource
  235.                                     // refnumber if succeeded, or -1
  236. short SoundDirectory::locate_file_open_resource(const int file_index)
  237. {
  238.     assert( file_index > 0 && file_index <= no_files );
  239.     FLInfo file_info(volume_refno,dir_id,file_index);
  240.     if( file_info.io_error() != noErr )
  241.       return -1;
  242. //    message("File name is %#s",file_info.file_name);
  243.     short res_refno = HOpenResFile(volume_refno,dir_id,file_info.file_name,fsRdPerm);
  244.     if( res_refno == -1 )
  245.       message("Failed to open the resource fork because of error %d",ResError());
  246.     return res_refno;
  247. }
  248.  
  249.  
  250.                                             // Pick a 'snd ' resource at random
  251.                                             // (if there are more than one)
  252. Handle SoundDirectory::get_random_sound_rsc(void)
  253. {
  254.     const ResType snd_restype = 'snd ';
  255.     const int no_snd_resources = Count1Resources(snd_restype);
  256.     if( ResError() != noErr || no_snd_resources < 1 )
  257.     {
  258.       message("Failed to count sound resources because of error %d",ResError());
  259.       return nil;
  260.     }
  261.     
  262.     // message("No of resources %d",no_snd_resources);
  263.     int index;
  264.     if( no_snd_resources == 1 )
  265.       index = 1;
  266.     else
  267.     {                                            // Pick up an index at random
  268.         index = Random() % no_snd_resources;    // within [1,no_snd_resources]
  269.         index = ( index < 0 ? index + no_snd_resources : index ) + 1;
  270.     }
  271.                                                     // Pick the sound resource
  272.      Handle sound_handle = Get1IndResource(snd_restype,index);
  273.     if( ResError() != noErr )
  274.       message("Failed to load a sound resource because of error %d",ResError());
  275.     return sound_handle;
  276. }
  277.  
  278.                                             // Plays and closes the resource file
  279. void SoundDirectory::play_at_random(void)
  280. {
  281.     if( dir_id < 0 )
  282.       locate_sound_directory();
  283.     GetDateTime((unsigned long *)&randSeed);
  284.     Random(); Random(); Random(); Random();                    // Just randomizing
  285.     
  286.     const int max_no_tries = 5;
  287.     register int try;
  288.     for(try=1; try <= max_no_tries; try++)
  289.     {                                        // Pick up an index at random [1,no_files]
  290.       int file_index;
  291.       if( no_files == 1 )
  292.         file_index = 1;
  293.       else
  294.       {
  295.         file_index = Random() % no_files;
  296.         file_index = (file_index < 0 ? file_index + no_files : file_index ) + 1;
  297.       }
  298.       short res_refno = locate_file_open_resource(file_index);
  299.       if( res_refno == -1 )
  300.         continue;
  301.         
  302.       Handle sound_handle = get_random_sound_rsc();
  303.       if( sound_handle != nil )
  304.         {
  305.           LoadResource(sound_handle);      
  306.         do_well( SndPlay(nil,sound_handle,FALSE) );        // Play sound in sync mode
  307.         DisposeHandle(sound_handle);
  308.         CloseResFile(res_refno);
  309.         break;
  310.       }
  311.       else
  312.         CloseResFile(res_refno);                        // and try another sound
  313.      }
  314. }
  315.  
  316. /*
  317.  *-----------------------------------------------------------------------------------
  318.  *                                 Routing module
  319.  */
  320.  
  321. static SoundDirectory sound_bundle;
  322.  
  323. void play_random_sound(void)
  324. {
  325.     sound_bundle.play_at_random();
  326. }
  327.