View Javadoc

1   package net.sf.jack4j.util;
2   
3   /*
4   Copyright (C) 2008 Ondrej Par
5   
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10  
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU Lesser General Public License for more details.
15  
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  
20  */
21  
22  import java.nio.ByteBuffer;
23  
24  /**
25   * Converts samples stored in WAVE file to <code>float</code> and vice-versa.
26   * 
27   * @author repa
28   * 
29   */
30  public abstract class IntSampleConverter {
31  
32  	private static final IntSampleConverter[] converters = { new IntSampleConverter8BitUnsigned(),
33  	        new IntSampleConverter16BitSignedLittleEndian(), new IntSampleConverter24BitSignedLittleEndian(),
34  	        new IntSampleConverter32BitSignedLittleEndian() };
35  
36  	private final static class IntSampleConverter8BitUnsigned extends IntSampleConverter {
37  
38  		@Override
39  		public int bytesPerSample() {
40  			return 1;
41  		}
42  
43  		@Override
44  		public void floatToIntSample(float sample, ByteBuffer byteBuffer) {
45  			int value = (int) (sample * 127 + 128);
46  
47  			byteBuffer.put((byte) value);
48  		}
49  
50  		@Override
51  		public float intSampleToFloat(ByteBuffer byteBuffer) {
52  			return (byteBuffer.get() - 128) / 128.0f;
53  		}
54  
55  		@Override
56  		public boolean isBigEndian() {
57  			// doesn't really matter for 8 bits
58  			return false;
59  		}
60  
61  		@Override
62  		public boolean isSigned() {
63  			return false;
64  		}
65  
66  	}
67  
68  	private final static class IntSampleConverter16BitSignedLittleEndian extends IntSampleConverter {
69  
70  		@Override
71  		public int bytesPerSample() {
72  			return 2;
73  		}
74  
75  		@Override
76  		public void floatToIntSample(float sample, ByteBuffer byteBuffer) {
77  			int value = (int) (sample * 0x8000);
78  			byteBuffer.put((byte) (value & 0xff));
79  			byteBuffer.put((byte) ((value >> 8) & 0xff));
80  		}
81  
82  		@Override
83  		public float intSampleToFloat(ByteBuffer byteBuffer) {
84  			int intValue = ((byteBuffer.get() & 0xff) | (byteBuffer.get() << 8));
85  			return ((float) intValue) / 0x8000;
86  		}
87  
88  		@Override
89  		public boolean isBigEndian() {
90  			return false;
91  		}
92  
93  		@Override
94  		public boolean isSigned() {
95  			return true;
96  		}
97  
98  	}
99  
100 	private final static class IntSampleConverter24BitSignedLittleEndian extends IntSampleConverter {
101 
102 		@Override
103 		public int bytesPerSample() {
104 			return 3;
105 		}
106 
107 		@Override
108 		public void floatToIntSample(float sample, ByteBuffer byteBuffer) {
109 			int value = (int) (sample * 0x800000);
110 			byteBuffer.put((byte) (value & 0xff));
111 			byteBuffer.put((byte) ((value >> 8) & 0xff));
112 			byteBuffer.put((byte) ((value >> 16) & 0xff));
113 		}
114 
115 		@Override
116 		public float intSampleToFloat(ByteBuffer byteBuffer) {
117 			int intValue = ((byteBuffer.get() & 0xff) | (byteBuffer.get() << 8) | (byteBuffer.get() << 16));
118 			return ((float) intValue) / 0x800000;
119 		}
120 
121 		@Override
122 		public boolean isBigEndian() {
123 			return false;
124 		}
125 
126 		@Override
127 		public boolean isSigned() {
128 			return true;
129 		}
130 
131 	}
132 
133 	private final static class IntSampleConverter32BitSignedLittleEndian extends IntSampleConverter {
134 
135 		@Override
136 		public int bytesPerSample() {
137 			return 4;
138 		}
139 
140 		@Override
141 		public void floatToIntSample(float sample, ByteBuffer byteBuffer) {
142 			int value = (int) (sample * 0x80000000);
143 			byteBuffer.put((byte) (value & 0xff));
144 			byteBuffer.put((byte) ((value >> 8) & 0xff));
145 			byteBuffer.put((byte) ((value >> 16) & 0xff));
146 			byteBuffer.put((byte) ((value >> 24) & 0xff));
147 		}
148 
149 		@Override
150 		public float intSampleToFloat(ByteBuffer byteBuffer) {
151 			int intValue = ((byteBuffer.get() & 0xff) | (byteBuffer.get() << 8) | (byteBuffer.get() << 16) | (byteBuffer
152 			        .get() << 24));
153 			return ((float) intValue) / 0x80000000;
154 		}
155 
156 		@Override
157 		public boolean isBigEndian() {
158 			return false;
159 		}
160 
161 		@Override
162 		public boolean isSigned() {
163 			return true;
164 		}
165 
166 	}
167 
168 	public static IntSampleConverter createIntSampleConverter(int bitsPerSample, boolean signed, boolean bigEndian) {
169 		if ((bitsPerSample <= 0) || (bitsPerSample > 32)) {
170 			throw new IllegalArgumentException();
171 		}
172 
173 		int bytesPerSample = (bitsPerSample / 8) + (((bitsPerSample % 8) == 0) ? 0 : 1);
174 
175 		for (IntSampleConverter converter : converters) {
176 			if ((bytesPerSample == converter.bytesPerSample()) && (signed == converter.isSigned())
177 			        && ((bytesPerSample == 1) || (bigEndian == converter.isBigEndian()))) {
178 				return converter;
179 			}
180 		}
181 
182 		throw new IllegalArgumentException();
183 	}
184 
185 	public abstract int bytesPerSample();
186 
187 	public abstract boolean isSigned();
188 
189 	public abstract boolean isBigEndian();
190 
191 	public abstract void floatToIntSample(float sample, ByteBuffer byteBuffer);
192 
193 	public abstract float intSampleToFloat(ByteBuffer byteBuffer);
194 }