/*
* Copyright (c) 2008, 2009, 2010 Denis Tulskiy
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with this work. If not, see <http://www.gnu.org/licenses/>.
*/
package com.tulskiy.musique.audio.formats.wavpack;
import com.tulskiy.musique.audio.Encoder;
import com.tulskiy.musique.system.configuration.Configuration;
import com.tulskiy.musique.util.Util;
import com.wavpack.encoder.Defines;
import com.wavpack.encoder.WavPackUtils;
import com.wavpack.encoder.WavpackConfig;
import com.wavpack.encoder.WavpackContext;
import javax.sound.sampled.AudioFormat;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Author: Denis Tulskiy
* Date: Jul 25, 2010
*/
public class WavPackEncoder implements Encoder {
private WavpackContext wpc;
private long[] sample_buffer;
private int totalSamples;
@Override
public boolean open(File outputFile, AudioFormat fmt, Configuration options) {
wpc = new WavpackContext();
WavpackConfig config = wpc.config;
try {
wpc.outfile = new RandomAccessFile(outputFile, "rw");
wpc.outfile.setLength(0);
if (options != null) {
if (options.getBoolean("encoder.wavpack.hybrid.enable", false)) {
float bitrate = options.getFloat("encoder.wavpack.hybrid.bitrate", -1);
config.flags |= Defines.CONFIG_HYBRID_FLAG;
config.bitrate = (int) (bitrate * 256);
if (options.getBoolean("encoder.wavpack.hybrid.wvc.enabled", true)) {
config.flags |= Defines.CONFIG_CREATE_WVC;
File wvc = new File(Util.removeExt(
outputFile.getAbsolutePath()) + ".wvc");
wpc.correction_outfile = new RandomAccessFile(wvc, "rw");
wpc.correction_outfile.setLength(0);
if (options.getBoolean("encoder.wavpack.hybrid.wvc.optimize", false)) {
config.flags |= Defines.CONFIG_OPTIMIZE_WVC;
}
}
float noiseShape = options.getFloat("encoder.wavpack.hybrid.noiseShape", 0);
config.shaping_weight = (int) (noiseShape * 1024.0);
if (config.shaping_weight == 0) {
config.flags |= Defines.CONFIG_SHAPE_OVERRIDE;
config.flags &= ~Defines.CONFIG_HYBRID_SHAPE;
} else if ((config.shaping_weight >= -1024) && (config.shaping_weight <= 1024)) {
config.flags |= (Defines.CONFIG_HYBRID_SHAPE |
Defines.CONFIG_SHAPE_OVERRIDE);
}
}
String mode = options.getString("encoder.wavpack.mode", null);
if ("fast".equals(mode)) {
config.flags |= Defines.CONFIG_FAST_FLAG;
} else if ("high".equals(mode)) {
config.flags |= Defines.CONFIG_HIGH_FLAG;
} else if ("very high".equals(mode)) {
config.flags |= Defines.CONFIG_VERY_HIGH_FLAG;
}
}
config.bytes_per_sample = fmt.getSampleSizeInBits() / 8;
config.bits_per_sample = fmt.getSampleSizeInBits();
config.num_channels = fmt.getChannels();
config.sample_rate = (long) fmt.getSampleRate();
WavPackUtils.WavpackSetConfiguration(wpc, config, -1);
WavPackUtils.WavpackPackInit(wpc);
sample_buffer = new long[(Defines.INPUT_SAMPLES * 4 * fmt.getChannels())];
totalSamples = 0;
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
@Override
public void encode(byte[] buf, int len) {
int loopBps = WavPackUtils.WavpackGetBytesPerSample(wpc);
int sample_count = len / loopBps / 2;
totalSamples += sample_count;
int cnt = sample_count * WavPackUtils.WavpackGetNumChannels(wpc);
if (loopBps == 1) {
int intermalCount = 0;
while (cnt > 0) {
sample_buffer[intermalCount] = (buf[intermalCount] & 0xff) - 128;
intermalCount++;
cnt--;
}
} else if (loopBps == 2) {
int dcounter = 0;
int scounter = 0;
while (cnt > 0) {
sample_buffer[dcounter] = (buf[scounter] & 0xff) | (buf[scounter + 1] << 8);
scounter = scounter + 2;
dcounter++;
cnt--;
}
} else if (loopBps == 3) {
int dcounter = 0;
int scounter = 0;
while (cnt > 0) {
sample_buffer[dcounter] = (buf[scounter] & 0xff) |
((buf[scounter + 1] & 0xff) << 8) | (buf[scounter + 2] << 16);
scounter = scounter + 3;
dcounter++;
cnt--;
}
}
wpc.byte_idx = 0;
WavPackUtils.WavpackPackSamples(wpc, sample_buffer, sample_count);
}
@Override
public void close() {
try {
WavPackUtils.WavpackFlushSamples(wpc);
fixLength(wpc.outfile);
wpc.outfile.close();
if (wpc.correction_outfile != null) {
fixLength(wpc.correction_outfile);
wpc.correction_outfile.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void fixLength(RandomAccessFile file) throws IOException {
ByteBuffer buf = ByteBuffer.allocate(4);
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.putInt(totalSamples);
file.seek(12);
file.write(buf.array());
}
}