Skip to content

Commit 10d1e5c

Browse files
authored
Merge pull request #3 from sahaRatul/24bit-support
24bit support
2 parents 6b3a8d4 + 2ef0f9d commit 10d1e5c

19 files changed

+247
-65
lines changed

src/main/java/org/sela/App.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,12 @@ private static void parseCommandLineArgs(final String[] args)
3939
} else if (args[0].equals("-p") && args.length == 2) {
4040
final File inputFile = new File(args[1]);
4141
System.out.println("Playing: " + inputFile.getAbsolutePath());
42-
playFile(inputFile);
42+
playSelaFile(inputFile);
43+
System.out.println("");
44+
} else if(args[0].equals("-w") && args.length == 2) {
45+
final File inputFile = new File(args[1]);
46+
System.out.println("Playing: " + inputFile.getAbsolutePath());
47+
playWavFile(inputFile);
4348
System.out.println("");
4449
} else {
4550
System.out.println("Invalid arguments...");
@@ -61,11 +66,16 @@ private static void decodeFile(final File inputFile, final File outputFile) thro
6166
wavFile.writeToStream();
6267
}
6368

64-
private static void playFile(final File inputFile) throws IOException, FileException, LineUnavailableException, InterruptedException {
69+
private static void playSelaFile(final File inputFile) throws IOException, FileException, LineUnavailableException, InterruptedException {
6570
final Player selaPlayer = new Player(inputFile);
6671
selaPlayer.play();
6772
}
6873

74+
private static void playWavFile(final File inputFile) throws IOException, FileException, LineUnavailableException, InterruptedException {
75+
final WavPlayer wavPlayer = new WavPlayer(inputFile);
76+
wavPlayer.play();
77+
}
78+
6979
private static void printUsage() {
7080
System.out.println("");
7181
System.out.println("Usage:");
@@ -76,8 +86,11 @@ private static void printUsage() {
7686
System.out.println("Decoding a file:");
7787
System.out.println("java -jar sela.jar -d path/to/input.sela path/to/output.wav");
7888
System.out.println("");
79-
System.out.println("Playing a file:");
89+
System.out.println("Playing a sela file:");
8090
System.out.println("java -jar sela.jar -p path/to/input.sela");
8191
System.out.println("");
92+
System.out.println("Playing a sela file:");
93+
System.out.println("java -jar sela.jar -w path/to/input.wav");
94+
System.out.println("");
8295
}
8396
}

src/main/java/org/sela/Encoder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ private void readSamples() {
3232
for (int i = 0; i < frameCount; i++) {
3333
final int[][] samples = new int[wavFile.getNumChannels()][samplePerSubFrame];
3434
wavFile.readFrames(samples, samplePerSubFrame);
35-
wavFrames.add(new WavFrame(i, samples));
35+
wavFrames.add(new WavFrame(i, samples, (byte)wavFile.getBitsPerSample()));
3636
}
3737
}
3838

src/main/java/org/sela/Player.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ public void play() throws LineUnavailableException, InterruptedException {
4141
printThread.start();
4242

4343
// Output wave form repeatedly
44+
byte bytesPerSample = (byte) ((byte) decoder.selaFile.getBitsPerSample() / 8);
4445
for (int i = 0; i < wavFrames.size(); i++) {
45-
final byte[] bytes = wavFrames.get(i).getDemuxedShortSamplesInByteArray();
46+
final byte[] bytes = wavFrames.get(i).getDemuxedSamplesInByteArray(bytesPerSample);
4647
line.write(bytes, 0, bytes.length);
4748
progress.current++;
4849
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package org.sela;
2+
3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.util.ArrayList;
6+
import java.util.List;
7+
8+
import javax.sound.sampled.AudioFormat;
9+
import javax.sound.sampled.AudioSystem;
10+
import javax.sound.sampled.DataLine;
11+
import javax.sound.sampled.LineUnavailableException;
12+
import javax.sound.sampled.SourceDataLine;
13+
14+
import org.sela.data.Progress;
15+
import org.sela.data.WavFile;
16+
import org.sela.data.WavFrame;
17+
import org.sela.exception.FileException;
18+
import org.sela.utils.ProgressPrinter;
19+
20+
public class WavPlayer {
21+
private final WavFile wavFile;
22+
private List<WavFrame> wavFrames;
23+
private int frameCount;
24+
private final int samplePerSubFrame = 2048;
25+
26+
public WavPlayer(final File inputFile) throws IOException, FileException {
27+
wavFile = new WavFile(inputFile);
28+
}
29+
30+
private void readSamples() {
31+
final long sampleCount = wavFile.getSampleCount();
32+
frameCount = (int) Math.ceil((double) sampleCount / (samplePerSubFrame * wavFile.getNumChannels()));
33+
wavFrames = new ArrayList<>(frameCount);
34+
35+
for (int i = 0; i < frameCount; i++) {
36+
final int[][] samples = new int[wavFile.getNumChannels()][samplePerSubFrame];
37+
wavFile.readFrames(samples, samplePerSubFrame);
38+
wavFrames.add(new WavFrame(i, samples, (byte) wavFile.getBitsPerSample()));
39+
}
40+
}
41+
42+
public void play() throws LineUnavailableException, InterruptedException, FileException, IOException {
43+
readSamples();
44+
45+
// Select audio format parameters
46+
final AudioFormat af = new AudioFormat(wavFile.getSampleRate(), wavFile.getBitsPerSample(),
47+
wavFile.getNumChannels(), true, false);
48+
final DataLine.Info info = new DataLine.Info(SourceDataLine.class, af);
49+
final SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info);
50+
51+
// Prepare audio output
52+
line.open(af, 2048 * wavFile.getNumChannels());
53+
line.start();
54+
55+
// Prepare print thread
56+
final Progress progress = new Progress(wavFrames.size());
57+
final Thread printThread = new Thread(new ProgressPrinter(progress));
58+
printThread.start();
59+
60+
// Output wave form repeatedly
61+
byte bytesPerSample = (byte) ((byte) wavFile.getBitsPerSample() / 8);
62+
for (int i = 0; i < wavFrames.size(); i++) {
63+
final byte[] bytes = wavFrames.get(i).getDemuxedSamplesInByteArray(bytesPerSample);
64+
line.write(bytes, 0, bytes.length);
65+
progress.current++;
66+
}
67+
printThread.join();
68+
line.drain();
69+
line.stop();
70+
line.close();
71+
}
72+
}

src/main/java/org/sela/data/DataSubChunk.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,17 @@
44

55
public class DataSubChunk extends SubChunk {
66
public int[] samples;
7+
private final byte bitsPerSample;
8+
9+
public DataSubChunk(final byte bitsPerSample) {
10+
this.bitsPerSample = bitsPerSample;
11+
}
712

813
public void validate() throws FileException {
914
if(!super.subChunkId.equals("data")) {
1015
throw new FileException("Invalid subChunkId for data");
1116
}
12-
if(super.subChunkSize != (samples.length * 2)) {
17+
if(super.subChunkSize != (samples.length * (bitsPerSample / 8))) {
1318
throw new FileException("Invalid subChunkSize for data");
1419
}
1520
}

src/main/java/org/sela/data/FormatSubChunk.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,8 @@ public void validate() throws FileException {
1414
if(!super.subChunkId.equals("fmt ")) {
1515
throw new FileException("Invalid subChunkId for fmt");
1616
}
17-
else if(super.subChunkSize != 16) {
18-
throw new FileException("Invalid subChunk size");
19-
}
20-
else if(audioFormat != 1) {
21-
throw new FileException("Invalid audioFormat");
22-
}
2317
else if(bitsPerSample != 16) {
24-
throw new FileException("Only 16bit PCM supported");
18+
throw new FileException("Only 16bit LE PCM supported");
2519
}
2620
}
2721
}

src/main/java/org/sela/data/Frame.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,28 @@
66
public final class Frame implements Comparable<Frame> {
77
public final int syncWord = 0xAA55FF00;
88
public ArrayList<SubFrame> subFrames;
9+
private final byte bitsPerSample; //For internal reference, not to be written on output
910
private final int index; // For internal sorting, not to be written to output
1011

11-
public Frame(final ArrayList<SubFrame> subFrames, final int index) {
12+
public Frame(final ArrayList<SubFrame> subFrames, final byte bitsPerSample, final int index) {
1213
this.subFrames = subFrames;
14+
this.bitsPerSample = bitsPerSample;
1315
this.index = index;
1416
}
1517

16-
public Frame(final int index) {
18+
public Frame(final int index, final byte bitsPerSample) {
1719
this.index = index;
20+
this.bitsPerSample = bitsPerSample;
1821
}
1922

2023
public int getIndex() {
2124
return index;
2225
}
2326

27+
public byte getBitsPerSample() {
28+
return bitsPerSample;
29+
}
30+
2431
@Override
2532
public int compareTo(final Frame frame) {
2633
return this.index - frame.index;
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package org.sela.data;
22

33
public final class LpcDecodedData {
4-
public int[] samples;
4+
public final int[] samples;
5+
public final byte bitsPerSample;
56

6-
public LpcDecodedData(final int[] samples) {
7+
public LpcDecodedData(final int[] samples, final byte bitsPerSample) {
78
this.samples = samples;
9+
this.bitsPerSample = bitsPerSample;
810
}
911
}

src/main/java/org/sela/data/LpcEncodedData.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package org.sela.data;
22

33
public final class LpcEncodedData {
4-
public byte optimalLpcOrder;
5-
public int[] quantizedReflectionCoefficients;
6-
public int[] residues;
4+
public final byte optimalLpcOrder;
5+
public final byte bitsPerSample;
6+
public final int[] quantizedReflectionCoefficients;
7+
public final int[] residues;
78

8-
public LpcEncodedData(final byte optimalLpcOrder, final int[] quantizedReflectionCoefficients,
9+
public LpcEncodedData(final byte optimalLpcOrder, final byte bitsPerSample, final int[] quantizedReflectionCoefficients,
910
final int[] residues) {
1011
this.optimalLpcOrder = optimalLpcOrder;
12+
this.bitsPerSample = bitsPerSample;
1113
this.quantizedReflectionCoefficients = quantizedReflectionCoefficients;
1214
this.residues = residues;
1315
}

src/main/java/org/sela/data/SelaFile.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ private void read(final ByteBuffer buffer) throws FileException {
7171
if (sync != 0xAA55FF00) {
7272
break;
7373
}
74-
final Frame frame = new Frame(i);
74+
final Frame frame = new Frame(i, (byte)bitsPerSample);
7575
frame.subFrames = new ArrayList<>(2);
7676

7777
// Read subframes

0 commit comments

Comments
 (0)