home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / demos / audio / drive / Noise.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  6.7 KB  |  287 lines

  1. /*
  2.  * Copyright 1992-1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. #include "Noise.h"
  18. #include <string.h>
  19.  
  20. static void kill_handler(int);
  21.  
  22. #define MAX_SOUNDS 1000
  23.  
  24. static Boolean _arena_initialized = FALSE;
  25. static char * _arena_file = "/usr/tmp/soundXXXXXX";
  26. static usptr_t * _arena;
  27.  
  28. Noise::Noise(const char *filename, int max_usec, Boolean continuity)
  29. {
  30.     // keep around the filename to identify the noise
  31.     _filename = filename;
  32.     
  33.     // init audio for this noise
  34.     _config = ALnewconfig();
  35.     ALsetwidth(_config, AL_SAMPLE_16);
  36.     ALsetchannels(_config, AL_STEREO);
  37.     // ALsetqueuesize(_config, 2048);
  38.     _port = ALopenport(filename, "w", _config);
  39.  
  40.     if (! _port)
  41.     {
  42.         fprintf(stderr,"Couldn't open a port. %s will not play.\n",_filename);
  43.         return;
  44.     }
  45.  
  46.     fprintf(stderr,"Reading audio file %s...",_filename);
  47.     _s = readsample(_filename);
  48.     fprintf(stderr,"Done.\n");
  49.     _max_samples = sample_length(max_usec);
  50.  
  51.     // array used to store the sound to be played
  52.     _outsample = new short [_max_samples]; 
  53.     _start = 0.0; // start of next sound as a fractional pointer
  54.  
  55.     // if continuity is false, the audio handler will
  56.     // go to sleep when the queue is empty, otherwise it
  57.     // repeatedly play at the last pitch until a new one shows up
  58.     _continuous = continuity;
  59.  
  60.     // allocate circular queue pitches to play
  61.     _queue = new Sound [MAX_SOUNDS];
  62.     _in = _out = 0;
  63.         
  64.     _received_noise = FALSE;
  65.     
  66.     // initialize shared mem stuff which is common to all noises just once
  67.     if (! _arena_initialized)
  68.     {
  69.         fprintf(stderr, "Initializing shared memory...");
  70.         // create unique filename
  71.          mktemp(_arena_file);
  72.  
  73.         // initialize shared memory arena
  74.         usconfig(CONF_ARENATYPE,US_SHAREDONLY);
  75.         _arena = usinit(_arena_file);
  76.  
  77.         _arena_initialized = TRUE;
  78.         fprintf(stderr,"Done.\n");
  79.     }
  80.  
  81.     // initialize semaphore for the circular sound buffer
  82.     _noises_to_play = usnewsema(_arena, 0); // initially no sounds
  83.  
  84.     // set up the audio process
  85.     fprintf(stderr,"Initializing audio process...");
  86.     sproc( (void (*)(void *)) (Noise::audio_handler), PR_SALL, this);
  87.  
  88.     // setup signal handling - children notified if parent dies
  89.     prctl(PR_SETEXITSIG, SIGTERM);
  90.  
  91.     // setup signal handling in parent
  92.     sigset(SIGINT, (void (*)(int ...)) &kill_handler);
  93.     sigset(SIGTERM, (void (*)(int ...)) &kill_handler);
  94.     sigset(SIGQUIT, (void (*)(int ...)) &kill_handler);
  95.     fprintf(stderr,"Done.\n");
  96. }
  97.  
  98.  
  99. Noise::~Noise()
  100. {
  101. //    delete [_max_samples] _outsample;
  102. //    delete [MAX_SOUNDS] _queue;
  103.     delete [] _outsample;
  104.     delete [] _queue;
  105.  
  106.     // for now, let the process get killed so we don't get a race
  107.     // condition where the port gets closed before the process
  108.     // get killed
  109. //    ALcloseport(_port);
  110. }
  111.  
  112.  
  113. // returns the number of samples to fill the given time
  114. long Noise::sample_length(long usec)
  115. {
  116.     // times 2 since stereo, XXX clean this up
  117.     return 2*(long)((float)_s->samprate * (float)usec/1000000.0);
  118. }
  119.  
  120.  
  121. // doesn't really play the sound, instead adds it to
  122. // the circular queue for this sound
  123. void Noise::play(float pitch, long usec)
  124. {
  125.     if (! _port)
  126.     {
  127.         fprintf(stderr,"%s does not have a port. Nothing played.\n",_filename);
  128.         return;
  129.     }
  130.  
  131.     
  132.     if (usec < 2000) usec = 2000;    
  133.     long samples = sample_length(usec);
  134.  
  135.     if (samples > _max_samples)
  136.     {
  137.         fprintf(stderr, "Noise %s: sample too long. Ignoring.\n",_filename);
  138.         return;
  139.     }
  140.     
  141.     _queue[_in].pitch = pitch;
  142.     _queue[_in].length = samples;
  143.  
  144.     _received_noise = TRUE;
  145.     
  146.     usvsema(_noises_to_play); // increment (release) the semaphore
  147.     _in = (_in + 1)%MAX_SOUNDS;
  148. }
  149.  
  150.  
  151. void Noise::play_now(float pitch, long usec)
  152. {
  153.     if (! _port)
  154.     {
  155.         fprintf(stderr,"This noise does not have a port. Nothing played.\n");
  156.         return;
  157.     }
  158.  
  159.     static float last_pitch;
  160.     static Boolean first_time = TRUE;
  161.     
  162.     long length = sample_length(usec);
  163.     
  164.     if (length > _max_samples)
  165.     {
  166.         fprintf(stderr, "Noise: sample too long. Ignoring.\n");
  167.         return;
  168.     }
  169.     
  170.     if (first_time)
  171.     {
  172.         last_pitch = pitch;
  173.         first_time = FALSE;
  174.     }
  175.  
  176.     makenoise(last_pitch, pitch, length);
  177. }
  178.  
  179.  
  180. // Create the sample to play and send it to the
  181. // audio subsystem.
  182. // The sound will be a smooth transition in pitch from
  183. // the last pitch played to this pitch. 
  184. // pitch = 1.0 is the original sound
  185. // pitch = .5 is down one octave, pitch = 2.0 up one octave, etc.
  186. // length is length in samples
  187. void Noise::makenoise(float last_pitch, float pitch, long length)
  188. {
  189.     float step = last_pitch;
  190.     float delta_step = (pitch - last_pitch)/(float)length;;
  191.  
  192.     for (int i = 0; i < length; i++)
  193.     {
  194.         int ptr = (int) (_start + 0.5);
  195.         
  196.         _outsample[i] = _s->data[ptr];
  197.  
  198.         _start = _start + step;
  199.         
  200.         if ((int) (_start + 0.5) >= _s->nsamples)
  201.             _start = _start - (float)_s->nsamples;
  202.  
  203.         step += delta_step;
  204.     }
  205.  
  206.     while (ALgetfilled(_port) > 10000)
  207.         hack_sginap(1);
  208.  
  209.     ALwritesamps(_port, _outsample, length);
  210. }
  211.  
  212.  
  213. // This processes is sproc'ed from the constructor. It reads
  214. // out of the circular queue, and blocks if there is nothing
  215. // to read.
  216. // This process will sleep if there is nothing to play
  217. void Noise::audio_handler()
  218. {
  219.     float pitch, last_pitch = 1.0;
  220.     long length, last_length = 10000;
  221.     Boolean first_time = TRUE;
  222.  
  223.     sigset(SIGTERM, (void (*)(int ...)) &kill_handler);
  224.     
  225.     while(TRUE)
  226.     {
  227.         Boolean get_from_queue = FALSE;
  228.  
  229.         if (! _continuous)
  230.         {
  231.             // Aquire the semaphore. This decrements the semaphore,
  232.             // and will sleep if it goes to -1
  233.             uspsema(_noises_to_play);
  234.  
  235.             get_from_queue = TRUE;
  236.         }
  237.         else
  238.         {
  239.             // Try to aquire the semaphore.
  240.             // If aquired, get sound, otherwise use previous
  241.             // sound. This will not ever go to sleep.
  242.             if (uscpsema(_noises_to_play))
  243.                 get_from_queue = TRUE;
  244.         }                
  245.  
  246.         if (get_from_queue)
  247.         {
  248.             // read the sound from the queue
  249.             pitch = _queue[_out].pitch;
  250.             length = _queue[_out].length;
  251.             
  252.             _out = (_out + 1)%MAX_SOUNDS;
  253.  
  254.             if (first_time)
  255.             {
  256.                 last_pitch = pitch;
  257.                 last_length = length;
  258.                 first_time = FALSE;
  259.             }
  260.         }
  261.         else
  262.         {
  263.             // no sounds were available, so play
  264.             // previous sound
  265.             pitch = last_pitch;
  266.             length = last_length;
  267.         }
  268.         
  269.         // do it
  270.         if (_received_noise)
  271.         {
  272.             makenoise(last_pitch, pitch, length);
  273.             last_pitch = pitch;
  274.             last_length = length;
  275.         }
  276.     }
  277. }
  278.  
  279.  
  280. static void kill_handler(int signal)
  281. {
  282.     printf("Audio process killed by a signal %d\n",signal);
  283.     exit(0);
  284. }
  285.  
  286.  
  287.