Skip to content

Commit

Permalink
feat(root): use checksums to prevent unnecessary transfers of IR, DDC…
Browse files Browse the repository at this point in the history
…, EEL, or GraphicEQ data to the engine
  • Loading branch information
timschneeb committed Sep 9, 2023
1 parent c2118b0 commit ee76fa2
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 25 deletions.
35 changes: 27 additions & 8 deletions app/src/main/cpp/libjdspimptoolbox/main/JdspImpResToolbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdint.h>

#include <jdsp_header.h>

Expand All @@ -11,11 +12,27 @@ void channel_splitFloat(float *buffer, unsigned int num_frames, float **chan_buf
for (i = 0; i < samples; i++)
chan_buffers[i % num_channels][i / num_channels] = buffer[i];
}
void channel_joinFloat(float **chan_buffers, unsigned int num_channels, float *buffer, unsigned int num_frames)
int32_t channel_joinFloat_crc(float **chan_buffers, unsigned int num_channels, float *buffer, unsigned int num_frames)
{
unsigned int i, samples = num_frames * num_channels;
for (i = 0; i < samples; i++)
buffer[i] = chan_buffers[i % num_channels][i / num_channels];
unsigned int i, samples = num_frames * num_channels;
union
{
int32_t raw;
float f;
} fltInt;
int32_t crc = 0xFFFFFFFF;
for (i = 0; i < samples; i++)
{
buffer[i] = chan_buffers[i % num_channels][i / num_channels];
fltInt.f = buffer[i];
crc = crc ^ fltInt.raw;
for (int j = 7; j >= 0; j--)
{
int32_t mask = -(crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & mask);
}
}
return ~crc;
}

unsigned int LLIntegerLog2(unsigned int v)
Expand Down Expand Up @@ -457,6 +474,7 @@ JNIEXPORT jfloatArray JNICALL Java_me_timschneeberger_rootlessjamesdsp_interop_J
splittedBuffer[i] = (float*)malloc(frameCount * sizeof(float));
}
channel_splitFloat(pFrameBuffer, frameCount, splittedBuffer, channels);
int32_t crc32;
if (convMode > 0)
{
free(pFrameBuffer);
Expand Down Expand Up @@ -526,7 +544,7 @@ JNIEXPORT jfloatArray JNICALL Java_me_timschneeberger_rootlessjamesdsp_interop_J
unsigned int totalFrames = xLen * channels;
frameCount = xLen;
pFrameBuffer = (float*)malloc(totalFrames * sizeof(float));
channel_joinFloat(outPtr, channels, pFrameBuffer, xLen);
crc32 = channel_joinFloat_crc(outPtr, channels, pFrameBuffer, xLen);
}
else
{
Expand All @@ -536,16 +554,17 @@ JNIEXPORT jfloatArray JNICALL Java_me_timschneeberger_rootlessjamesdsp_interop_J
for (int j = 0; j < javaAdvSetPtr[i + 2] - 1; j++)
splittedBuffer[i][j] = 0.0f;
}
channel_joinFloat(splittedBuffer, channels, pFrameBuffer, frameCount);
crc32 = channel_joinFloat_crc(splittedBuffer, channels, pFrameBuffer, frameCount);
}
for (i = 0; i < channels; i++)
free(splittedBuffer[i]);
(*env)->ReleaseIntArrayElements(env, jadvParam, javaAdvSetPtr, 0);
jint *javaBasicInfoPtr = (jint*) (*env)->GetIntArrayElements(env, jImpInfo, 0);
javaBasicInfoPtr[0] = (int)channels;
javaBasicInfoPtr[1] = (int)frameCount;
javaBasicInfoPtr[2] = (int)isAdvSetValid;
(*env)->SetIntArrayRegion(env, jImpInfo, 0, 3, javaBasicInfoPtr);
javaBasicInfoPtr[2] = (int)crc32;
javaBasicInfoPtr[3] = (int)isAdvSetValid;
(*env)->SetIntArrayRegion(env, jImpInfo, 0, 4, javaBasicInfoPtr);
jfloatArray outbuf;
int frameCountTotal = channels * frameCount;
size_t bufferSize = frameCountTotal * sizeof(float);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ abstract class JamesDspBaseEngine(val context: Context, val callbacks: JamesDspW

// Handle disabled state before everything else
if(!enable || !File(path).exists() || File(path).isDirectory) {
setConvolverInternal(false, FloatArray(0), 0, 0)
setConvolverInternal(false, FloatArray(0), 0, 0, 0)
return true
}

Expand All @@ -223,7 +223,7 @@ abstract class JamesDspBaseEngine(val context: Context, val callbacks: JamesDspW
callbacks?.onConvolverParseError(ProcessorMessage.ConvolverErrorCode.AdvParamsInvalid)
}

val info = IntArray(3)
val info = IntArray(4)
val imp = JdspImpResToolbox.ReadImpulseResponseToFloat(
path,
sampleRate.toInt(),
Expand All @@ -234,26 +234,26 @@ abstract class JamesDspBaseEngine(val context: Context, val callbacks: JamesDspW

if(imp == null) {
Timber.e("setConvolver: Failed to read IR")
setConvolverInternal(false, FloatArray(0), 0, 0)
setConvolverInternal(false, FloatArray(0), 0, 0, 0)
callbacks?.onConvolverParseError(ProcessorMessage.ConvolverErrorCode.Corrupted)
return false
}

// check frame count
if(info[1] == 0) {
Timber.e("setConvolver: IR has no frames")
setConvolverInternal(false, FloatArray(0), 0, 0)
setConvolverInternal(false, FloatArray(0), 0, 0, 0)
callbacks?.onConvolverParseError(ProcessorMessage.ConvolverErrorCode.NoFrames)
return false
}

// check if advSetting was invalid
if(info[2] == 0) {
if(info[3] == 0) {
Timber.w("setConvolver: advSetting was invalid")
callbacks?.onConvolverParseError(ProcessorMessage.ConvolverErrorCode.AdvParamsInvalid)
}

return setConvolverInternal(true, imp, info[0], info[1])
return setConvolverInternal(true, imp, info[0], info[1], info[2])
}

fun setGraphicEq(enable: Boolean, bands: String): Boolean
Expand Down Expand Up @@ -304,9 +304,9 @@ abstract class JamesDspBaseEngine(val context: Context, val callbacks: JamesDspW
protected abstract fun setMultiEqualizerInternal(enable: Boolean, filterType: Int, interpolationMode: Int, bands: DoubleArray): Boolean
protected abstract fun setCompanderInternal(enable: Boolean, timeConstant: Float, granularity: Int, tfTransforms: Int, bands: DoubleArray): Boolean
protected abstract fun setVdcInternal(enable: Boolean, vdc: String): Boolean
protected abstract fun setConvolverInternal(enable: Boolean, impulseResponse: FloatArray, irChannels: Int, irFrames: Int): Boolean
protected abstract fun setConvolverInternal(enable: Boolean, impulseResponse: FloatArray, irChannels: Int, irFrames: Int, irCrc: Int): Boolean
protected abstract fun setGraphicEqInternal(enable: Boolean, bands: String): Boolean
protected abstract fun setLiveprogInternal(enable: Boolean, name: String, path: String): Boolean
protected abstract fun setLiveprogInternal(enable: Boolean, name: String, script: String): Boolean

// Feature support
abstract fun supportsEelVmAccess(): Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ class JamesDspLocalEngine(context: Context, callbacks: JamesDspWrapper.JamesDspC
enable: Boolean,
impulseResponse: FloatArray,
irChannels: Int,
irFrames: Int
irFrames: Int,
irCrc: Int
): Boolean {
return JamesDspWrapper.setConvolver(handle, enable, impulseResponse, irChannels, irFrames)
}
Expand All @@ -157,8 +158,8 @@ class JamesDspLocalEngine(context: Context, callbacks: JamesDspWrapper.JamesDspC
return JamesDspWrapper.setGraphicEq(handle, enable, bands)
}

override fun setLiveprogInternal(enable: Boolean, name: String, path: String): Boolean {
return JamesDspWrapper.setLiveprog(handle, enable, name, path)
override fun setLiveprogInternal(enable: Boolean, name: String, script: String): Boolean {
return JamesDspWrapper.setLiveprog(handle, enable, name, script)
}

// Feature support
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import me.timschneeberger.rootlessjamesdsp.utils.extensions.AudioEffectExtension
import me.timschneeberger.rootlessjamesdsp.utils.extensions.ContextExtensions.registerLocalReceiver
import me.timschneeberger.rootlessjamesdsp.utils.extensions.ContextExtensions.toast
import me.timschneeberger.rootlessjamesdsp.utils.extensions.ContextExtensions.unregisterLocalReceiver
import me.timschneeberger.rootlessjamesdsp.utils.extensions.crc
import me.timschneeberger.rootlessjamesdsp.utils.extensions.toShort
import timber.log.Timber
import java.util.UUID
Expand Down Expand Up @@ -198,8 +199,15 @@ class JamesDspRemoteEngine(
}

override fun setVdcInternal(enable: Boolean, vdc: String): Boolean {
if(enable)
val prevCrc = this.ddcHash
val currentCrc = vdc.crc()

Timber.i("VDC hash before: $prevCrc, current: $currentCrc")
if (prevCrc != currentCrc && enable) {
effect.setParameterCharBuffer(12001, 10009, vdc)
effect.setParameter(25001, currentCrc) // Commit hash
}

return effect.setParameter(1212, enable.toShort()) == AudioEffect.SUCCESS
}

Expand All @@ -208,21 +216,43 @@ class JamesDspRemoteEngine(
impulseResponse: FloatArray,
irChannels: Int,
irFrames: Int,
irCrc: Int
): Boolean {
if(enable)

val prevCrc = this.convolverHash

Timber.i("Convolver hash before: $prevCrc, current: $irCrc")
if (prevCrc != irCrc && enable) {
effect.setParameterImpulseResponseBuffer(12000, 10004, impulseResponse, irChannels)
effect.setParameter(25003, irCrc) // Commit hash
}

return effect.setParameter(1205, enable.toShort()) == AudioEffect.SUCCESS
}

override fun setGraphicEqInternal(enable: Boolean, bands: String): Boolean {
if(enable)
val prevCrc = this.graphicEqHash
val currentCrc = bands.crc()

Timber.i("GraphicEQ hash before: $prevCrc, current: $currentCrc")
if (prevCrc != currentCrc && enable) {
effect.setParameterCharBuffer(12001, 10006, bands)
effect.setParameter(25000, currentCrc) // Commit hash
}

return effect.setParameter(1210, enable.toShort()) == AudioEffect.SUCCESS
}

override fun setLiveprogInternal(enable: Boolean, name: String, path: String): Boolean {
if(enable)
effect.setParameterCharBuffer(12001, 10010, path)
override fun setLiveprogInternal(enable: Boolean, name: String, script: String): Boolean {
val prevCrc = this.liveprogHash
val currentCrc = script.crc()

Timber.i("Liveprog hash before: $prevCrc, current: $currentCrc")
if (prevCrc != currentCrc && enable) {
effect.setParameterCharBuffer(12001, 10010, script)
effect.setParameter(25002, currentCrc) // Commit hash
}

return effect.setParameter(1213, enable.toShort()) == AudioEffect.SUCCESS
}

Expand Down Expand Up @@ -250,6 +280,14 @@ class JamesDspRemoteEngine(
get() = effect.getParameterInt(19999) ?: -1
val allocatedBlockLength: Int
get() = effect.getParameterInt(20000) ?: -1
val graphicEqHash: Int
get() = effect.getParameterInt(30000) ?: -1
val ddcHash: Int
get() = effect.getParameterInt(30001) ?: -1
val liveprogHash: Int
get() = effect.getParameterInt(30002) ?: -1
val convolverHash: Int
get() = effect.getParameterInt(30003) ?: -1

enum class PluginState {
Unavailable,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ import kotlin.math.max
import kotlin.math.pow
import kotlin.math.roundToInt

fun String.crc(): Int = this.toByteArray()
.fold(-0x1) { crc, byte ->
(0 until 8).fold(crc xor byte.toInt()) { acc, _ ->
val mask = -(acc and 1)
(acc shr 1) xor (-0x12477ce0 and mask)
}
}
.inv()

fun String.asHtml(): Spanned = Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY)

fun Double.equalsDelta(other: Double) = abs(this - other) < 0.00001 * max(abs(this), abs(other))
Expand Down

0 comments on commit ee76fa2

Please sign in to comment.