www in docker support
This commit is contained in:
parent
539a848e95
commit
c227fce036
2145 changed files with 399596 additions and 58 deletions
|
|
@ -0,0 +1,78 @@
|
|||
package org.jcodec.audio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
public class Audio {
|
||||
public static void transfer(AudioSource src, AudioSink sink) throws IOException {
|
||||
filterTransfer(src, new DummyFilter(1), sink);
|
||||
}
|
||||
|
||||
public static void filterTransfer(AudioSource src, AudioFilter filter, AudioSink sink) throws IOException {
|
||||
if (filter.getNInputs() != 1)
|
||||
throw new IllegalArgumentException("Audio filter has # inputs != 1");
|
||||
if (filter.getNOutputs() != 1)
|
||||
throw new IllegalArgumentException("Audio filter has # outputs != 1");
|
||||
if (filter.getDelay() != 0)
|
||||
throw new IllegalArgumentException("Audio filter has delay");
|
||||
FloatBuffer[] ins = { FloatBuffer.allocate(4096) };
|
||||
FloatBuffer[] outs = { FloatBuffer.allocate(8192) };
|
||||
long[] pos = new long[1];
|
||||
while (src.readFloat(ins[0]) != -1) {
|
||||
ins[0].flip();
|
||||
filter.filter(ins, pos, outs);
|
||||
pos[0] = pos[0] + (long)ins[0].position();
|
||||
rotate(ins[0]);
|
||||
outs[0].flip();
|
||||
sink.writeFloat(outs[0]);
|
||||
outs[0].clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static void print(FloatBuffer buf) {
|
||||
FloatBuffer dup = buf.duplicate();
|
||||
while (dup.hasRemaining())
|
||||
System.out.print(String.format("%.3f,", dup.get()));
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
public static void rotate(FloatBuffer buf) {
|
||||
int pos;
|
||||
for (pos = 0; buf.hasRemaining(); pos++)
|
||||
buf.put(pos, buf.get());
|
||||
buf.position(pos);
|
||||
buf.limit(buf.capacity());
|
||||
}
|
||||
|
||||
public static class DummyFilter implements AudioFilter {
|
||||
private int nInputs;
|
||||
|
||||
public DummyFilter(int nInputs) {
|
||||
this.nInputs = nInputs;
|
||||
}
|
||||
|
||||
public void filter(FloatBuffer[] _in, long[] inPos, FloatBuffer[] out) {
|
||||
for (int i = 0; i < _in.length; i++) {
|
||||
if (out[i].remaining() >= _in[i].remaining()) {
|
||||
out[i].put(_in[i]);
|
||||
} else {
|
||||
FloatBuffer duplicate = _in[i].duplicate();
|
||||
duplicate.limit(_in[i].position() + out[i].remaining());
|
||||
out[i].put(duplicate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getDelay() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getNInputs() {
|
||||
return this.nInputs;
|
||||
}
|
||||
|
||||
public int getNOutputs() {
|
||||
return this.nInputs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package org.jcodec.audio;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
public interface AudioFilter {
|
||||
void filter(FloatBuffer[] paramArrayOfFloatBuffer1, long[] paramArrayOflong, FloatBuffer[] paramArrayOfFloatBuffer2);
|
||||
|
||||
int getDelay();
|
||||
|
||||
int getNInputs();
|
||||
|
||||
int getNOutputs();
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package org.jcodec.audio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
public interface AudioSink {
|
||||
void writeFloat(FloatBuffer paramFloatBuffer) throws IOException;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package org.jcodec.audio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.FloatBuffer;
|
||||
import org.jcodec.common.AudioFormat;
|
||||
|
||||
public interface AudioSource {
|
||||
AudioFormat getFormat();
|
||||
|
||||
int readFloat(FloatBuffer paramFloatBuffer) throws IOException;
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package org.jcodec.audio;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
import org.jcodec.common.AudioFormat;
|
||||
import org.jcodec.common.Preconditions;
|
||||
|
||||
public class ChannelMerge implements AudioFilter {
|
||||
private AudioFormat format;
|
||||
|
||||
public ChannelMerge(AudioFormat format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public void filter(FloatBuffer[] _in, long[] inPos, FloatBuffer[] out) {
|
||||
if (_in.length != this.format.getChannels())
|
||||
throw new IllegalArgumentException("Channel merge must be supplied with " + this.format.getChannels() + " input buffers to hold the channels.");
|
||||
if (out.length != 1)
|
||||
throw new IllegalArgumentException("Channel merget invoked on more then one output");
|
||||
FloatBuffer out0 = out[0];
|
||||
int min = Integer.MAX_VALUE;
|
||||
for (int k = 0; k < _in.length; k++) {
|
||||
if (_in[k].remaining() < min)
|
||||
min = _in[k].remaining();
|
||||
}
|
||||
for (int j = 0; j < _in.length; j++)
|
||||
Preconditions.checkState((_in[j].remaining() == min));
|
||||
if (out0.remaining() < min * _in.length)
|
||||
throw new IllegalArgumentException("Supplied output buffer is not big enough to hold " + min + " * " + _in.length + " = " + min * _in.length + " output samples.");
|
||||
for (int i = 0; i < min; i++) {
|
||||
for (int m = 0; m < _in.length; m++)
|
||||
out0.put(_in[m].get());
|
||||
}
|
||||
}
|
||||
|
||||
public int getDelay() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getNInputs() {
|
||||
return this.format.getChannels();
|
||||
}
|
||||
|
||||
public int getNOutputs() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package org.jcodec.audio;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
import org.jcodec.common.AudioFormat;
|
||||
|
||||
public class ChannelSplit implements AudioFilter {
|
||||
private AudioFormat format;
|
||||
|
||||
public ChannelSplit(AudioFormat format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public void filter(FloatBuffer[] _in, long[] inPos, FloatBuffer[] out) {
|
||||
if (_in.length != 1)
|
||||
throw new IllegalArgumentException("Channel split invoked on more then one input");
|
||||
if (out.length != this.format.getChannels())
|
||||
throw new IllegalArgumentException("Channel split must be supplied with " + this.format.getChannels() + " output buffers to hold the channels.");
|
||||
FloatBuffer in0 = _in[0];
|
||||
int outSampleCount = in0.remaining() / out.length;
|
||||
for (int i = 0; i < out.length; i++) {
|
||||
if (out[i].remaining() < outSampleCount)
|
||||
throw new IllegalArgumentException("Supplied buffer for " + i + "th channel doesn't have sufficient space to put the samples ( required: " + outSampleCount + ", actual: " + out[i]
|
||||
|
||||
.remaining() + ")");
|
||||
}
|
||||
while (in0.remaining() >= this.format.getChannels()) {
|
||||
for (int j = 0; j < out.length; j++)
|
||||
out[j].put(in0.get());
|
||||
}
|
||||
}
|
||||
|
||||
public int getDelay() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getNInputs() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int getNOutputs() {
|
||||
return this.format.getChannels();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package org.jcodec.audio;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
public abstract class ConvolutionFilter implements AudioFilter {
|
||||
private double[] kernel;
|
||||
|
||||
protected abstract double[] buildKernel();
|
||||
|
||||
public void filter(FloatBuffer[] _in, long[] pos, FloatBuffer[] out) {
|
||||
if (_in.length != 1)
|
||||
throw new IllegalArgumentException(getClass().getName() + " filter is designed to work only on one input");
|
||||
if (out.length != 1)
|
||||
throw new IllegalArgumentException(getClass().getName() + " filter is designed to work only on one output");
|
||||
FloatBuffer in0 = _in[0];
|
||||
FloatBuffer out0 = out[0];
|
||||
if (this.kernel == null)
|
||||
this.kernel = buildKernel();
|
||||
if (out0.remaining() < in0.remaining() - this.kernel.length)
|
||||
throw new IllegalArgumentException("Output buffer is too small");
|
||||
if (in0.remaining() <= this.kernel.length)
|
||||
throw new IllegalArgumentException("Input buffer should contain > kernel lenght (" + this.kernel.length + ") samples.");
|
||||
int halfKernel = this.kernel.length / 2;
|
||||
int i;
|
||||
for (i = in0.position() + halfKernel; i < in0.limit() - halfKernel; i++) {
|
||||
double result = 0.0D;
|
||||
for (int j = 0; j < this.kernel.length; j++)
|
||||
result += this.kernel[j] * (double)in0.get(i + j - halfKernel);
|
||||
out0.put((float)result);
|
||||
}
|
||||
in0.position(i - halfKernel);
|
||||
}
|
||||
|
||||
public int getDelay() {
|
||||
if (this.kernel == null)
|
||||
this.kernel = buildKernel();
|
||||
return this.kernel.length / 2;
|
||||
}
|
||||
|
||||
public int getNInputs() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int getNOutputs() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
package org.jcodec.audio;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class FilterGraph implements AudioFilter {
|
||||
private FilterSocket[] sockets;
|
||||
|
||||
public static Factory addLevel(AudioFilter first) {
|
||||
return new Factory(first);
|
||||
}
|
||||
|
||||
public static class Factory {
|
||||
private List<FilterSocket> sockets = new ArrayList<>();
|
||||
|
||||
protected Factory(AudioFilter firstFilter) {
|
||||
if (firstFilter.getDelay() != 0) {
|
||||
this.sockets.add(FilterSocket.createFilterSocket(new Audio.DummyFilter[] { new Audio.DummyFilter(firstFilter.getNInputs()) }));
|
||||
addLevel(new AudioFilter[] { firstFilter });
|
||||
} else {
|
||||
this.sockets.add(FilterSocket.createFilterSocket(new AudioFilter[] { firstFilter }));
|
||||
}
|
||||
}
|
||||
|
||||
public Factory addLevel(AudioFilter[] filters) {
|
||||
FilterSocket socket = FilterSocket.createFilterSocket(filters);
|
||||
socket.allocateBuffers(4096);
|
||||
this.sockets.add(socket);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Factory addLevels(AudioFilter filter, int n) {
|
||||
AudioFilter[] filters = new AudioFilter[n];
|
||||
Arrays.fill(filters, filter);
|
||||
return addLevel(filters);
|
||||
}
|
||||
|
||||
public Factory addLevelSpan(AudioFilter filter) {
|
||||
int prevLevelOuts = this.sockets.get(this.sockets.size() - 1).getTotalOutputs();
|
||||
if (prevLevelOuts % filter.getNInputs() != 0)
|
||||
throw new IllegalArgumentException("Can't fill " + prevLevelOuts + " with multiple of " +
|
||||
filter.getNInputs());
|
||||
return addLevels(filter, prevLevelOuts / filter.getNInputs());
|
||||
}
|
||||
|
||||
public FilterGraph create() {
|
||||
return new FilterGraph(this.sockets.<FilterSocket>toArray(new FilterSocket[0]));
|
||||
}
|
||||
}
|
||||
|
||||
private FilterGraph(FilterSocket[] sockets) {
|
||||
this.sockets = sockets;
|
||||
}
|
||||
|
||||
public void filter(FloatBuffer[] ins, long[] pos, FloatBuffer[] outs) {
|
||||
this.sockets[0].setBuffers(ins, pos);
|
||||
for (int i = 0; i < this.sockets.length; i++) {
|
||||
FloatBuffer[] curOut = (i < this.sockets.length - 1) ? this.sockets[i + 1].getBuffers() : outs;
|
||||
this.sockets[i].filter(curOut);
|
||||
if (i > 0)
|
||||
this.sockets[i].rotate();
|
||||
if (i < this.sockets.length - 1)
|
||||
for (FloatBuffer b : curOut)
|
||||
b.flip();
|
||||
}
|
||||
}
|
||||
|
||||
public int getDelay() {
|
||||
return this.sockets[0].getFilters()[0].getDelay();
|
||||
}
|
||||
|
||||
public int getNInputs() {
|
||||
return this.sockets[0].getTotalInputs();
|
||||
}
|
||||
|
||||
public int getNOutputs() {
|
||||
return this.sockets[this.sockets.length - 1].getTotalOutputs();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
package org.jcodec.audio;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
import org.jcodec.platform.Platform;
|
||||
|
||||
public class FilterSocket {
|
||||
private FloatBuffer[] buffers;
|
||||
|
||||
private long[] positions;
|
||||
|
||||
private int[] delays;
|
||||
|
||||
private AudioFilter[] filters;
|
||||
|
||||
private int totalInputs;
|
||||
|
||||
private int totalOutputs;
|
||||
|
||||
public static FilterSocket createFilterSocket(AudioFilter[] filters) {
|
||||
FilterSocket fs = new FilterSocket();
|
||||
fs.totalInputs = 0;
|
||||
fs.totalOutputs = 0;
|
||||
for (int j = 0; j < filters.length; j++) {
|
||||
fs.totalInputs += filters[j].getNInputs();
|
||||
fs.totalOutputs += filters[j].getNOutputs();
|
||||
}
|
||||
fs.buffers = new FloatBuffer[fs.totalInputs];
|
||||
fs.positions = new long[fs.totalInputs];
|
||||
fs.delays = new int[fs.totalInputs];
|
||||
for (int i = 0, b = 0; i < filters.length; i++) {
|
||||
for (int k = 0; k < filters[i].getNInputs(); k++, b++)
|
||||
fs.delays[b] = filters[i].getDelay();
|
||||
}
|
||||
fs.filters = filters;
|
||||
return fs;
|
||||
}
|
||||
|
||||
public void allocateBuffers(int bufferSize) {
|
||||
for (int i = 0; i < this.totalInputs; i++) {
|
||||
this.buffers[i] = FloatBuffer.allocate(bufferSize + this.delays[i] * 2);
|
||||
this.buffers[i].position(this.delays[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static FilterSocket createFilterSocket2(AudioFilter filter, FloatBuffer[] buffers, long[] positions) {
|
||||
FilterSocket fs = new FilterSocket();
|
||||
fs.filters = new AudioFilter[] { filter };
|
||||
fs.buffers = buffers;
|
||||
fs.positions = positions;
|
||||
fs.delays = new int[] { filter.getDelay() };
|
||||
fs.totalInputs = filter.getNInputs();
|
||||
fs.totalOutputs = filter.getNOutputs();
|
||||
return fs;
|
||||
}
|
||||
|
||||
public void filter(FloatBuffer[] outputs) {
|
||||
if (outputs.length != this.totalOutputs)
|
||||
throw new IllegalArgumentException("Can not output to provided filter socket inputs != outputs (" + outputs.length + "!=" + this.totalOutputs + ")");
|
||||
for (int i = 0, ii = 0, oi = 0; i < this.filters.length; ii += this.filters[i].getNInputs(), oi += this.filters[i]
|
||||
.getNOutputs(), i++)
|
||||
this.filters[i].filter(Platform.<FloatBuffer>copyOfRangeO(this.buffers, ii, this.filters[i].getNInputs() + ii),
|
||||
Platform.copyOfRangeL(this.positions, ii, this.filters[i].getNInputs() + ii),
|
||||
Platform.<FloatBuffer>copyOfRangeO(outputs, oi, this.filters[i].getNOutputs() + oi));
|
||||
}
|
||||
|
||||
FloatBuffer[] getBuffers() {
|
||||
return this.buffers;
|
||||
}
|
||||
|
||||
public void rotate() {
|
||||
for (int i = 0; i < this.buffers.length; i++) {
|
||||
this.positions[i] = this.positions[i] + (long)this.buffers[i].position();
|
||||
Audio.rotate(this.buffers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void setBuffers(FloatBuffer[] ins, long[] pos) {
|
||||
if (ins.length != this.totalInputs)
|
||||
throw new IllegalArgumentException("Number of input buffers provided is less then the number of filter inputs.");
|
||||
if (pos.length != this.totalInputs)
|
||||
throw new IllegalArgumentException("Number of input buffer positions provided is less then the number of filter inputs.");
|
||||
this.buffers = ins;
|
||||
this.positions = pos;
|
||||
}
|
||||
|
||||
public int getTotalInputs() {
|
||||
return this.totalInputs;
|
||||
}
|
||||
|
||||
public int getTotalOutputs() {
|
||||
return this.totalOutputs;
|
||||
}
|
||||
|
||||
AudioFilter[] getFilters() {
|
||||
return this.filters;
|
||||
}
|
||||
|
||||
public long[] getPositions() {
|
||||
return this.positions;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package org.jcodec.audio;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
public class LanczosInterpolator implements AudioFilter {
|
||||
private double rateStep;
|
||||
|
||||
public static double lanczos(double x, int a) {
|
||||
return (x < (double)-a) ? 0.0D : ((x > (double)a) ? 0.0D : (
|
||||
(double)a * Math.sin(Math.PI * x) * Math.sin(Math.PI * x / (double)a) / (9.869604401089358D * x * x)));
|
||||
}
|
||||
|
||||
public LanczosInterpolator(int fromRate, int toRate) {
|
||||
this.rateStep = (double)fromRate / (double)toRate;
|
||||
}
|
||||
|
||||
public void filter(FloatBuffer[] _in, long[] pos, FloatBuffer[] out) {
|
||||
if (_in.length != 1)
|
||||
throw new IllegalArgumentException(getClass().getName() + " filter is designed to work only on one input");
|
||||
if (out.length != 1)
|
||||
throw new IllegalArgumentException(getClass().getName() + " filter is designed to work only on one output");
|
||||
FloatBuffer in0 = _in[0];
|
||||
FloatBuffer out0 = out[0];
|
||||
if ((double)out0.remaining() < (double)(in0.remaining() - 6) / this.rateStep)
|
||||
throw new IllegalArgumentException("Output buffer is too small");
|
||||
if (in0.remaining() <= 6)
|
||||
throw new IllegalArgumentException("Input buffer should contain > 6 samples.");
|
||||
for (int outSample = 0;; outSample++) {
|
||||
double inSample = 3.0D + (double)outSample * this.rateStep + Math.ceil((double)pos[0] / this.rateStep) * this.rateStep - (double)pos[0];
|
||||
int p0i = (int)Math.floor(inSample);
|
||||
int q0i = (int)Math.ceil(inSample);
|
||||
if (p0i >= in0.limit() - 3) {
|
||||
in0.position(p0i - 3);
|
||||
break;
|
||||
}
|
||||
double p0d = (double)p0i - inSample;
|
||||
if (p0d < -0.001D) {
|
||||
double q0d = (double)q0i - inSample;
|
||||
double p0c = lanczos(p0d, 3);
|
||||
double q0c = lanczos(q0d, 3);
|
||||
double p1c = lanczos(p0d - 1.0D, 3);
|
||||
double q1c = lanczos(q0d + 1.0D, 3);
|
||||
double p2c = lanczos(p0d - 2.0D, 3);
|
||||
double q2c = lanczos(q0d + 2.0D, 3);
|
||||
double factor = 1.0D / (p0c + p1c + p2c + q0c + q1c + q2c);
|
||||
out0.put(
|
||||
(float)(((double)in0.get(q0i) * q0c + (double)in0.get(q0i + 1) * q1c + (double)in0.get(q0i + 2) * q2c + (double)in0.get(p0i) * p0c + (double)in0.get(p0i - 1) * p1c + (double)in0.get(p0i - 2) * p2c) * factor));
|
||||
} else {
|
||||
out0.put(in0.get(p0i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getDelay() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
public int getNInputs() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int getNOutputs() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package org.jcodec.audio;
|
||||
|
||||
public class SincLowPassFilter extends ConvolutionFilter {
|
||||
private int kernelSize;
|
||||
|
||||
private double cutoffFreq;
|
||||
|
||||
public static SincLowPassFilter createSincLowPassFilter(double cutoffFreq) {
|
||||
return new SincLowPassFilter(40, cutoffFreq);
|
||||
}
|
||||
|
||||
public static SincLowPassFilter createSincLowPassFilter2(int cutoffFreq, int samplingRate) {
|
||||
return new SincLowPassFilter(40, (double)cutoffFreq / (double)samplingRate);
|
||||
}
|
||||
|
||||
public SincLowPassFilter(int kernelSize, double cutoffFreq) {
|
||||
this.kernelSize = kernelSize;
|
||||
this.cutoffFreq = cutoffFreq;
|
||||
}
|
||||
|
||||
protected double[] buildKernel() {
|
||||
double[] kernel = new double[this.kernelSize];
|
||||
double sum = 0.0D;
|
||||
for (int j = 0; j < this.kernelSize; j++) {
|
||||
int a = j - this.kernelSize / 2;
|
||||
if (a != 0) {
|
||||
kernel[j] = Math.sin(6.283185307179586D * this.cutoffFreq * (double)(j - this.kernelSize / 2)) / (double)(j - this.kernelSize / 2) * (0.54D - 0.46D *
|
||||
Math.cos(6.283185307179586D * (double)j / (double)this.kernelSize));
|
||||
} else {
|
||||
kernel[j] = 6.283185307179586D * this.cutoffFreq;
|
||||
}
|
||||
sum += kernel[j];
|
||||
}
|
||||
for (int i = 0; i < this.kernelSize; i++)
|
||||
kernel[i] = kernel[i] / sum;
|
||||
return kernel;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue