2 * Sonitus - SampleOutputStream.java - Copyright © 2013 David Roden
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package net.pterodactylus.sonitus.io;
20 import java.io.FilterOutputStream;
21 import java.io.IOException;
22 import java.io.OutputStream;
25 * {@link OutputStream} wrapper that is aware of channels and samples and can
26 * process samples before forwarding them to the wrapped output stream.
28 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
30 public abstract class ProcessingOutputStream extends FilterOutputStream {
32 /** The number of channels. */
33 private final int channels;
35 /** The current sample’s channel values. */
36 private int[] currentSamples;
38 /** The index of the current channel. */
39 private int currentSampleIndex;
41 /** The byte ofset of the current sample’s current channel. */
42 private int currentOffset;
44 /** The current sample’s channel value. */
45 private int currentSample;
48 * Creates a new processing output stream. Sample values are always assumed to
49 * be 16 bits wide little-ending signed integers.
52 * The output stream to wrap
54 * The number of channels
56 public ProcessingOutputStream(OutputStream outputStream, int channels) {
58 this.channels = channels;
59 currentSamples = new int[channels];
63 // OUTPUTSTREAM METHODS
67 public void write(int data) throws IOException {
68 currentSample = ((currentSample >> 8) & 0xff) | (data << 8);
69 if (++currentOffset == 2) {
71 currentSamples[currentSampleIndex++] = currentSample;
73 if (currentSampleIndex == channels) {
74 currentSampleIndex = 0;
75 int[] newSamples = processSamples(currentSamples);
76 for (int sampleIndex = 0; sampleIndex < newSamples.length; ++sampleIndex) {
77 super.write(newSamples[sampleIndex] & 0xff);
78 super.write(newSamples[sampleIndex] >> 8);
85 public void write(byte[] buffer) throws IOException {
86 write(buffer, 0, buffer.length);
90 public void write(byte[] buffer, int offset, int length) throws IOException {
91 for (int index = 0; index < length; ++index) {
92 write(buffer[offset + index]);
101 * Processes the given sample.
104 * The channel values for a single sample
105 * @return The processed sample’s channel values
107 protected abstract int[] processSamples(int[] samples);