home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 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.
- */
- /***********************************************************************
- * tableNet.c:
- * Generates AIFF-C file containing eight single, cycle waveforms
- * stored in the following order:
- *
- * 1 non-bandlimited sawtooth
- * 2 non-bandlimited triangle
- * 3 non-bandlimited pulse wave (25% duty cycle)
- * 4 non-bandlimited square wave (50% duty cycle)
- * 5 non-bandlimited pulse wave (75% duty cycle)
- * 6 sine wave
- * cosine wave
- * 3 harmonic wave (1st, 5th, 9th harmonics)
- *
- * To inspect file, use soundeditor, a graphical waveform editor.
- * A bug in released versions of soundeditor yields a waveform
- * displayed upside down (display only) and clips the waveform values
- * exceeding range [-32000 .. 32000] (display only).
- *
- * Written by Gints Klimanis
- * Silicon Graphics Computer Systems
- * 1992
- *********************************************************************** */
- #include <stdio.h>
- #include <audio.h>
- #include <math.h>
- #include <stdlib.h>
- #include "audiofile.h"
-
- AFfilesetup newSetUp;
- AFfilehandle sourceFile;
-
- double *cycle;
- double *sineTable;
- short *output;
- int numWaves;
- int waveLength = 4096;
-
- /* a single cycle of waveform can contain up to (length of cycle in samples)/2
- harmonics without aliasing. However, when changing the playback rate of the
- waveforms to output various pitches, the high frequencies cause noticable
- aliasing and jitter noise.
- */
- #define MAX_HARMONICS 200
- double amplitudes[MAX_HARMONICS];
- double phases[MAX_HARMONICS];
-
- double initialAmplitude = 32767.0;
- double samplingRate = 44100.0;
- char sourceFileName[1000];
-
- double pi, twoPi;
-
- #define FALSE 0
- #define TRUE 1
-
- /****************************************************************
- * DoublesToShorts: convert input buffer of DOUBLE to output buffer
- * of SHORT. Saturate option to 16-bits.
- *****************************************************************/
- void
- DoublesToShorts(double *in, short *out, long length, int saturate)
- /* in: base address of input data file
- out: base address of output data file
- length: length of data file
- saturate: if TRUE, perform saturation */
- {
- register long i;
- register double *source = in;
- register short *destination = out;
- register double value;
- register double ceiling = 32767.0;
- register double floor = -32768.0;
-
- /* convert buffer without saturation */
- if (saturate == FALSE)
- {
- for (i = length; --i >= 0;)
- *destination++ = (short) *source++;
- }
- /* convert buffer w/saturation to short range [-32768..32767] */
- else
- {
- for (i = length; --i >= 0; destination++)
- {
- value = *source++;
- if (value > ceiling)
- *destination = 32767;
- else if (value < floor)
- *destination = -32768;
- else
- *destination = (short) value;
- }
- }
- } /* ------------------ end DoublesToShorts() --------------- */
- /****************************************************************
- * ClearDoubles: fill buffer w/zero-valued DOUBLEs
- *****************************************************************/
- void
- ClearDoubles(double *in, long length)
- /* in: base address of input data file
- length: length of data file */
- {
- register long i;
- register double zeroValue = 0.0; /* zero valued register */
- register double *ptr = in; /* just some ptr */
-
- /* clear buffer */
- for (i = length; --i >= 0;)
- *ptr++ = zeroValue;
- } /* ------------------ end ClearDoubles() --------------- */
-
- /*
- * GenerateSawtoothCycle: generate single cycle, non-bandlimited
- * sawtooth wave.
- * -------------------------------------------------------------------- */
- void
- GenerateSawtoothCycle(double *sampleBase, int waveLength)
- {
- int i;
- double arg, argInc;
-
- /*
- * compute sawtooth wave. This process generates a wave of all harmonics
- * w/amplitude proportional to 1/harmonic #.
- */
- arg = 32767.0;
- argInc = 2.0*arg/((double) waveLength);
- for (i = 0; i < waveLength; i++, arg -= argInc)
- {
- sampleBase[i] = arg;
- }
- } /* ----------------------- end GenerateSawtoothCycle() --------------------- */
-
- /*
- * GenerateTriangleCycle: generate single cycle, non-bandlimited
- * triangle wave.
- * -------------------------------------------------------------------- */
- void
- GenerateTriangleCycle(double *waveMemory, int waveLength)
- {
- int i;
- double arg, argInc;
-
- /*
- * compute triangle wave. This process generates a wave w/odd harmonics only
- * w/amplitude proportional to 1/(harmonic # squared).
- */
- arg = -32767.0;
- argInc = 4.0*32767.0/((double) waveLength);
- /* do positive slope portion */
- for (i = 0; (i < waveLength)&&(arg <= 32767.0); i++, arg += argInc)
- waveMemory[i] = (double) arg;
-
- /* do negative slope portion */
- arg = 2.0*32767.0 - arg; /* mirror xtra back into range */
- for (; i < waveLength; i++, arg -= argInc)
- waveMemory[i] = (double) arg;
- } /* ----------------------- end GenerateTriangleCycle() --------------------- */
-
- /*
- * GeneratePulseCycle: generate non-bandlimited pulse wave of specified duty cycle.
- * -------------------------------------------------------------------- */
- void
- GeneratePulseCycle(double *waveMemory, int waveLength, double dutyCycle)
- {
- int i;
- int dutyCycleEnd;
-
- /* check for valid duty cycle Range: 1..waveLength-1 */
- dutyCycleEnd = dutyCycle*((double) waveLength);
- if ((dutyCycleEnd <= 0)||(dutyCycle >= waveLength))
- {
- fprintf(stderr, "GeneratePulseCycle(): bogus duty cycle: %f. No wave, dude\n",
- dutyCycle);
- return;
- }
- /* Here, duty cycle is percentage of wavelength signal positive.
- * Duty cycle specifies the harmonic relationships. A pulse function in the
- * time domain transforms into a sin(x)/x or sinc(x) function in the
- * frequency domain. The value of the sinc function will determine the
- * amplitude of the harmonics.
- *
- * A square wave (duty cycle 50%) is member of the pulse wave family. Just
- * so happens that the frequency domain sinc function for the square wave
- * is zero at every even harmonic. Thus, a square wave contains odd only
- * harmonics whose amplitudes are 1/harmonic #.
- *
- * A pulse wave of 33% duty cycle is missing every third harmonic.
- * A pulse wave of 25% duty cycle is missing every fourth harmonic.
- * And so on, and so on. However, the present harmonics don't have a
- * simple 1/harmonic # amplitude relationship. Need to examin the sinc function.
- * Very small and very large duty cycles have a nasal quality.
- *
- * A traditional method for producing ballsy sounds from a single oscillator
- * is to modulate the duty cycle. This can be done by computing 400 or so
- * pulse waves w/increasing duty cycles and cycling through this list of
- * waves in a forward backward manner. THIS IS TERMED PULSE WIDTH MODULATION.
- * The more samples are in your wave, the thinner your thinnest pulse can be.
- *
- * The modulation rate is determined by the rate at which the pulse widths change.
- * This is determined by the rate at which the pulse wave set is stepped
- * thru and the number of different pulse waves in the set.
- */
- /* do duty cycle portion */
- for (i = 0; i < dutyCycleEnd; i++)
- waveMemory[i] = 32767.0;
-
- /* do off portion */
- for (; i < waveLength; i++)
- waveMemory[i] = -32767.0;
- } /* ----------------------- end GeneratePulseCycle() --------------------- */
-
- /*
- * GenerateCycle: generate general wave as sum of of sines of specified
- * waveLength.
- * -------------------------------------------------------------------- */
- void
- GenerateCycle(double *waveMemory, int waveLength, double amplitudes[],
- double phases[], double sineTable[])
- {
- int i, j;
- int someNumber;
- int sineIndex, sineIncrement;
- double maxValue, someDouble;
- double *wave;
-
- /* allocate and clear temporary wave memory */
- wave = (double *) malloc(waveLength*sizeof(double));
- if (wave == NULL)
- {
- fprintf(stderr,"GenerateCycle(): failed to allocate intermediate memory. No wave, dude.\n");
- return;
- }
- ClearDoubles(wave, waveLength);
-
- /* generate wave w/specified harmonics at specified amplitudes and phases */
- i = 1;
- while (amplitudes[i] != -1.0)
- {
- if (amplitudes[i] != 0.0)
- {
- /* phase specified in radians. Convert to nearest sample */
- /* convert to phase in terms of fraction of a cycle */
- someDouble = phases[i];
- someDouble /= twoPi;
- /* extract fractional part */
- someDouble -= (double)((int) someDouble);
- /* convert phase to table index */
- someDouble *= (double) (waveLength-1);
- sineIndex = (int) someDouble;
- for (j = 0; j < waveLength; j++)
- {
- wave[j] += amplitudes[i]*sineTable[sineIndex];
- sineIndex += i;
- /* bound sine table index to actual table */
- if (sineIndex >= waveLength)
- sineIndex -= waveLength;
- }
- }
- i++;
- }
-
- /* find largest absolute value in wave */
- maxValue = 0.0;
- for (i = 0; i < waveLength; i++)
- {
- someDouble = wave[i];
- if (someDouble < 0.0)
- someDouble = -someDouble;
- if (someDouble > maxValue)
- maxValue = someDouble;
- }
-
- /* write into sample memory. Product is fit in range -32768..32767 */
- maxValue = 32767.0/maxValue; /* normalization factor */
- for (i = 0; i < waveLength; i++)
- waveMemory[i] = (double) (maxValue*wave[i]);
-
- if (wave != NULL)
- free(wave);
- } /* ----------------------- end GenerateCycle() --------------------- */
-
- /*
- * main()
- * -------------------------------------------------------------------- */
- main(int argc, char **argv)
- {
- int i, j;
- long n2write, nwrote;
- double arg, argInc;
- int maxHarmonics;
-
- /* compute some pi */
- pi = 4.0*atan(1.0);
- twoPi = 2.0*pi;
-
- /* allocate buffers */
- cycle = (double *) malloc(waveLength*sizeof(double));
- output = (short *) malloc(waveLength*sizeof(short));
- if ((cycle == NULL)||(output == NULL))
- {
- fprintf(stderr, "main(): couldn't allocate signal buffers. Exiting ...\n");
- exit(-1);
- }
-
- /* allocate memory for sine table, intermediate storage and final product */
- sineTable = (double *) malloc(waveLength*sizeof(double));
- if (sineTable == NULL)
- {
- fprintf(stderr,"main(): failed to allocate sineTable. No wave, dude.\n");
- exit(-1);
- }
- /* generate single cycle of sine */
- argInc = (8.0*atan(1.0))/((double) waveLength); /* 2*PI/wavelength */
- arg = 0.0;
- for (i = 0; i < waveLength; i++, arg += argInc)
- sineTable[i] = sin(arg);
-
- /*
- * initialize setup structure for new file
- */
- strcpy(sourceFileName, "tableNet.aifc");
- newSetUp = AFnewfilesetup();
- /* init # of channels and sampling rate */
- AFinitchannels(newSetUp, AF_DEFAULT_TRACK, 1);
- AFinitrate(newSetUp, AF_DEFAULT_TRACK, samplingRate);
-
- /* open new file */
- sourceFile = AFopenfile(sourceFileName, "w", newSetUp);
- if (sourceFile == AF_NULL_FILEHANDLE)
- {
- fprintf(stderr, "couldn't open %s\n", sourceFileName);
- exit(1);
- }
-
- /*
- * generate waveform table
- */
- fprintf(stderr, "wave table generation initiated for '%s'.\n", sourceFileName);
- /* wave 0: sawtooth */
- GenerateSawtoothCycle(cycle, waveLength);
- /* write converted data to file */
- DoublesToShorts(cycle, output, waveLength, TRUE);
- nwrote = AFwriteframes(sourceFile, AF_DEFAULT_TRACK, output, waveLength);
-
- /* wave 1: triangle wave */
- GenerateTriangleCycle(cycle, waveLength);
- /* write converted data to file */
- DoublesToShorts(cycle, output, waveLength, TRUE);
- nwrote = AFwriteframes(sourceFile, AF_DEFAULT_TRACK, output, waveLength);
-
- /* wave 2: pulse wave of 25% duty cycle*/
- GeneratePulseCycle(cycle, waveLength, 0.25);
- /* write converted data to file */
- DoublesToShorts(cycle, output, waveLength, TRUE);
- nwrote = AFwriteframes(sourceFile, AF_DEFAULT_TRACK, output, waveLength);
-
- /* wave 3: square wave */
- GeneratePulseCycle(cycle, waveLength, 0.50);
- /* write converted data to file */
- DoublesToShorts(cycle, output, waveLength, TRUE);
- nwrote = AFwriteframes(sourceFile, AF_DEFAULT_TRACK, output, waveLength);
-
- /* wave 4: pulse wave of 75% duty cycle */
- GeneratePulseCycle(cycle, waveLength, 0.75);
- /* write converted data to file */
- DoublesToShorts(cycle, output, waveLength, TRUE);
- nwrote = AFwriteframes(sourceFile, AF_DEFAULT_TRACK, output, waveLength);
-
- /* wave 5: sine wave*/
- ClearDoubles(amplitudes, MAX_HARMONICS);
- ClearDoubles(phases, MAX_HARMONICS);
- amplitudes[1] = 1.0;
- phases[1] = 0.0;
- amplitudes[2] = -1.0;
- GenerateCycle(cycle, waveLength, amplitudes, phases, sineTable);
- /* write converted data to file */
- DoublesToShorts(cycle, output, waveLength, TRUE);
- nwrote = AFwriteframes(sourceFile, AF_DEFAULT_TRACK, output, waveLength);
-
- /* wave 6: cosine wave */
- ClearDoubles(amplitudes, MAX_HARMONICS);
- ClearDoubles(phases, MAX_HARMONICS);
- amplitudes[1] = 1.0;
- phases[1] = pi/2.0;
- amplitudes[2] = -1.0;
- GenerateCycle(cycle, waveLength, amplitudes, phases, sineTable);
- /* write converted data to file */
- DoublesToShorts(cycle, output, waveLength, TRUE);
- nwrote = AFwriteframes(sourceFile, AF_DEFAULT_TRACK, output, waveLength);
-
- /* wave 7 */
- ClearDoubles(amplitudes, MAX_HARMONICS);
- ClearDoubles(phases, MAX_HARMONICS);
- amplitudes[1] = 1.0;
- amplitudes[5] = 1.0/5.0;
- amplitudes[9] = 1.0/9.0;
- amplitudes[10] = -1.0;
- GenerateCycle(cycle, waveLength, amplitudes, phases, sineTable);
- /* write converted data to file */
- DoublesToShorts(cycle, output, waveLength, TRUE);
- nwrote = AFwriteframes(sourceFile, AF_DEFAULT_TRACK, output, waveLength);
-
- /* close source file */
- AFclosefile(sourceFile);
-
- /* deallocate buffers */
- if (cycle != NULL)
- free(cycle);
- if (output != NULL)
- free(output);
- }
-
-