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;
037:
038: public abstract class AbstractAudio {
039:
040: // Size of buffer used throughout the code
041: public static final int SAMPLEBUFFERSIZE = 7500;
042:
043: // AbstractAudio device types
044: public static final int ALLTYPES = -1;
045: public static final int NOTYPE = 0;
046: public static final int SOURCE = 1;
047: public static final int PROCESSOR = 2;
048: public static final int MONITOR = 3;
049: public static final int SINK = 4;
050:
051: // Class data
052: public AbstractAudio previous;
053: public AbstractAudio next;
054: private String name;
055: private int type;
056: private int samplingRate;
057: private int numberOfChannels;
058: private boolean samplingRateFrozen;
059: private boolean numberOfChannelsFrozen;
060: private boolean byPass;
061:
062: /**
063: * AbstractAudio class constructor
064: *
065: * NOTE: name and type are for informational purposes only and
066: * serve to identify a specific device.
067: *
068: * @param String name is the name given to this device
069: * @param int type is one of the device types listed above
070: */
071: public AbstractAudio(String name, int type) {
072:
073: // Save incoming
074: this .name = name;
075: this .type = type;
076:
077: // Do various initialization
078: previous = null;
079: next = null;
080:
081: samplingRate = 0;
082: numberOfChannels = 0;
083:
084: samplingRateFrozen = false;
085: numberOfChannelsFrozen = false;
086:
087: byPass = false;
088:
089: }
090:
091: /**
092: * Static method for displaying a type string given the device type
093: *
094: * @param int type is the type of this AbstractAudio device
095: */
096: public static String typeString(int type) {
097:
098: switch (type) {
099:
100: case NOTYPE:
101: return "No Type";
102:
103: case SOURCE:
104: return "Source";
105:
106: case PROCESSOR:
107: return "Processor";
108:
109: case MONITOR:
110: return "Monitor";
111:
112: case SINK:
113: return "Sink";
114: }
115: return "Unknown type";
116:
117: }
118:
119: /**
120: * Convert AbstractAudio parameters to a string for display
121: *
122: * @return String containing description of this device
123: */
124: public String toString() {
125: String retString = "<AbstractAudio: " + name;
126: retString += " Type: " + typeString(type);
127: retString += " Rate: " + samplingRate;
128: retString += " Channels: " + numberOfChannels;
129: retString += " Bypass: " + byPass + ">\n";
130:
131: return retString;
132:
133: }
134:
135: /**
136: * Function to determine if one AbstractAudio device is the
137: * same as another. Equality is assumed if name and type match. This
138: * method is used in the LinkedListVector class to find specific
139: * devices on the list.
140: *
141: * @return boolean true if the name and type match, false otherwise.
142: */
143: public boolean equals(AbstractAudio a) {
144:
145: return (name.equals(a.getName()) && (type == a.type));
146:
147: }
148:
149: /**
150: * Return the name of this AbstractAudio device
151: *
152: * @return String containing device's assigned name
153: */
154: public String getName() {
155:
156: return name;
157:
158: }
159:
160: /**
161: * This method must be iplemented by all devices that extend
162: * the AbstractAudio class. This is the method by which audio
163: * samples are moved between device stages. Call the getSamples()
164: * method on the device previous to this device in the signal path
165: * causes samples to be pull from it.
166: *
167: * @param short [] buffer is a buffer that this stage of processing
168: * should fill with data for subsequent return to calling code.
169: * @param int length is the number of samples that are requested
170: *
171: * @return int indicating the number of samples available or -1 if
172: * the end of input or file has been reached.
173: */
174: public abstract int getSamples(short[] buffer, int length);
175:
176: /**
177: * Return the current by pass state of this device.
178: *
179: * @return boolean true if this stage of processing is bypassed and
180: * false otherwise.
181: */
182: public boolean getByPass() {
183:
184: return byPass;
185:
186: }
187:
188: /**
189: * Used to set the bypass state of this device
190: *
191: * @param boolean byPass if true stage will be bypassed.
192: */
193: public void setByPass(boolean byPass) {
194:
195: this .byPass = byPass;
196:
197: }
198:
199: /**
200: * Retrieve the sample rate of the signal path. If not already
201: * set, this call with instigate negotiation.
202: *
203: * @return int containing the agreed upon sample rate
204: */
205: public int getSamplingRate() {
206:
207: if (!samplingRateFrozen) // Not frozen?
208: negotiateSamplingRate(); // Go figure it out
209:
210: return samplingRate; // Return sampling rate
211:
212: }
213:
214: /**
215: * Sets the sample rate for this device if possible
216: *
217: * @param int s is the sample rate to set
218: */
219: protected void setSamplingRate(int s) {
220:
221: if (samplingRateFrozen) {
222: System.out.println("Can't change sampling rate");
223: System.exit(1);
224: }
225: samplingRate = s;
226:
227: }
228:
229: /**
230: * Called to instigate sample rate negotiation in the signal chain
231: * of AbstractAudio device.
232: * First it causes propagation towards the sink in the signal chain.
233: * Next, the default sample rate values are set and the negotiation
234: * is begun by a call to minMaxSamplingRate. Upon return from
235: * negotiation, some checking is done to see that the negotiated rate
236: * is acceptable and then setSamplingRateRecursive is called to force
237: * the agreed upon sample rate into each of the AbstractAudio devices
238: * in the signal chain.
239: */
240: protected void negotiateSamplingRate() {
241:
242: if (next != null) // Are we right most?
243: next.negotiateSamplingRate(); // No, propagate to the right
244: else { // Yes, we are
245: // Set reasonable defaults
246: int min = 11025;
247: int max = 44100;
248: int preferred = 11025;
249:
250: // Get the real values
251: minMaxSamplingRate(min, max, preferred);
252: if (min > max) { // Check for bogus values
253: System.out.println("Couldn't negotiate sampling rate");
254: System.exit(1);
255: }
256: setSamplingRateRecursive(preferred); // Set them everywhere
257: }
258:
259: }
260:
261: /**
262: * Called to find the min, preferred and max values for sample rate
263: * the devices in the signal path find acceptable.
264: *
265: * @param MyInt min is the wrapped minimum value of sampling rate
266: * this signal path can tolerate.
267: * @param MyInt max is the wrapped maximum value of sampling rate
268: * this signal path can tolerate.
269: * @param MyInt preferred is the wrapped sampling rate value this
270: * signal path prefers.
271: */
272: public void minMaxSamplingRate(int min, int max, int preferred) {
273:
274: // Propagate call until first device in chain is located
275: if (previous != null)
276: previous.minMaxSamplingRate(min, max, preferred);
277:
278: // Get current values
279: int this min = min;
280: int this max = max;
281: int this preferred = preferred;
282:
283: // Does this stage have a sampling rate preference?
284: if (samplingRate != 0) {
285: this preferred = samplingRate;
286: preferred = samplingRate;
287: }
288:
289: // Is the preferred value below the lower bound?
290: if (this preferred < this min)
291: preferred = this min;
292:
293: // Is the preferred value above the upper bound?
294: if (this preferred > this max)
295: preferred = this max;
296:
297: }
298:
299: /**
300: * Causes all the device stages to have their sampling rate set
301: * to the specified value.
302: *
303: * @param int sr is the sampling rate that was negotiated and needs
304: * therefore to be set into each stage.
305: */
306: public void setSamplingRateRecursive(int sr) {
307:
308: if (previous != null) // Are we left most?
309: previous.setSamplingRateRecursive(sr);
310:
311: setSamplingRate(sr); // Set it
312: samplingRateFrozen = true; // Yes, we've negotiated
313:
314: }
315:
316: /**
317: * Retrieve the number of channel of the signal path. If not already
318: * set, this call with instigate negotiation.
319: *
320: * @return int containing the agreed upon number of channels
321: */
322: public int getNumberOfChannels() {
323:
324: if (!numberOfChannelsFrozen)
325: negotiateNumberOfChannels();
326:
327: return numberOfChannels;
328:
329: }
330:
331: /**
332: * Sets the number of channels for this device if possible
333: *
334: * @param int channels is the number of channels to set
335: */
336: protected void setNumberOfChannels(int channels) {
337:
338: if (numberOfChannelsFrozen) {
339: System.out.println("Can't change number of channels");
340: System.exit(1);
341: }
342: numberOfChannels = channels;
343:
344: }
345:
346: /**
347: * Called to instigate number of channel negotiation in the signal chain
348: * of AbstractAudio device.
349: * First it causes propagation towards the sink in the signal chain.
350: * Next, the default number of channels value is set and the negotiation
351: * is begun by a call to minMaxChannels. Upon return from
352: * negotiation, some checking is done to see that the negotiated channels
353: * is acceptable and then setChannelsRecursive is called to force
354: * the agreed upon number of channels into each of the AbstractAudio devices
355: * in the signal chain.
356: */
357: protected void negotiateNumberOfChannels() {
358:
359: if (next != null) // Are we right most device?
360: next.negotiateNumberOfChannels(); // Move towards the right
361: else {
362: // Set default values
363: int min = 1;
364: int max = 2;
365: int preferred = 1;
366:
367: // Negotiate for the real values
368: minMaxChannels(min, max, preferred);
369: if (min > max) {
370: System.out.println("Couldn't negotiate channels");
371: System.exit(1);
372: }
373: setChannelsRecursive(preferred);
374: }
375:
376: }
377:
378: /**
379: * Called to find the min, preferred and max values for the number
380: * of channels the devices in the signal path find acceptable.
381: *
382: * @param MyInt min is the wrapped minimum number of channels
383: * this signal path can tolerate.
384: * @param MyInt max is the wrapped maximum number of channels
385: * this signal path can tolerate.
386: * @param MyInt preferred is the wrapped number of channels this
387: * signal path prefers.
388: */
389: public void minMaxChannels(int min, int max, int preferred) {
390:
391: // Propagate call towards the source
392: if (previous != null)
393: previous.minMaxChannels(min, max, preferred);
394:
395: // If this stage has a channel preference, set it
396: if (numberOfChannels != 0)
397: preferred = numberOfChannels;
398:
399: // Get the parameters from previous stages
400: int currentMin = min;
401: int currentMax = max;
402: int currentPreferred = preferred;
403:
404: // Force preferred value to be within min, max range
405: if (currentPreferred < currentMin)
406: preferred = currentMin;
407:
408: if (currentPreferred > currentMax)
409: preferred = currentMax;
410:
411: }
412:
413: /**
414: * Called to force the specified number of channels to be used
415: * in the device chain. This causes a propagation towards the source
416: * in the signal chain and then on return sets the number of channels
417: * variable in each stage of the chain.
418: *
419: * @param int ch is the number of channels to set either 1 for mono or
420: * 2 for stereo.
421: */
422: public void setChannelsRecursive(int ch) {
423:
424: // Propagate call towards source
425: if (previous != null)
426: previous.setChannelsRecursive(ch);
427:
428: // Set negotiated channels and indicate negotiation complete
429: numberOfChannels = ch;
430: numberOfChannelsFrozen = true;
431:
432: }
433:
434: /**
435: * Override this method if reset functionality is required
436: * for your AbstractAudio device derivative. If not overridden
437: * nothing will happen in this device when a reset operation
438: * occurs.
439: */
440: protected void reset() {
441: }
442:
443: /**
444: * Propagate reset call to all processing stages
445: */
446: protected void propagateReset() {
447:
448: if (previous != null)
449: previous.propagateReset();
450:
451: // Call reset on this stage of processing
452: reset();
453:
454: }
455:
456: /**
457: * Called to perform a reset operation on all participating device
458: * stages.
459: */
460: public void doReset() {
461:
462: // Propagate reset towards sink then towards source
463: if (next != null)
464: next.doReset();
465: else
466: propagateReset();
467:
468: }
469:
470: /**
471: * Hex string display method
472: *
473: * @param int i is the value to convert to a hex string
474: */
475: public void hexo(int i) {
476:
477: System.out.println(Long.toHexString(i));
478:
479: }
480:
481: /**
482: * Labeled hex string display method
483: *
484: * @param String s is the label to prepend to the hex string
485: * @param int i is the value to convert to a hex string
486: */
487: public void hexo(String s, int i) {
488:
489: System.out.println(s + Long.toHexString(i));
490:
491: }
492:
493: /**
494: * Hex string display method
495: *
496: * @param long i is the value to convert to a hex string
497: */
498: public static void hexo(long i) {
499:
500: System.out.println(Long.toHexString(i));
501:
502: }
503:
504: /**
505: * Labeled hex string display method
506: *
507: * @param String s is the label to prepend to the hex string
508: * @param long i is the value to convert to a hex string
509: */
510: public static void hexo(String s, long i) {
511:
512: System.out.println(s + Long.toHexString(i));
513:
514: }
515:
516: /**
517: * Shortcut method for system.out.println
518: *
519: * @param String s is the string to write to standard out
520: */
521: public static void o(String s) {
522:
523: System.out.println(s);
524:
525: }
526:
527: }
|