Jogamp
40c39e7558570bf1b3e275fed98a2b16230e6c81
[jogl.git] / src / jogl / classes / com / jogamp / javafx / audio / windows / waveout / Track.java
1 /*
2  * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
3  * 
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  * 
8  * - Redistribution of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * 
11  * - Redistribution in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in the
13  *   documentation and/or other materials provided with the distribution.
14  * 
15  * Neither the name of Sun Microsystems, Inc. or the names of
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  * 
19  * This software is provided "AS IS," without a warranty of any kind. ALL
20  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
23  * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
24  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
25  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
26  * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
27  * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
28  * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
29  * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
30  * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  */
32
33 package com.jogamp.javafx.audio.windows.waveout;
34
35 import java.io.*;
36 import java.nio.*;
37
38 public class Track {
39     // Default number of samples per buffer
40     private static final int BUFFER_SIZE = 32768;
41     // Number of bytes per sample (FIXME: dependence on audio format)
42     static final int BYTES_PER_SAMPLE = 2;
43     // Whether we need byte swapping (FIXME: dependence on audio format)
44     static final boolean NEEDS_BYTE_SWAP = true;
45
46     // This is the buffer this track is currently playing from
47     private SoundBuffer activeBuffer;
48     // This is the sample position in the active buffer
49     private int samplePosition;
50     // This is the total number of samples in the file
51     private int totalSamples;
52     // This is the total number of samples we have read
53     private int samplesRead;
54     // This is the buffer that the background filler thread may be filling
55     private SoundBuffer fillingBuffer;
56     // If we're playing the file, this is its input stream
57     private InputStream input;
58     // Keep around the file name
59     private File file;
60     // Whether we're playing this sound
61     private boolean playing;
62     // Whether we're looping this sound
63     private boolean looping;
64     // The position of this sound; defaults to being at the origin
65     private volatile Vec3f position = new Vec3f();
66
67     Track(File file) throws IOException {
68         if (!file.getName().endsWith(".rawsound")) {
69             throw new IOException("Unsupported file format (currently supports only raw sounds)");
70         }
71
72         this.file = file;
73         openInput();
74
75         // Allocate the buffers
76         activeBuffer  = new SoundBuffer(BUFFER_SIZE, BYTES_PER_SAMPLE, NEEDS_BYTE_SWAP);
77         fillingBuffer = new SoundBuffer(BUFFER_SIZE, BYTES_PER_SAMPLE, NEEDS_BYTE_SWAP);
78
79         // Fill the first buffer immediately
80         fill();
81         swapBuffers();
82     }
83
84     private void openInput() throws IOException {
85         input = new BufferedInputStream(new FileInputStream(file));
86         totalSamples = (int) file.length() / BYTES_PER_SAMPLE;
87     }
88
89     public File getFile() {
90         return file;
91     }
92
93     public synchronized void play() {
94         if (input == null) {
95             try {
96                 openInput();
97                 // Fill it immediately
98                 fill();
99             } catch (IOException e) {
100                 e.printStackTrace();
101                 return;
102             }
103         }
104
105         playing = true;
106     }
107
108     public synchronized boolean isPlaying() {
109         return playing;
110     }
111
112     public synchronized void setLooping(boolean looping) {
113         this.looping = looping;
114     }
115
116     public synchronized boolean isLooping() {
117         return looping;
118     }
119
120     public void setPosition(float x, float y, float z) {
121         position = new Vec3f(x, y, z);
122     }
123
124     synchronized void fill() throws IOException {
125         if (input == null) {
126             return;
127         }
128         SoundBuffer curBuffer = fillingBuffer;
129         if (!curBuffer.empty()) {
130             return;
131         }
132         curBuffer.fill(input);
133         if (curBuffer.empty()) {
134             // End of file
135             InputStream tmp = null;
136             synchronized(this) {
137                 tmp = input;
138                 input = null;
139             }
140             tmp.close();
141
142             // If looping, re-open
143             if (isLooping()) {
144                 openInput();
145                 // and fill
146                 fill();
147             }
148         }
149     }
150
151     // These are only for use by the Mixer
152     private float leftGain;
153     private float rightGain;
154     
155     void setLeftGain(float leftGain) {
156         this.leftGain = leftGain;
157     }
158
159     float getLeftGain() {
160         return leftGain;
161     }
162
163     void setRightGain(float rightGain) {
164         this.rightGain = rightGain;
165     }
166
167     float getRightGain() {
168         return rightGain;
169     }
170
171     Vec3f getPosition() {
172         return position;
173     }
174
175     // This is called by the mixer and must be extremely fast
176     // Note this assumes mono sounds (FIXME)
177     boolean hasNextSample() {
178         return (!activeBuffer.empty() && samplePosition < activeBuffer.numSamples());
179     }
180
181     // This is called by the mixer and must be extremely fast
182     float nextSample() {
183         float res = activeBuffer.getSample(samplePosition++);
184         ++samplesRead;
185         if (!hasNextSample()) {
186             swapBuffers();
187             samplePosition = 0;
188             if (done()) {
189                 playing = false;
190             }
191         }
192         return res;
193     }
194
195     synchronized void swapBuffers() {
196         SoundBuffer tmp = activeBuffer;
197         activeBuffer = fillingBuffer;
198         fillingBuffer = tmp;
199         fillingBuffer.empty(true);
200     }
201
202     // This provides a more robust termination condition
203     boolean done() {
204         return (samplesRead == totalSamples) && !looping;
205     }
206 }
http://JogAmp.org git info: FAQ, tutorial and man pages.