001: /*
002: * Copyright (c) 2000 Silvere Martin-Michiellot All Rights Reserved.
003: *
004: * Silvere Martin-Michiellot grants you ("Licensee") a non-exclusive,
005: * royalty free, license to use, modify and redistribute this
006: * software in source and binary code form,
007: * provided that i) this copyright notice and license appear on all copies of
008: * the software; and ii) Licensee does not utilize the software in a manner
009: * which is disparaging to Silvere Martin-Michiellot.
010: *
011: * This software is provided "AS IS," without a warranty of any kind. ALL
012: * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
013: * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
014: * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. Silvere Martin-Michiellot
015: * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES
016: * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
017: * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
018: * Silvere Martin-Michiellot OR ITS LICENSORS BE LIABLE
019: * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
020: * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
021: * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
022: * OR INABILITY TO USE SOFTWARE, EVEN IF Silvere Martin-Michiellot HAS BEEN
023: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
024: *
025: * This software is not designed or intended for use in on-line control of
026: * aircraft, air traffic, aircraft navigation or aircraft communications; or in
027: * the design, construction, operation or maintenance of any nuclear
028: * facility. Licensee represents and warrants that it will not use or
029: * redistribute the Software for such purposes.
030: *
031: */
032:
033: // This code is repackaged after the code from Craig A. Lindley, from Digital Audio with Java
034: // Site ftp://ftp.prenhall.com/pub/ptr/professional_computer_science.w-022/digital_audio/
035: // Email
036: package com.db.media.audio.dsp.sources;
037:
038: import java.util.Random;
039:
040: // NOTE: 16 bit PCM data has a min value of -32768 (8000H)
041: // and a max value of 32767 (7FFFFH).
042:
043: public class Oscillator extends AbstractAudio {
044:
045: public static final int NOTYPE = 0;
046: public static final int NOISE = 1;
047: public static final int SINEWAVE = 2;
048: public static final int TRIANGLEWAVE = 3;
049: public static final int SQUAREWAVE = 4;
050:
051: // Class data
052: protected int type;
053: protected int frequency;
054: protected int sampleRate;
055: protected int numberOfChannels;
056: protected NegotiationListener negComplete;
057: protected int pos;
058: protected short[] waveTable;
059: protected double amplitudeAdj;
060:
061: public Oscillator(int type, int frequency, int sampleRate,
062: int numberOfChannels, NegotiationListener negComplete) {
063:
064: super ("Oscillator", AbstractAudio.SOURCE);
065:
066: // Save incoming
067: this .type = type;
068: this .frequency = frequency;
069: this .sampleRate = sampleRate;
070: this .numberOfChannels = numberOfChannels;
071: this .negComplete = negComplete;
072:
073: // Set amplitude adjustment
074: amplitudeAdj = 1.0;
075:
076: // Table of samples for oscillator waveform
077: waveTable = null;
078:
079: // Generate wave table
080: buildWaveTable();
081:
082: }
083:
084: // Constructor with reasonable defaults
085: public Oscillator(NegotiationListener negComplete) {
086:
087: this (SINEWAVE, 1000, 22050, 1, negComplete);
088:
089: }
090:
091: public int getOscType() {
092:
093: return type;
094:
095: }
096:
097: public void setOscType(int type) {
098:
099: this .type = type;
100:
101: buildWaveTable();
102:
103: }
104:
105: public int getFrequency() {
106:
107: return frequency;
108:
109: }
110:
111: public void setFrequency(int frequency) {
112:
113: this .frequency = frequency;
114:
115: // Reset waveTable index
116: pos = 0;
117:
118: }
119:
120: public int getSampleRate() {
121:
122: return sampleRate;
123:
124: }
125:
126: public void setSampleRate(int sampleRate) {
127:
128: this .sampleRate = sampleRate;
129:
130: buildWaveTable();
131:
132: }
133:
134: public int getNumberOfChannels() {
135:
136: return numberOfChannels;
137:
138: }
139:
140: public void setNumberOfChannels(int numberOfChannels) {
141:
142: this .numberOfChannels = numberOfChannels;
143:
144: }
145:
146: public double getAmplitudeAdj() {
147:
148: return amplitudeAdj;
149:
150: }
151:
152: public void setAmplitudeAdj(double amplitudeAdj) {
153:
154: this .amplitudeAdj = amplitudeAdj;
155:
156: }
157:
158: // Generate a wavetable for the waveform
159: protected void buildWaveTable() {
160:
161: if (type == NOTYPE)
162: return;
163:
164: // Initialize waveTable index as wave table is changing
165: pos = 0;
166:
167: // Allocate a table for 1 cycle of waveform
168: waveTable = new short[sampleRate];
169:
170: switch (type) {
171: case NOISE:
172: // Create a random number generator for returning gaussian
173: // distributed numbers. The result is white noise.
174: Random random = new Random();
175:
176: for (int sample = 0; sample < sampleRate; sample++)
177: waveTable[sample] = (short) ((65535.0 * random
178: .nextGaussian()) - 32768);
179: break;
180:
181: case SINEWAVE:
182: double scale = (2.0 * Math.PI) / sampleRate;
183:
184: for (int sample = 0; sample < sampleRate; sample++)
185: waveTable[sample] = (short) (32767.0 * Math.sin(sample
186: * scale));
187:
188: break;
189:
190: case TRIANGLEWAVE:
191: double sign = 1.0;
192: double value = 0.0;
193:
194: int oneQuarterWave = sampleRate / 4;
195: int threeQuarterWave = (3 * sampleRate) / 4;
196:
197: scale = 32767.0 / oneQuarterWave;
198:
199: for (int sample = 0; sample < sampleRate; sample++) {
200:
201: if ((sample > oneQuarterWave)
202: && (sample <= threeQuarterWave))
203: sign = -1.0;
204: else
205: sign = 1.0;
206:
207: value += sign * scale;
208: waveTable[sample] = (short) value;
209: }
210: break;
211:
212: case SQUAREWAVE:
213: for (int sample = 0; sample < sampleRate; sample++) {
214: if (sample < sampleRate / 2)
215: waveTable[sample] = 32767;
216: else
217: waveTable[sample] = -32768;
218: }
219: break;
220: }
221:
222: }
223:
224: public int getSamples(short[] buffer, int length) {
225:
226: int sample = 0;
227: int count = length;
228:
229: while (count-- != 0) {
230:
231: buffer[sample++] = (short) (amplitudeAdj * waveTable[pos]);
232:
233: pos += frequency;
234: if (pos >= sampleRate)
235: pos -= sampleRate;
236: }
237:
238: return length;
239:
240: }
241:
242: // We know this is first device in chain so no propagation
243: // is necessary.
244: public void minMaxSamplingRate(int min, int max, int preferred) {
245:
246: // Use the sample rate passed in
247: max = sampleRate;
248: min = sampleRate;
249: preferred = sampleRate;
250:
251: // Determine if there is a listener interested in whether
252: // negotations have been completed or not.
253: if (negComplete != null)
254: negComplete.negotiationCompletedEvent();
255:
256: }
257:
258: public void minMaxChannels(int min, int max, int preferred) {
259:
260: min = numberOfChannels;
261: max = numberOfChannels;
262: preferred = numberOfChannels;
263:
264: }
265:
266: }
|