home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1992-1993, 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- #include "Noise.h"
- #include <string.h>
-
- static void kill_handler(int);
-
- #define MAX_SOUNDS 1000
-
- static Boolean _arena_initialized = FALSE;
- static char * _arena_file = "/usr/tmp/soundXXXXXX";
- static usptr_t * _arena;
-
- Noise::Noise(const char *filename, int max_usec, Boolean continuity)
- {
- // keep around the filename to identify the noise
- _filename = filename;
-
- // init audio for this noise
- _config = ALnewconfig();
- ALsetwidth(_config, AL_SAMPLE_16);
- ALsetchannels(_config, AL_STEREO);
- // ALsetqueuesize(_config, 2048);
- _port = ALopenport(filename, "w", _config);
-
- if (! _port)
- {
- fprintf(stderr,"Couldn't open a port. %s will not play.\n",_filename);
- return;
- }
-
- fprintf(stderr,"Reading audio file %s...",_filename);
- _s = readsample(_filename);
- fprintf(stderr,"Done.\n");
- _max_samples = sample_length(max_usec);
-
- // array used to store the sound to be played
- _outsample = new short [_max_samples];
- _start = 0.0; // start of next sound as a fractional pointer
-
- // if continuity is false, the audio handler will
- // go to sleep when the queue is empty, otherwise it
- // repeatedly play at the last pitch until a new one shows up
- _continuous = continuity;
-
- // allocate circular queue pitches to play
- _queue = new Sound [MAX_SOUNDS];
- _in = _out = 0;
-
- _received_noise = FALSE;
-
- // initialize shared mem stuff which is common to all noises just once
- if (! _arena_initialized)
- {
- fprintf(stderr, "Initializing shared memory...");
- // create unique filename
- mktemp(_arena_file);
-
- // initialize shared memory arena
- usconfig(CONF_ARENATYPE,US_SHAREDONLY);
- _arena = usinit(_arena_file);
-
- _arena_initialized = TRUE;
- fprintf(stderr,"Done.\n");
- }
-
- // initialize semaphore for the circular sound buffer
- _noises_to_play = usnewsema(_arena, 0); // initially no sounds
-
- // set up the audio process
- fprintf(stderr,"Initializing audio process...");
- sproc( (void (*)(void *)) (Noise::audio_handler), PR_SALL, this);
-
- // setup signal handling - children notified if parent dies
- prctl(PR_SETEXITSIG, SIGTERM);
-
- // setup signal handling in parent
- sigset(SIGINT, (void (*)(int ...)) &kill_handler);
- sigset(SIGTERM, (void (*)(int ...)) &kill_handler);
- sigset(SIGQUIT, (void (*)(int ...)) &kill_handler);
- fprintf(stderr,"Done.\n");
- }
-
-
- Noise::~Noise()
- {
- // delete [_max_samples] _outsample;
- // delete [MAX_SOUNDS] _queue;
- delete [] _outsample;
- delete [] _queue;
-
- // for now, let the process get killed so we don't get a race
- // condition where the port gets closed before the process
- // get killed
- // ALcloseport(_port);
- }
-
-
- // returns the number of samples to fill the given time
- long Noise::sample_length(long usec)
- {
- // times 2 since stereo, XXX clean this up
- return 2*(long)((float)_s->samprate * (float)usec/1000000.0);
- }
-
-
- // doesn't really play the sound, instead adds it to
- // the circular queue for this sound
- void Noise::play(float pitch, long usec)
- {
- if (! _port)
- {
- fprintf(stderr,"%s does not have a port. Nothing played.\n",_filename);
- return;
- }
-
-
- if (usec < 2000) usec = 2000;
- long samples = sample_length(usec);
-
- if (samples > _max_samples)
- {
- fprintf(stderr, "Noise %s: sample too long. Ignoring.\n",_filename);
- return;
- }
-
- _queue[_in].pitch = pitch;
- _queue[_in].length = samples;
-
- _received_noise = TRUE;
-
- usvsema(_noises_to_play); // increment (release) the semaphore
- _in = (_in + 1)%MAX_SOUNDS;
- }
-
-
- void Noise::play_now(float pitch, long usec)
- {
- if (! _port)
- {
- fprintf(stderr,"This noise does not have a port. Nothing played.\n");
- return;
- }
-
- static float last_pitch;
- static Boolean first_time = TRUE;
-
- long length = sample_length(usec);
-
- if (length > _max_samples)
- {
- fprintf(stderr, "Noise: sample too long. Ignoring.\n");
- return;
- }
-
- if (first_time)
- {
- last_pitch = pitch;
- first_time = FALSE;
- }
-
- makenoise(last_pitch, pitch, length);
- }
-
-
- // Create the sample to play and send it to the
- // audio subsystem.
- // The sound will be a smooth transition in pitch from
- // the last pitch played to this pitch.
- // pitch = 1.0 is the original sound
- // pitch = .5 is down one octave, pitch = 2.0 up one octave, etc.
- // length is length in samples
- void Noise::makenoise(float last_pitch, float pitch, long length)
- {
- float step = last_pitch;
- float delta_step = (pitch - last_pitch)/(float)length;;
-
- for (int i = 0; i < length; i++)
- {
- int ptr = (int) (_start + 0.5);
-
- _outsample[i] = _s->data[ptr];
-
- _start = _start + step;
-
- if ((int) (_start + 0.5) >= _s->nsamples)
- _start = _start - (float)_s->nsamples;
-
- step += delta_step;
- }
-
- while (ALgetfilled(_port) > 10000)
- hack_sginap(1);
-
- ALwritesamps(_port, _outsample, length);
- }
-
-
- // This processes is sproc'ed from the constructor. It reads
- // out of the circular queue, and blocks if there is nothing
- // to read.
- // This process will sleep if there is nothing to play
- void Noise::audio_handler()
- {
- float pitch, last_pitch = 1.0;
- long length, last_length = 10000;
- Boolean first_time = TRUE;
-
- sigset(SIGTERM, (void (*)(int ...)) &kill_handler);
-
- while(TRUE)
- {
- Boolean get_from_queue = FALSE;
-
- if (! _continuous)
- {
- // Aquire the semaphore. This decrements the semaphore,
- // and will sleep if it goes to -1
- uspsema(_noises_to_play);
-
- get_from_queue = TRUE;
- }
- else
- {
- // Try to aquire the semaphore.
- // If aquired, get sound, otherwise use previous
- // sound. This will not ever go to sleep.
- if (uscpsema(_noises_to_play))
- get_from_queue = TRUE;
- }
-
- if (get_from_queue)
- {
- // read the sound from the queue
- pitch = _queue[_out].pitch;
- length = _queue[_out].length;
-
- _out = (_out + 1)%MAX_SOUNDS;
-
- if (first_time)
- {
- last_pitch = pitch;
- last_length = length;
- first_time = FALSE;
- }
- }
- else
- {
- // no sounds were available, so play
- // previous sound
- pitch = last_pitch;
- length = last_length;
- }
-
- // do it
- if (_received_noise)
- {
- makenoise(last_pitch, pitch, length);
- last_pitch = pitch;
- last_length = length;
- }
- }
- }
-
-
- static void kill_handler(int signal)
- {
- printf("Audio process killed by a signal %d\n",signal);
- exit(0);
- }
-
-
-