/******************************************************************* * * * lrf_audio.c - Audio Port Code * * * * This file contains functions related to the audio port. * * Routines to open, close, write to, and control the audio port. * * Routines to generate several types of audio signals are also * * included. * * * * Prior to initialization, the audio port and audio control port * * file descriptors are set to -1. * * * * WRITTEN BY: Bill Kapralos * * DATE: Monday, June 16 1997 * * * * York University * * Department of Computer Science * * * * Part of the port initialization code (audioInit) was obtained * * from soundtool.c (author unknown). * * * *******************************************************************/ #include "lrf_audio.h" struct audio_info audioInfo; /* Audio settings and parameters. */ /***************************************************************** * * Open audio port for writing only. Initialize audio control port * to the desired parameters. Settings can also be set using the audio * device however it is recommended to use the audio control device. * * Returns 1 upon successful open/initialization and 0 otherwise. * ******************************************************************/ int audioInit(char *audioDevice){ int err, flag; /* Open audio port. A return of < 0 indicates unsuccessful open. */ if((audioFd = open(audioDevice, O_WRONLY)) < 0 ){ if((errno == EINTR) || (errno == EBUSY)){ /* Device being used. */ fprintf(stderr, "Audio device being used.\n"); return ERROR; } /* Error opening audio device. */ fprintf(stderr, "Unable to open %s.\n", AUDIO_PORT); return ERROR; } /* Initialize audio structure and set accordingly. Before setting any parameters, reset the device. See audioio.h and lrf_audiov2.h for the definition of the setting values. */ AUDIO_INITINFO(&audioInfo); audioInfo.play.port = AUDIO_HEADPHONE; /* audioInfo.play.port = AUDIO_SPEAKER;*/ /* Control the volume between the left and right channels. When set between AUDIO_LEFT_BALANCE and AUDIO_MID_BALANCE the right channel will be reduced in prportion to balance value. When set between AUDIO_MID_BALANCE and AUDIO_RIGHT_BALANCE let channel is reduced. */ audioInfo.play.balance = AUDIO_MID_BALANCE; /* Volume control. Between 0 (AUDIO_MIN_GAIN) to 255 AUDIO_MAX_GAIN. */ audioInfo.play.gain = AUDIO_GAIN; audioInfo.play.sample_rate = FREQ_SAMPLING_RATE; /* Encoding setting - linear (AUDIO_ENCODING_LINEAR), u-law (AUDIO_ENCODING_ULAW), A-law (AUDIO_ENCODING_ALAW. */ audioInfo.play.encoding = AUDIO_ENCODING_LINEAR; /* Bits per sample - 8 or 16 or 32. */ audioInfo.play.precision = SAMPLE_PRECISION; /* Set audio device with above parameters. */ err = ioctl(audioFd, AUDIO_SETINFO, &audioInfo); if(err < 0){ /* Audio control device not set. */ fprintf(stderr, "Cannot set audio info.\n"); return ERROR; } /* Successful opening/setting of audio and audio control devices. */ audioPortInitialized = 1; return 1; } /***************************************************************** * * Sends 'numOfSamples' bytes to the audio port beginning at address * 'buffer'. Audio port must be initialized and the number of bytes * actually written to the port must be the same as the number sent to * avoid error and halting of the program. * *******************************************************************/ int sendAudio(short *buffer, int numOfSamples){ int count; if (!audioPortInitialized){ fprintf(stderr, "Audio Port not initialized!"); return ERROR; } if((count = write(audioFd, (short *)&buffer[0], numOfSamples)) != numOfSamples){ fprintf(stderr, "Sending data to audio port!\n"); return ERROR; } /* Allow blocking until all queded output data has been played since all data sent to audio device is buffered. */ if (ioctl(audioFd, AUDIO_DRAIN) < 0) fprintf(stderr, "Could not drain audio buffer"); return count; } /*********************************************************************** * * The samples required for each cosine wave (each cosine wave corresponds to a * particular distance), are calculated and stored in a table to allow for * future look up and use). Table contains samples of waves from MIN_DISTANCE * to MAX_DISTANCE (incremented by 0.10 - which represents the LRF accuracy * in temperature range of -20 - 50 degrees Celsius). * *************************************************************************/ void tableInit(short *table[], int varyMagnitude){ double frequency, excitation, distance = MIN_DISTANCE, *signal; int index; /* Create all the samples for each wave in the table. There are several distances below MIN_DISTANCE not represented in the table. Table contains 150 waves minus these non-included waves. */ for(index = 0; index < NUM_OF_WAVES - tableOffset; index++, distance += DISTANCE_INCR){ frequency = FREQ_CONST * exp(-(distance - MIN_DISTANCE) * ADJUSTMENT); /* Vary magnitude of signal with distance if option chosen. */ excitation = (varyMagnitude) ? 20.0 * (1/pow(distance, 2.0)) : 1.0; table[index] = makeWave(frequency, excitation, NUM_OF_SAMPLES); } } /****************************************************************** * * Create a buffer of samples representing a cosine wave of the specified * frequency and magnitude. Convert the values obtained from the cos * function to the corresponding PCM value. * **************************************************************/ short *makeWave(double frequency, double magnitude, int numSamples){ int index; double freqRatio, twoPi, radianValue, twoPiF_S, num = 100; short *sample; FILE *tempFD; /* Allocate the sample array and set to zero. */ sample = (short *) calloc(NUM_OF_SAMPLES, sizeof(short)); tmpFd = fopen("tempAudio", "wb"); if(!sample) error("Unable to allocate samples"); /* Ratio of frequency to frequency sampling rate. */ freqRatio = (frequency / FREQ_SAMPLING_RATE); twoPi = 8.0 * atan(1.0); /* Calculate 2 * PI = 360 deg. */ twoPiF_S = twoPi * freqRatio; /* Constant for all sample values. */ /* Create the samples. */ for (index = 0; index < numSamples; index++) sample[index] = audio_d2s((magnitude * cos(twoPiF_S * index))); for(index = numSamples - (int) num; index < numSamples; index++){ fprintf(fileDes, "%lf\n",sin(twoPiF_S * index)); sample[index] = (((double) numSamples - (double) index) / num) * audio_d2s((magnitude * sin(twoPiF_S * index))); } return(sample); } /*****************************************************************/ short *makeDepthSignal(int numOfSamples){ short *buffer; int index = 0; if(!(buffer = (short *) calloc(numOfSamples, sizeof(short *)))) error("Cannot allocate space for 'buffer' in makeDepthSignal()."); buffer[index++] = -32500; for(; index < numOfSamples - 1; index++) buffer[index] = 32500; buffer[index] = -32500; return buffer; } /******************************************************************** * * Creates and returns a buffer representing noise when output with magnitude * given by 'excitation'. Noise is created by assigning random values to * element of the buffer. * ********************************************************************/ short *createNoise(int numOfSamples, double excitation){ int index; short *buffer; if(!(buffer = (short *) calloc(numOfSamples, sizeof(short *)))) error("Cannot allocate space for 'buffer' in createNoise()."); srand(0); /* Seed used for the random number generator. */ for(index = 0; index < numOfSamples; index++) buffer[index] = excitation * rand(); return buffer; } /***************************************************************** * * *****************************************************************/ double findAmplitude(double frequency){ int index = 0, newFreq, fraction = 0; double amp, tempAmp; /* No entry in the table for frequencies below 20Hz. */ if(frequency < 20.0){ printf("Small frequency!\n"); exit(0); } /* Any fractional portion of the argument 'frequency' is ignored. */ newFreq = (int) frequency; /* Frequencies in the range 20 - 99Hz. */ if(newFreq < 100){ /* Determine whether frequency maps to table entry & if not keep a record of it as we will need to return an average. */ if(newFreq % 10 != 0){ /* We will look up the closest entry less than the argument 'frequency'. */ newFreq = newFreq - (newFreq % 10); fraction = 1; } /* Determine the table index. */ while(newFreq > 0){ newFreq = newFreq - 10; index++; } } /* Frequencies in the range 100 - 999Hz. */ else if(newFreq < 1000){ if(newFreq % 100 != 0){ fraction = 1; newFreq = newFreq - (newFreq % 100); } while(newFreq > 0){ newFreq = newFreq - 100; index++; } index += 9; } /* frequencies in the range 1000 - 9999Hz. */ else if(newFreq < 10000){ if(newFreq % 1000 != 0) fraction = 1; while(newFreq > 0){ newFreq = newFreq - 1000; index++; } index += 18; } if(!fraction){ return amplitudeTable[index - 1]; } else { return ((amplitudeTable[index - 1] + amplitudeTable[index]) / 2.0); } } /********************************************************************/