Skip to content

Commit

Permalink
Add java support
Browse files Browse the repository at this point in the history
  • Loading branch information
ShirasawaSama committed Dec 9, 2023
1 parent b5f65fc commit f1dfbcb
Show file tree
Hide file tree
Showing 5 changed files with 440 additions and 4 deletions.
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# EIMTimeStretchers [![Release](https://github.com/EchoInMirror/EIMTimeStretchers/actions/workflows/release.yml/badge.svg)](https://github.com/EchoInMirror/EIMTimeStretchers/actions/workflows/release.yml)
# EIMTimeStretchers [![Release](https://github.com/EchoInMirror/EIMTimeStretchers/actions/workflows/release.yml/badge.svg)](https://github.com/EchoInMirror/EIMTimeStretchers/actions/workflows/release.yml) [![Jitpack](https://www.jitpack.io/v/EchoInMirror/EIMTimeStretchers.svg)](https://www.jitpack.io/#EchoInMirror/EIMTimeStretchers)

A collection of time stretchers, FFT and resample algorithms for digital audio signals processing.

Expand All @@ -10,6 +10,27 @@ A collection of time stretchers, FFT and resample algorithms for digital audio s
- sleef (FFT, Windows only)
- libresample (Resample)

## Usage - Java

```groovy
repositories {
maven { url 'https://www.jitpack.io' }
}
dependencies {
implementation 'com.github.EchoInMirror:EIMTimeStretchers:<version>'
}
tasks.withType(JavaCompile).each {
it.options.compilerArgs.add('--enable-preview')
}
// kotlin script
// tasks.withType<JavaCompile> {
// options.compilerArgs = options.compilerArgs + listOf("--enable-preview")
// }
```

## Author

Shirasawa
Expand Down
27 changes: 25 additions & 2 deletions lib/library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,16 @@ EXPORT int fft_get_size(RubberBand::FFT *fft) {
}

char fftDefaultImplementation[256] = {0};
EXPORT const char* fft_get_default_implementation() {
EXPORT const char* fft_get_implementations() {
if (fftDefaultImplementation[0] == 0) {
strcpy(fftDefaultImplementation, RubberBand::FFT::getDefaultImplementation().c_str());
int i = 0;
for (auto& impl : RubberBand::FFT::getImplementations()) {
if (i > 0) {
strcat(fftDefaultImplementation, ",");
}
strcat(fftDefaultImplementation, impl.c_str());
i++;
}
}
return fftDefaultImplementation;
}
Expand Down Expand Up @@ -179,4 +186,20 @@ EXPORT double resampler_get_effective_ratio(RubberBand::Resampler *resampler, do
EXPORT void resampler_reset(RubberBand::Resampler *resampler) {
resampler->reset();
}

EXPORT const char* resampler_get_implementation() {
#ifdef HAVE_IPP
return "ipp";
#elifdef USE_SPEEX
return "speex";
#elifdef HAVE_LIBSPEEXDSP
return "speexdsp";
#elifdef USE_BQRESAMPLER
return "bqresampler";
#elifdef HAVE_LIBSAMPLERATE
return "libsamplerate";
#else
return "unknown";
#endif
}
}
227 changes: 227 additions & 0 deletions src/main/java/com/eimsound/dsp/timestretchers/NativeFFT.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
package com.eimsound.dsp.timestretchers;

import org.jetbrains.annotations.NotNull;

import java.lang.foreign.*;
import java.lang.invoke.MethodHandle;

@SuppressWarnings("unused")
public final class NativeFFT implements AutoCloseable {
private boolean isClosed = false;
private final Addressable pointer;

private static MethodHandle fft_init; // void* *fft_init(int fftSize)
private static MethodHandle fft_destroy; // void fft_destroy(void* *fft)
private static MethodHandle fft_forward; // void fft_forward(void* *fft, const float *realIn, float *realOut, float *imagOut)
private static MethodHandle fft_forward_interleaved; // void fft_forward_interleaved(void* *fft, const float *realIn, float *complexOut)
private static MethodHandle fft_forward_polar; // void fft_forward_polar(void* *fft, const float *realIn, float *magOut, float *phaseOut)
private static MethodHandle fft_forward_magnitude; // void fft_forward_magnitude(void* *fft, const float *realIn, float *magOut)
private static MethodHandle fft_inverse; // void fft_inverse(void* *fft, const float *realIn, const float *imagIn, float *realOut)
private static MethodHandle fft_inverse_interleaved; // void fft_inverse_interleaved(void* *fft, const float *complexIn, float *realOut)
private static MethodHandle fft_inverse_polar; // void fft_inverse_polar(void* *fft, const float *magIn, const float *phaseIn, float *realOut)
private static MethodHandle fft_inverse_cepstral; // void fft_inverse_cepstral(void* *fft, const float *magIn, float *cepOut)
private static MethodHandle fft_get_size; // int fft_get_size(void* *fft)
private static MethodHandle fft_get_default_implementation; // const char* fft_get_default_implementation()

private static void init() {
if (fft_init != null) return;
var lib = NativeLibrary.getLookup();
var linker = Linker.nativeLinker();
fft_init = linker.downcallHandle(
lib.lookup("fft_init").orElseThrow(),
FunctionDescriptor.of(
ValueLayout.ADDRESS,
ValueLayout.JAVA_INT
)
);
fft_destroy = linker.downcallHandle(
lib.lookup("fft_destroy").orElseThrow(),
FunctionDescriptor.ofVoid(
ValueLayout.ADDRESS
)
);
fft_forward = linker.downcallHandle(
lib.lookup("fft_forward").orElseThrow(),
FunctionDescriptor.ofVoid(
ValueLayout.ADDRESS,
ValueLayout.ADDRESS,
ValueLayout.ADDRESS,
ValueLayout.ADDRESS
)
);
fft_forward_interleaved = linker.downcallHandle(
lib.lookup("fft_forward_interleaved").orElseThrow(),
FunctionDescriptor.ofVoid(
ValueLayout.ADDRESS,
ValueLayout.ADDRESS,
ValueLayout.ADDRESS
)
);
fft_forward_polar = linker.downcallHandle(
lib.lookup("fft_forward_polar").orElseThrow(),
FunctionDescriptor.ofVoid(
ValueLayout.ADDRESS,
ValueLayout.ADDRESS,
ValueLayout.ADDRESS,
ValueLayout.ADDRESS
)
);
fft_forward_magnitude = linker.downcallHandle(
lib.lookup("fft_forward_magnitude").orElseThrow(),
FunctionDescriptor.ofVoid(
ValueLayout.ADDRESS,
ValueLayout.ADDRESS,
ValueLayout.ADDRESS
)
);
fft_inverse = linker.downcallHandle(
lib.lookup("fft_inverse").orElseThrow(),
FunctionDescriptor.ofVoid(
ValueLayout.ADDRESS,
ValueLayout.ADDRESS,
ValueLayout.ADDRESS,
ValueLayout.ADDRESS
)
);
fft_inverse_interleaved = linker.downcallHandle(
lib.lookup("fft_inverse_interleaved").orElseThrow(),
FunctionDescriptor.ofVoid(
ValueLayout.ADDRESS,
ValueLayout.ADDRESS,
ValueLayout.ADDRESS
)
);
fft_inverse_polar = linker.downcallHandle(
lib.lookup("fft_inverse_polar").orElseThrow(),
FunctionDescriptor.ofVoid(
ValueLayout.ADDRESS,
ValueLayout.ADDRESS,
ValueLayout.ADDRESS,
ValueLayout.ADDRESS
)
);
fft_inverse_cepstral = linker.downcallHandle(
lib.lookup("fft_inverse_cepstral").orElseThrow(),
FunctionDescriptor.ofVoid(
ValueLayout.ADDRESS,
ValueLayout.ADDRESS,
ValueLayout.ADDRESS
)
);
fft_get_size = linker.downcallHandle(
lib.lookup("fft_get_size").orElseThrow(),
FunctionDescriptor.of(
ValueLayout.JAVA_INT,
ValueLayout.ADDRESS
)
);
fft_get_default_implementation = linker.downcallHandle(
lib.lookup("fft_get_default_implementation").orElseThrow(),
FunctionDescriptor.of(
ValueLayout.ADDRESS
)
);
}

public NativeFFT(int fftSize) {
init();
try {
pointer = (MemoryAddress) fft_init.invokeExact(fftSize);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}

public void forward(@NotNull Addressable realIn, @NotNull Addressable realOut, @NotNull Addressable imagOut) {
try {
fft_forward.invokeExact(pointer, realIn, realOut, imagOut);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}

public void forwardInterleaved(@NotNull Addressable realIn, @NotNull Addressable complexOut) {
try {
fft_forward_interleaved.invokeExact(pointer, realIn, complexOut);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}

public void forwardPolar(@NotNull Addressable realIn, @NotNull Addressable magOut, @NotNull Addressable phaseOut) {
try {
fft_forward_polar.invokeExact(pointer, realIn, magOut, phaseOut);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}

public void forwardMagnitude(@NotNull Addressable realIn, @NotNull Addressable magOut) {
try {
fft_forward_magnitude.invokeExact(pointer, realIn, magOut);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}

public void inverse(@NotNull Addressable realIn, @NotNull Addressable imagIn, @NotNull Addressable realOut) {
try {
fft_inverse.invokeExact(pointer, realIn, imagIn, realOut);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}

public void inverseInterleaved(@NotNull Addressable complexIn, @NotNull Addressable realOut) {
try {
fft_inverse_interleaved.invokeExact(pointer, complexIn, realOut);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}

public void inversePolar(@NotNull Addressable magIn, @NotNull Addressable phaseIn, @NotNull Addressable realOut) {
try {
fft_inverse_polar.invokeExact(pointer, magIn, phaseIn, realOut);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}

public void inverseCepstral(@NotNull Addressable magIn, @NotNull Addressable cepOut) {
try {
fft_inverse_cepstral.invokeExact(pointer, magIn, cepOut);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}

public int getSize() {
try {
return (int) fft_get_size.invokeExact(pointer);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}

@NotNull
public static String getDefaultImplementation() {
init();
try {
return ((MemoryAddress) fft_get_default_implementation.invokeExact()).getUtf8String(0L);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}

@Override
public void close() {
if (isClosed) return;
isClosed = true;
try {
fft_destroy.invokeExact(pointer);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
Loading

0 comments on commit f1dfbcb

Please sign in to comment.