// Copyright 2014-2025 Jesper Larsson
//
// This file is part of Klipspringer, <https://klipspringer.avadeaux.net/>
//
// Klipspringer is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// Klipspringer 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
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with Klipspringer. If
// not, see <https://www.gnu.org/licenses/>.
#include <stdlib.h>
#include <stdint.h>
#include "Library.h"
// Generated by javac -h
#include "net_avadeaux_klipspringer_codec_PcmBuffer_PcmBuffer1.h"
#include "net_avadeaux_klipspringer_codec_PcmBuffer_PcmBuffer2.h"
#include "net_avadeaux_klipspringer_codec_PcmBuffer_PcmBuffer3.h"
#include "net_avadeaux_klipspringer_codec_PcmBuffer_PcmBuffer4.h"
// A pointer to this struct is cast to an integer and used for interaction with the Java side.
typedef struct {
void *restrict buf; // underlying storage of Java-side direct buffer
bool buf_signed; // buf is signed
bool buf_bigend; // buf is in big endian
uint32_t sign; // 1 in sign bit position only
uint32_t xsign; // sign if LSBX, zero otherwise
uint8_t shift; // shifted positions (zero unless MSB)
unsigned channels; // number of channels in format
} BufferRecord;
// -------------------------------------------------------------------------------------------------
// Base class methods.
#define METHOD(name) JNICALL Java_net_avadeaux_klipspringer_codec_PcmBuffer_ ## name
JNIEXPORT jlong
METHOD(create) (JNIEnv *env,
jobject jthis,
jobject jbuf,
jint jchannels,
jboolean jsigned,
jboolean jbigend,
jint jsign,
jint jxsign,
jint jshift)
{
void *buf = (*env)->GetDirectBufferAddress(env, jbuf);
if (buf == NULL) { raiseError(env, "Cannot get byte buffer address"); return 0; }
BufferRecord *brec = malloc(sizeof *brec);
if (brec == NULL) { raiseError(env, "Failed to allocate decoder record"); return 0; }
brec->buf = buf;
brec->buf_signed = jsigned;
brec->buf_bigend = jbigend;
brec->sign = jsign;
brec->xsign = jxsign;
brec->shift = jshift;
brec->channels = jchannels;
return (intptr_t) brec;
}
JNIEXPORT void
METHOD(free) (JNIEnv *env,
jobject jthis,
long jbrec)
{
free((BufferRecord *) (intptr_t) jbrec);
}
// -------------------------------------------------------------------------------------------------
// Macros common to put and monomix.
// Sets the offset variables C0 and C2 for 3-byte access.
#define ENDIAN_OFF(ISBIG, C) \
uint8_t C ## 0, C ## 2; \
if (ISBIG) { \
C ## 0 = 16; \
C ## 2 = 0; \
} else { \
C ## 0 = 0; \
C ## 2 = 16; \
}
// -------------------------------------------------------------------------------------------------
// Subclass put methods.
// Method head
#define PUT(S) JNICALL Java_net_avadeaux_klipspringer_codec_ \
## PcmBuffer_00024PcmBuffer ## S ## _put \
(JNIEnv *env, \
jobject jthis, \
jlong jbrec, \
jobject jdata, \
jint jdataPos, \
jboolean jdataSigned, \
jint jdataSs, \
jboolean jdataBigend, \
jint jbufPos, \
jint jsamples) \
// Common declaractions
#define PUT_DECL(T) \
BufferRecord *brec = (BufferRecord *) (intptr_t) jbrec; \
T flip = jdataSigned == brec->buf_signed ? 0 : brec->sign; \
T xsign = brec->xsign; \
uint8_t shift = brec->shift; \
uint8_t *data8 = (*env)->GetDirectBufferAddress(env, jdata); \
if (data8 == NULL) { \
raiseError(env, "Cannot get data byte buffer address"); \
return; \
} \
data8 += jdataPos;
// The main loop of put. In the loop body, the normal case is that data[i] is the value to read, and
// buf[i] the destination. The exception is for ss=3: If both data and buf have ss=3, data[i to i+2]
// are the bytes of the sample to read and buf[i to i+2] the bytes to write. If only one of the
// arrays has ss=3, we use an extra loop variable j for the byte positions (read from data8[j to
// j+2] or write to buf[j to j+2], while i has its normal meaning.
//
// - T the type of a sample value
// - DATA expression that reads a value from data, position i or j
// - WRITE expression that writes v to buf
// - II increment per sample of buf, 3 if both buf and data have ss=3, 1 otherwise
// - JDEF definition of j, or empty
// - JINCR expression that increments j, or empty
#define PUT_LOOP(T, DATA, WRITE, II, JDEF, JINCR) \
for (int i = 0 JDEF; i < II * jsamples; i += II JINCR) { \
T v = DATA ^ flip; \
v = (v | -(v & xsign)) << shift; \
WRITE; \
}
// Read expression for 16-bit or 32-bit data[i].
#define DATA1(BITS) (jdataBigend ? be ## BITS ## toh(data[i]) : le ## BITS ## toh(data[i]))
// Read expression for 24-bit data8[i to i+2] or [j to j+2].
#define DATA3(I) (data8[I] << d0 | data8[I+1] << 8 | data8[I+2] << d2)
// Write expression for 16-bit or 32-bit buf[i].
#define WRITE1(BITS) buf[i] = buf_bigend ? htobe ## BITS(v) : htole ## BITS(v)
// Write expression for 24-bit buf[i to i+2] or [j to j+2].
#define WRITE3(I) buf[I] = v >> b0; buf[I+1] = v >> 8; buf[I+2] = v >> b2
// Comma.
#define CM ,
JNIEXPORT void PUT(1)
{
PUT_DECL(uint8_t);
uint8_t *restrict buf = brec->buf;
buf += jbufPos;
if (jdataSs == 2) {
PUT_LOOP(uint8_t, data8[j], buf[i] = v, 1, CM j = jdataBigend ? 1 : 0, CM j += 2);
} else {
PUT_LOOP(uint8_t, data8[i], buf[i] = v, 1,,);
}
}
JNIEXPORT void PUT(2)
{
PUT_DECL(uint16_t);
uint16_t *restrict buf = brec->buf;
buf += jbufPos/2;
bool buf_bigend = brec->buf_bigend;
if (jdataSs == 2) {
uint16_t *data = (uint16_t *) data8;
PUT_LOOP(uint16_t, DATA1(16), WRITE1(16), 1,,);
} else {
PUT_LOOP(uint16_t, data8[i], WRITE1(16), 1,,);
}
}
JNIEXPORT void PUT(3)
{
PUT_DECL(uint32_t);
uint8_t *restrict buf = brec->buf;
buf += jbufPos;
ENDIAN_OFF(brec->buf_bigend, b);
if (jdataSs == 4) {
uint32_t *data = (uint32_t *) data8;
PUT_LOOP(uint32_t, DATA1(32), WRITE3(j), 1, CM j = 0, CM j += 3);
} else {
ENDIAN_OFF(jdataBigend, d);
PUT_LOOP(uint32_t, DATA3(i), WRITE3(i), 3,,);
}
}
JNIEXPORT void PUT(4)
{
PUT_DECL(uint32_t);
uint32_t *restrict buf = brec->buf;
buf += jbufPos/4;
bool buf_bigend = brec->buf_bigend;
if (jdataSs == 4) {
uint32_t *data = (uint32_t *) data8;
PUT_LOOP(uint32_t, DATA1(32), WRITE1(32), 1,,);
} else {
ENDIAN_OFF(jdataBigend, d);
PUT_LOOP(uint32_t, DATA3(j), WRITE1(32), 1, CM j = 0, CM j += 3);
}
}
// -------------------------------------------------------------------------------------------------
// Subclass monomix methods
// Method head.
#define MONOMIX(ss) JNICALL Java_net_avadeaux_klipspringer_codec_ \
## PcmBuffer_00024PcmBuffer ## ss ## _monomix \
(JNIEnv *env, \
jobject jthis, \
jlong jbrec, \
jint jpos, \
jint jframes)
// Common declaractions, where T is the individual sample type.
#define MIX_DECL(T) \
BufferRecord *brec = (BufferRecord *) (intptr_t) jbrec; \
T xsign = (T) brec->xsign << brec->shift; \
T sflip = brec->buf_signed ? (T) brec->sign << brec->shift : 0; \
T mask = ~-((T) brec->sign << brec->shift+1); \
unsigned channels = brec->channels;
// The main loop of put. In the loop body, the normal case is that buf[i+c] is the value read and
// write. The exception is for ss=3, in which case it is buf[i+c to i+c+2].
//
// - T the type of a sample value calculation, wide enough for the sum of frame samples
// - II increment per sample of buf, 3 if ss=3, 1 otherwise
// - RMIX expression that reads a value from buf, position given by i and c
// - WMIX expression that writes the corresponding positions
#define MIX_LOOP(T, II, RMIX, WMIX) \
for (int i = 0; i < II * jframes * channels; i += II * channels) { \
T v = 0; \
for (int c = 0; c < II * channels; c += II) { \
v += (RMIX ^ sflip) & mask; \
} \
v = v/channels ^ sflip; \
v |= -(v & xsign); \
for (int c = 0; c < II * channels; c += II) { \
WMIX; \
} \
}
// Read expression for 16-bit or 32-bit buf[i].
#define RMIX1(BITS) (buf_bigend ? be ## BITS ## toh(buf[i+c]) : le ## BITS ## toh(buf[i+c]))
// Read expression for 24-bit buf[i].
#define RMIX3 (buf[i+c] << b0 | buf[i+c+1] << 8 | buf[i+c+2] << b2)
// Write expression for 16-bit or 32-bit buf[i].
#define WMIX1(BITS) buf[i+c] = buf_bigend ? htobe ## BITS(v) : htole ## BITS(v)
// Read expression for 24-bit buf[i].
#define WMIX3 buf[i+c] = v >> b0; buf[i+c+1] = v >> 8; buf[i+c+2] = v >> b2
// Separates out the common case of two channels (stereo) for efficiency.
#define MIX_CASES(T, II, BUF, WRITE) \
if (channels == 2) { \
MIX_LOOP(T, II, BUF, WRITE); \
} else { \
MIX_LOOP(T, II, BUF, WRITE); \
}
JNIEXPORT void MONOMIX(1)
{
MIX_DECL(uint8_t);
uint8_t *buf = brec->buf;
buf += jpos;
MIX_CASES(unsigned, 1, buf[i], buf[i] = v);
}
JNIEXPORT void MONOMIX(2)
{
MIX_DECL(uint16_t);
uint16_t *buf = brec->buf;
buf += jpos/2;
bool buf_bigend = brec->buf_bigend;
MIX_CASES(uint32_t, 1, RMIX1(16), WMIX1(16));
}
JNIEXPORT void MONOMIX(3)
{
MIX_DECL(uint32_t);
uint8_t *buf = brec->buf;
buf += jpos;
ENDIAN_OFF(brec->buf_bigend, b);
MIX_CASES(uint32_t, 3, RMIX3, WMIX3);
}
JNIEXPORT void MONOMIX(4)
{
MIX_DECL(uint32_t);
uint32_t *buf = brec->buf;
buf += jpos/4;
bool buf_bigend = brec->buf_bigend;
MIX_CASES(uint64_t, 1, RMIX1(32), WMIX1(32));
}
Version: v4.3.2.2 (2026-05-16T17:03:34+02:00)
Raw file
Source code overview
Klipspringer home