2020-12-05 16:46:15 +00:00
|
|
|
#include <jni.h>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include "codec2/codec2_fdmdv.h"
|
|
|
|
#include "codec2/codec2.h"
|
2022-07-28 11:46:58 +00:00
|
|
|
#include "codec2/fsk.h"
|
2022-08-10 17:46:13 +00:00
|
|
|
#include "codec2/freedv_api.h"
|
2020-12-05 16:46:15 +00:00
|
|
|
|
|
|
|
namespace Java_com_ustadmobile_codec2_Codec2 {
|
|
|
|
|
|
|
|
struct Context {
|
|
|
|
struct CODEC2 *c2;
|
|
|
|
short *buf; //raw audio data
|
|
|
|
unsigned char *bits; //codec2 data
|
|
|
|
int nsam; //nsam: number of samples per frame - e.g. raw (uncompressed) size = samples per frame
|
|
|
|
int nbit;
|
|
|
|
int nbyte;//size of one frame of codec2 data
|
|
|
|
};
|
|
|
|
|
2022-07-28 11:46:58 +00:00
|
|
|
struct ContextFsk {
|
|
|
|
struct FSK *fsk;
|
2022-07-28 13:49:09 +00:00
|
|
|
float *modBuf;
|
|
|
|
unsigned char *modBits;
|
|
|
|
short *demodBuf;
|
|
|
|
COMP *demodCBuf;
|
|
|
|
unsigned char *demodBits;
|
2022-07-28 11:46:58 +00:00
|
|
|
int Nbits;
|
|
|
|
int N;
|
2022-07-28 18:14:45 +00:00
|
|
|
int Ts;
|
2022-08-06 16:35:00 +00:00
|
|
|
int gain;
|
2022-07-28 11:46:58 +00:00
|
|
|
};
|
|
|
|
|
2022-08-10 17:46:13 +00:00
|
|
|
struct ContextFreedv {
|
|
|
|
struct freedv *freeDv;
|
|
|
|
short *speechSamples;
|
|
|
|
short *modemSamples;
|
2022-08-13 21:02:05 +00:00
|
|
|
short *rawDataSamples;
|
|
|
|
unsigned char *rawData;
|
2022-08-10 17:46:13 +00:00
|
|
|
};
|
|
|
|
|
2020-12-05 16:46:15 +00:00
|
|
|
static Context *getContext(jlong jp) {
|
2022-07-28 11:46:58 +00:00
|
|
|
auto p = (unsigned long) jp;
|
2020-12-05 16:46:15 +00:00
|
|
|
Context *con;
|
|
|
|
con = (Context *) p;
|
|
|
|
return con;
|
|
|
|
}
|
|
|
|
|
2022-07-28 11:46:58 +00:00
|
|
|
static ContextFsk *getContextFsk(jlong jp) {
|
|
|
|
auto p = (unsigned long) jp;
|
|
|
|
ContextFsk *conFsk;
|
|
|
|
conFsk = (ContextFsk *) p;
|
|
|
|
return conFsk;
|
|
|
|
}
|
|
|
|
|
2022-08-10 17:46:13 +00:00
|
|
|
static ContextFreedv *getContextFreedv(jlong jp) {
|
|
|
|
auto p = (unsigned long) jp;
|
|
|
|
ContextFreedv *conFreedv;
|
|
|
|
conFreedv = (ContextFreedv *) p;
|
|
|
|
return conFreedv;
|
|
|
|
}
|
|
|
|
|
2020-12-05 16:46:15 +00:00
|
|
|
static jlong create(JNIEnv *env, jclass clazz, int mode) {
|
|
|
|
struct Context *con;
|
|
|
|
con = (struct Context *) malloc(sizeof(struct Context));
|
|
|
|
struct CODEC2 *c;
|
|
|
|
c = codec2_create(mode);
|
|
|
|
con->c2 = c;
|
|
|
|
con->nsam = codec2_samples_per_frame(c);
|
|
|
|
con->nbit = codec2_bits_per_frame(con->c2);
|
|
|
|
con->buf = (short*)malloc(con->nsam*sizeof(short));
|
|
|
|
con->nbyte = (con->nbit + 7) / 8;
|
|
|
|
con->bits = (unsigned char*)malloc(con->nbyte*sizeof(char));
|
2022-07-28 11:46:58 +00:00
|
|
|
auto pv = (unsigned long) con;
|
|
|
|
return pv;
|
|
|
|
}
|
2020-12-05 16:46:15 +00:00
|
|
|
|
2022-08-06 18:08:51 +00:00
|
|
|
static jlong fskCreate(JNIEnv *env, jclass clazz, int sampleFrequency, int symbolRate, int toneFreq, int toneSpacing, int gain) {
|
2022-07-28 11:46:58 +00:00
|
|
|
struct ContextFsk *conFsk;
|
|
|
|
conFsk = (struct ContextFsk *) malloc(sizeof(struct ContextFsk));
|
|
|
|
struct FSK *fsk;
|
2022-08-05 12:25:45 +00:00
|
|
|
fsk = fsk_create_hbr(sampleFrequency, symbolRate, MODE_2FSK, 8, FSK_DEFAULT_NSYM, toneFreq, toneSpacing);
|
2022-07-28 11:46:58 +00:00
|
|
|
conFsk->fsk = fsk;
|
2022-07-28 13:49:09 +00:00
|
|
|
|
2022-07-28 11:46:58 +00:00
|
|
|
conFsk->Nbits = fsk->Nbits;
|
|
|
|
conFsk->N = fsk->N;
|
2022-07-28 18:14:45 +00:00
|
|
|
conFsk->Ts = fsk->Ts;
|
2022-07-28 13:49:09 +00:00
|
|
|
|
2022-07-31 20:33:54 +00:00
|
|
|
conFsk->modBuf = (float*)malloc(sizeof(float) * conFsk->N);
|
2022-08-01 07:29:29 +00:00
|
|
|
conFsk->modBits = (uint8_t*)malloc(sizeof(uint8_t) * conFsk->Nbits);
|
2022-07-28 13:49:09 +00:00
|
|
|
|
|
|
|
conFsk->demodCBuf = (COMP*)malloc(sizeof(COMP) * (fsk->N + 2 * fsk->Ts));
|
|
|
|
conFsk->demodBits = (uint8_t*)malloc(sizeof(uint8_t) * fsk->Nbits);
|
|
|
|
conFsk->demodBuf = (int16_t*)malloc(sizeof(short) * (fsk->N + 2 * fsk->Ts));
|
|
|
|
|
2022-08-06 18:08:51 +00:00
|
|
|
conFsk->gain = gain;
|
2022-08-06 16:35:00 +00:00
|
|
|
|
2022-08-04 20:38:24 +00:00
|
|
|
fsk_set_freq_est_limits(fsk, 500, sampleFrequency / 4);
|
2022-08-02 14:26:06 +00:00
|
|
|
fsk_set_freq_est_alg(fsk, 0);
|
2022-08-01 19:22:00 +00:00
|
|
|
|
2022-08-10 17:46:13 +00:00
|
|
|
return reinterpret_cast<jlong>(conFsk);
|
|
|
|
}
|
|
|
|
|
2022-08-23 14:09:36 +00:00
|
|
|
static jlong freedvCreate(JNIEnv *env, jclass clazz, int mode, jboolean isSquelchEnabled, jfloat squelchSnr, jlong framesPerBurst) {
|
2022-08-10 17:46:13 +00:00
|
|
|
struct ContextFreedv *conFreedv;
|
|
|
|
conFreedv = (struct ContextFreedv *) malloc(sizeof(struct ContextFreedv));
|
|
|
|
conFreedv->freeDv = freedv_open(mode);
|
2022-08-13 21:02:05 +00:00
|
|
|
// speech
|
2022-08-10 17:46:13 +00:00
|
|
|
conFreedv->speechSamples = static_cast<short *>(malloc(
|
|
|
|
freedv_get_n_max_speech_samples(conFreedv->freeDv) * sizeof(short)));
|
|
|
|
conFreedv->modemSamples = static_cast<short *>(malloc(
|
|
|
|
freedv_get_n_max_modem_samples(conFreedv->freeDv) * sizeof(short)));
|
2022-08-13 21:02:05 +00:00
|
|
|
// data
|
|
|
|
conFreedv->rawData = static_cast<unsigned char *>(malloc(
|
|
|
|
freedv_get_bits_per_modem_frame(conFreedv->freeDv) / 8));
|
|
|
|
conFreedv->rawDataSamples = static_cast<short *>(malloc(
|
2022-08-14 12:57:05 +00:00
|
|
|
freedv_get_n_tx_modem_samples(conFreedv->freeDv) * sizeof(short)));
|
2022-08-13 21:02:05 +00:00
|
|
|
// squelch
|
2022-08-23 14:09:36 +00:00
|
|
|
if (isSquelchEnabled) {
|
|
|
|
freedv_set_squelch_en(conFreedv->freeDv, isSquelchEnabled);
|
|
|
|
freedv_set_snr_squelch_thresh(conFreedv->freeDv, squelchSnr);
|
|
|
|
}
|
|
|
|
// frames per single burst, 0 - not specified
|
|
|
|
if (framesPerBurst > 0) {
|
|
|
|
freedv_set_frames_per_burst(conFreedv->freeDv, framesPerBurst);
|
|
|
|
}
|
2022-08-23 14:17:42 +00:00
|
|
|
//freedv_set_tx_amp(conFreedv->freeDv, FSK_SCALE);
|
2022-08-10 17:46:13 +00:00
|
|
|
return reinterpret_cast<jlong>(conFreedv);
|
2020-12-05 16:46:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static jint c2spf(JNIEnv *env, jclass clazz, jlong n) {
|
|
|
|
Context *con = getContext(n);
|
|
|
|
return con->nsam;
|
|
|
|
}
|
|
|
|
|
|
|
|
static jint c2bits(JNIEnv *env, jclass clazz, jlong n) {
|
|
|
|
Context *con = getContext(n);
|
|
|
|
return con->nbyte;
|
|
|
|
}
|
|
|
|
|
2022-07-28 18:14:45 +00:00
|
|
|
static jint fskDemodSamplesBufSize(JNIEnv * env, jclass clazz, jlong n) {
|
|
|
|
ContextFsk *conFsk = getContextFsk(n);
|
2022-08-03 16:42:42 +00:00
|
|
|
return conFsk->N + 2 * conFsk->Ts; // number of shorts
|
2022-07-28 18:14:45 +00:00
|
|
|
}
|
|
|
|
|
2022-07-28 13:49:09 +00:00
|
|
|
static jint fskDemodBitsBufSize(JNIEnv * env, jclass clazz, jlong n) {
|
|
|
|
ContextFsk *conFsk = getContextFsk(n);
|
2022-08-03 16:42:42 +00:00
|
|
|
return conFsk->Nbits;
|
2022-07-28 13:49:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static jint fskModSamplesBufSize(JNIEnv * env, jclass clazz, jlong n) {
|
|
|
|
ContextFsk *conFsk = getContextFsk(n);
|
|
|
|
return conFsk->N;
|
|
|
|
}
|
|
|
|
|
2022-07-28 18:14:45 +00:00
|
|
|
static jint fskModBitsBufSize(JNIEnv * env, jclass clazz, jlong n) {
|
|
|
|
ContextFsk *conFsk = getContextFsk(n);
|
|
|
|
return conFsk->Nbits;
|
|
|
|
}
|
|
|
|
|
2022-07-31 11:30:51 +00:00
|
|
|
static jint fskSamplesPerSymbol(JNIEnv * env, jclass clazz, jlong n) {
|
|
|
|
ContextFsk *conFsk = getContextFsk(n);
|
|
|
|
return conFsk->Ts;
|
|
|
|
}
|
|
|
|
|
2022-08-01 19:22:00 +00:00
|
|
|
static jint fskNin(JNIEnv * env, jclass clazz, jlong n) {
|
|
|
|
ContextFsk *conFsk = getContextFsk(n);
|
|
|
|
return fsk_nin(conFsk->fsk);
|
|
|
|
}
|
|
|
|
|
2022-08-10 17:46:13 +00:00
|
|
|
static jint freedvGetMaxSpeechSamples(JNIEnv * env, jclass clazz, jlong n) {
|
|
|
|
ContextFreedv *conFreedv = getContextFreedv(n);
|
|
|
|
return freedv_get_n_max_speech_samples(conFreedv->freeDv);
|
|
|
|
}
|
|
|
|
|
|
|
|
static jint freedvGetMaxModemSamples(JNIEnv * env, jclass clazz, jlong n) {
|
|
|
|
ContextFreedv *conFreedv = getContextFreedv(n);
|
|
|
|
return freedv_get_n_max_modem_samples(conFreedv->freeDv);
|
|
|
|
}
|
|
|
|
|
|
|
|
static jint freedvGetNSpeechSamples(JNIEnv * env, jclass clazz, jlong n) {
|
|
|
|
ContextFreedv *conFreedv = getContextFreedv(n);
|
|
|
|
return freedv_get_n_speech_samples(conFreedv->freeDv);
|
|
|
|
}
|
|
|
|
|
|
|
|
static jint freedvGetNomModemSamples(JNIEnv * env, jclass clazz, jlong n) {
|
|
|
|
ContextFreedv *conFreedv = getContextFreedv(n);
|
|
|
|
return freedv_get_n_nom_modem_samples(conFreedv->freeDv);
|
|
|
|
}
|
|
|
|
|
2022-08-13 21:02:05 +00:00
|
|
|
static jint freedvGetBitsPerModemFrame(JNIEnv * env, jclass clazz, jlong n) {
|
|
|
|
ContextFreedv *conFreedv = getContextFreedv(n);
|
|
|
|
return freedv_get_bits_per_modem_frame(conFreedv->freeDv);
|
|
|
|
}
|
|
|
|
|
|
|
|
static jint freedvGetNTxSamples(JNIEnv * env, jclass clazz, jlong n) {
|
|
|
|
ContextFreedv *conFreedv = getContextFreedv(n);
|
|
|
|
return freedv_get_n_tx_modem_samples(conFreedv->freeDv);
|
|
|
|
}
|
|
|
|
|
2022-08-10 17:46:13 +00:00
|
|
|
static jint freedvNin(JNIEnv * env, jclass clazz, jlong n) {
|
|
|
|
ContextFreedv *conFreedv = getContextFreedv(n);
|
|
|
|
return freedv_nin(conFreedv->freeDv);
|
|
|
|
}
|
|
|
|
|
2020-12-05 16:46:15 +00:00
|
|
|
static jint destroy(JNIEnv *env, jclass clazz, jlong n) {
|
|
|
|
Context *con = getContext(n);
|
|
|
|
codec2_destroy(con->c2);
|
|
|
|
free(con->bits);
|
|
|
|
free(con->buf);
|
|
|
|
free(con);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-07-28 11:46:58 +00:00
|
|
|
static jint fskDestroy(JNIEnv *env, jclass clazz, jlong n) {
|
|
|
|
ContextFsk *conFsk = getContextFsk(n);
|
|
|
|
fsk_destroy(conFsk->fsk);
|
2022-07-28 13:49:09 +00:00
|
|
|
free(conFsk->demodBuf);
|
|
|
|
free(conFsk->demodBits);
|
|
|
|
free(conFsk->demodCBuf);
|
|
|
|
free(conFsk->modBits);
|
2022-07-28 11:46:58 +00:00
|
|
|
free(conFsk->modBuf);
|
|
|
|
free(conFsk);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-10 17:46:13 +00:00
|
|
|
static jint freedvDestroy(JNIEnv *env, jclass clazz, jlong n) {
|
|
|
|
ContextFreedv *conFreedv = getContextFreedv(n);
|
|
|
|
freedv_close(conFreedv->freeDv);
|
|
|
|
free(conFreedv->modemSamples);
|
|
|
|
free(conFreedv->speechSamples);
|
2022-08-13 21:02:05 +00:00
|
|
|
free(conFreedv->rawDataSamples);
|
|
|
|
free(conFreedv->rawData);
|
2022-08-10 17:46:13 +00:00
|
|
|
free(conFreedv);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-07-28 11:46:58 +00:00
|
|
|
static jlong encode(JNIEnv *env, jclass clazz, jlong n, jshortArray inputBuffer, jcharArray outputBits) {
|
2020-12-05 16:46:15 +00:00
|
|
|
Context *con = getContext(n);
|
2022-07-28 11:46:58 +00:00
|
|
|
jshort *jbuf = env->GetShortArrayElements(inputBuffer, nullptr);
|
2022-07-28 20:29:36 +00:00
|
|
|
for (int i = 0; i < con->nsam; i++) {
|
2022-07-28 11:46:58 +00:00
|
|
|
auto v = (short) jbuf[i];
|
2020-12-05 16:46:15 +00:00
|
|
|
con->buf[i] = v;
|
|
|
|
}
|
|
|
|
env->ReleaseShortArrayElements(inputBuffer, jbuf, 0);
|
2022-07-28 11:46:58 +00:00
|
|
|
|
2020-12-05 16:46:15 +00:00
|
|
|
codec2_encode(con->c2, con->bits, con->buf);
|
2022-07-28 11:46:58 +00:00
|
|
|
|
|
|
|
jchar *jbits = env->GetCharArrayElements(outputBits, nullptr);
|
2022-07-28 20:29:36 +00:00
|
|
|
for (int i = 0; i < con->nbyte; i++) {
|
2020-12-05 16:46:15 +00:00
|
|
|
jbits[i] = con->bits[i];
|
|
|
|
}
|
|
|
|
env->ReleaseCharArrayElements(outputBits, jbits, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-07-28 11:46:58 +00:00
|
|
|
static jlong fskModulate(JNIEnv *env, jclass clazz, jlong n, jshortArray outputSamples, jbyteArray inputBits) {
|
|
|
|
ContextFsk *conFsk = getContextFsk(n);
|
2022-07-29 14:54:24 +00:00
|
|
|
int inputBitsSize = env->GetArrayLength(inputBits);
|
2022-08-01 07:29:29 +00:00
|
|
|
env->GetByteArrayRegion(inputBits, 0, inputBitsSize, reinterpret_cast<jbyte*>(conFsk->modBits));
|
2022-07-29 14:54:24 +00:00
|
|
|
fsk_mod(conFsk->fsk, conFsk->modBuf, conFsk->modBits, inputBitsSize);
|
2022-07-28 11:46:58 +00:00
|
|
|
jshort *jOutBuf = env->GetShortArrayElements(outputSamples, nullptr);
|
2022-07-28 20:29:36 +00:00
|
|
|
for (int i = 0; i < conFsk->N; i++) {
|
2022-08-06 16:35:00 +00:00
|
|
|
jOutBuf[i] = (int16_t)(conFsk->modBuf[i] * conFsk->gain);
|
2022-07-28 11:46:58 +00:00
|
|
|
}
|
|
|
|
env->ReleaseShortArrayElements(outputSamples, jOutBuf, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
2020-12-05 16:46:15 +00:00
|
|
|
|
2022-08-10 17:46:13 +00:00
|
|
|
static jlong freedvTx(JNIEnv *env, jclass clazz, jlong n, jshortArray outputModemSamples, jshortArray inputSpeechSamples) {
|
|
|
|
ContextFreedv *conFreedv = getContextFreedv(n);
|
|
|
|
int cntSpeechSamples = freedv_get_n_speech_samples(conFreedv->freeDv);
|
|
|
|
env->GetShortArrayRegion(inputSpeechSamples, 0, cntSpeechSamples, conFreedv->speechSamples);
|
|
|
|
int cntModemSamples = freedv_get_n_nom_modem_samples(conFreedv->freeDv);
|
|
|
|
freedv_tx(conFreedv->freeDv, conFreedv->modemSamples, conFreedv->speechSamples);
|
|
|
|
env->SetShortArrayRegion(outputModemSamples, 0, cntModemSamples, conFreedv->modemSamples);
|
|
|
|
return cntModemSamples;
|
|
|
|
}
|
|
|
|
|
2022-08-13 21:02:05 +00:00
|
|
|
static jlong freedvRawDataTx(JNIEnv *env, jclass clazz, jlong n, jshortArray outputModemSamples, jbyteArray inputData) {
|
|
|
|
ContextFreedv *conFreedv = getContextFreedv(n);
|
|
|
|
int cntBytes = freedv_get_bits_per_modem_frame(conFreedv->freeDv) / 8;
|
|
|
|
env->GetByteArrayRegion(inputData, 0, cntBytes,
|
|
|
|
reinterpret_cast<jbyte *>(conFreedv->rawData));
|
|
|
|
uint16_t crc16 = freedv_gen_crc16(conFreedv->rawData, cntBytes - 2);
|
|
|
|
conFreedv->rawData[cntBytes-2] = crc16 >> 8;
|
|
|
|
conFreedv->rawData[cntBytes-1] = crc16 & 0xff;
|
|
|
|
freedv_rawdatatx(conFreedv->freeDv, conFreedv->rawDataSamples, conFreedv->rawData);
|
|
|
|
int cntSamples = freedv_get_n_tx_modem_samples(conFreedv->freeDv);
|
2022-08-14 12:57:05 +00:00
|
|
|
env->SetShortArrayRegion(outputModemSamples, 0, cntSamples, conFreedv->rawDataSamples);
|
2022-08-13 21:02:05 +00:00
|
|
|
return cntSamples;
|
|
|
|
}
|
|
|
|
|
|
|
|
static jlong freedvRawDataPreambleTx(JNIEnv *env, jclass clazz, jlong n, jshortArray outputModemSamples) {
|
|
|
|
ContextFreedv *conFreedv = getContextFreedv(n);
|
2022-08-14 12:57:05 +00:00
|
|
|
int cntSamples = freedv_rawdatapreambletx(conFreedv->freeDv, conFreedv->rawDataSamples);
|
|
|
|
env->SetShortArrayRegion(outputModemSamples, 0, cntSamples, conFreedv->rawDataSamples);
|
2022-08-13 21:02:05 +00:00
|
|
|
return cntSamples;
|
|
|
|
}
|
|
|
|
|
|
|
|
static jlong freedvRawDataPostambleTx(JNIEnv *env, jclass clazz, jlong n, jshortArray outputModemSamples) {
|
|
|
|
ContextFreedv *conFreedv = getContextFreedv(n);
|
2022-08-14 12:57:05 +00:00
|
|
|
int cntSamples = freedv_rawdatapostambletx(conFreedv->freeDv, conFreedv->rawDataSamples);
|
|
|
|
env->SetShortArrayRegion(outputModemSamples, 0, cntSamples, conFreedv->rawDataSamples);
|
2022-08-13 21:02:05 +00:00
|
|
|
return cntSamples;
|
|
|
|
}
|
|
|
|
|
2022-08-14 19:22:04 +00:00
|
|
|
static jfloat freedvGetModemStat(JNIEnv *env, jclass clazz, jlong n) {
|
|
|
|
ContextFreedv *conFreedv = getContextFreedv(n);
|
|
|
|
float snr;
|
|
|
|
freedv_get_modem_stats(conFreedv->freeDv, NULL, &snr);
|
|
|
|
return snr;
|
|
|
|
}
|
|
|
|
|
2022-07-28 11:46:58 +00:00
|
|
|
static jlong decode(JNIEnv *env, jclass clazz, jlong n, jshortArray outputSamples, jbyteArray inputBits) {
|
|
|
|
Context *con = getContext(n);
|
|
|
|
env->GetByteArrayRegion(inputBits, 0, con->nbyte, reinterpret_cast<jbyte*>(con->bits));
|
|
|
|
codec2_decode_ber(con->c2, con->buf, con->bits, 0.0);
|
|
|
|
env->SetShortArrayRegion(outputSamples, 0, con->nsam, con->buf);
|
|
|
|
return 0;
|
|
|
|
}
|
2020-12-05 16:46:15 +00:00
|
|
|
|
2022-07-28 11:46:58 +00:00
|
|
|
static jlong fskDemodulate(JNIEnv * env, jclass clazz, jlong n, jshortArray inputSamples, jbyteArray outputBits) {
|
|
|
|
ContextFsk *conFsk = getContextFsk(n);
|
2022-07-28 13:49:09 +00:00
|
|
|
env->GetShortArrayRegion(inputSamples, 0, conFsk->N, reinterpret_cast<jshort*>(conFsk->demodBuf));
|
2022-07-28 11:46:58 +00:00
|
|
|
for(int i = 0; i < fsk_nin(conFsk->fsk); i++){
|
2022-08-06 16:35:00 +00:00
|
|
|
conFsk->demodCBuf[i].real = ((float)conFsk->demodBuf[i]) / conFsk->gain;
|
2022-07-28 13:49:09 +00:00
|
|
|
conFsk->demodCBuf[i].imag = 0.0;
|
2022-07-28 11:46:58 +00:00
|
|
|
}
|
2022-07-28 13:49:09 +00:00
|
|
|
fsk_demod(conFsk->fsk, conFsk->demodBits, conFsk->demodCBuf);
|
|
|
|
env->SetByteArrayRegion(outputBits, 0, conFsk->Nbits, reinterpret_cast<const jbyte *>(conFsk->demodBits));
|
2020-12-05 16:46:15 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-10 17:46:13 +00:00
|
|
|
static jlong freedvRx(JNIEnv *env, jclass clazz, jlong n, jshortArray outputSpeechSamples, jshortArray inputModemSamples) {
|
|
|
|
ContextFreedv *conFreedv = getContextFreedv(n);
|
|
|
|
int nin = freedv_nin(conFreedv->freeDv);
|
|
|
|
env->GetShortArrayRegion(inputModemSamples, 0, nin, conFreedv->speechSamples);
|
2022-08-10 19:46:43 +00:00
|
|
|
int cntRead = freedv_rx(conFreedv->freeDv, conFreedv->modemSamples, conFreedv->speechSamples);
|
2022-08-14 14:48:01 +00:00
|
|
|
env->SetShortArrayRegion(outputSpeechSamples, 0, cntRead, conFreedv->modemSamples);
|
2022-08-10 19:46:43 +00:00
|
|
|
return cntRead;
|
2022-08-10 17:46:13 +00:00
|
|
|
}
|
|
|
|
|
2022-08-13 21:02:05 +00:00
|
|
|
static jlong freedvRawDataRx(JNIEnv *env, jclass clazz, jlong n, jbyteArray outputRawData, jshortArray inputModemSamples) {
|
|
|
|
ContextFreedv *conFreedv = getContextFreedv(n);
|
|
|
|
int nin = freedv_nin(conFreedv->freeDv);
|
|
|
|
env->GetShortArrayRegion(inputModemSamples, 0, nin, conFreedv->rawDataSamples);
|
|
|
|
int cntRead = freedv_rawdatarx(conFreedv->freeDv, conFreedv->rawData, conFreedv->rawDataSamples);
|
2022-08-14 14:48:01 +00:00
|
|
|
env->SetByteArrayRegion(outputRawData, 0, cntRead,
|
2022-08-13 21:02:05 +00:00
|
|
|
reinterpret_cast<const jbyte *>(conFreedv->rawData));
|
|
|
|
return cntRead;
|
|
|
|
}
|
|
|
|
|
2020-12-05 16:46:15 +00:00
|
|
|
static JNINativeMethod method_table[] = {
|
2022-08-10 17:46:13 +00:00
|
|
|
// codec2
|
|
|
|
{"create", "(I)J", (void *) create},
|
|
|
|
{"getSamplesPerFrame", "(J)I", (void *) c2spf},
|
|
|
|
{"getBitsSize", "(J)I", (void *) c2bits},
|
|
|
|
{"destroy", "(J)I", (void *) destroy},
|
|
|
|
{"encode", "(J[S[C)J", (void *) encode},
|
|
|
|
{"decode", "(J[S[B)J", (void *) decode},
|
|
|
|
// fsk
|
|
|
|
{"fskCreate", "(IIIII)J", (void *) fskCreate},
|
|
|
|
{"fskDestroy", "(J)I", (void *) fskDestroy},
|
|
|
|
{"fskModulate", "(J[S[B)J", (void *) fskModulate},
|
|
|
|
{"fskDemodulate", "(J[S[B)J", (void *) fskDemodulate},
|
|
|
|
{"fskDemodBitsBufSize", "(J)I", (void *) fskDemodBitsBufSize},
|
|
|
|
{"fskModSamplesBufSize", "(J)I", (void *) fskModSamplesBufSize},
|
|
|
|
{"fskDemodSamplesBufSize", "(J)I", (void *) fskDemodSamplesBufSize},
|
|
|
|
{"fskModBitsBufSize", "(J)I", (void *) fskModBitsBufSize},
|
|
|
|
{"fskSamplesPerSymbol", "(J)I", (void *) fskSamplesPerSymbol},
|
|
|
|
{"fskNin", "(J)I", (void *) fskNin},
|
|
|
|
// freedv
|
2022-08-23 14:09:36 +00:00
|
|
|
{"freedvCreate", "(IZFJ)J", (void *)freedvCreate},
|
2022-08-10 17:46:13 +00:00
|
|
|
{"freedvDestroy", "(J)I", (void *)freedvDestroy},
|
|
|
|
{"freedvGetMaxSpeechSamples", "(J)I", (void *)freedvGetMaxSpeechSamples},
|
|
|
|
{"freedvGetMaxModemSamples", "(J)I", (void *)freedvGetMaxModemSamples},
|
|
|
|
{"freedvGetNSpeechSamples", "(J)I", (void *)freedvGetNSpeechSamples},
|
|
|
|
{"freedvGetNomModemSamples", "(J)I", (void *)freedvGetNomModemSamples},
|
|
|
|
{"freedvNin", "(J)I", (void *)freedvNin},
|
|
|
|
{"freedvTx", "(J[S[S)J", (void *)freedvTx},
|
2022-08-13 21:02:05 +00:00
|
|
|
{"freedvRx", "(J[S[S)J", (void *)freedvRx},
|
2022-08-14 19:22:04 +00:00
|
|
|
{"freedvGetModemStat", "(J)F", (void *)freedvGetModemStat},
|
2022-08-13 21:02:05 +00:00
|
|
|
// freedv raw data
|
|
|
|
{"freedvRawDataRx", "(J[B[S)J", (void*)freedvRawDataRx},
|
|
|
|
{"freedvRawDataTx", "(J[S[B)J", (void*)freedvRawDataTx},
|
|
|
|
{"freedvRawDataPreambleTx", "(J[S)J", (void*)freedvRawDataPreambleTx},
|
|
|
|
{"freedvRawDataPostambleTx", "(J[S)J", (void*)freedvRawDataPostambleTx},
|
|
|
|
{"freedvGetBitsPerModemFrame", "(J)I", (void*)freedvGetBitsPerModemFrame},
|
|
|
|
{"freedvGetNTxSamples", "(J)I", (void*)freedvGetNTxSamples}
|
2022-07-28 11:46:58 +00:00
|
|
|
};
|
2020-12-05 16:46:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
using namespace Java_com_ustadmobile_codec2_Codec2;
|
|
|
|
|
|
|
|
extern "C" jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
|
|
|
JNIEnv *env;
|
|
|
|
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
|
|
|
return JNI_ERR;
|
|
|
|
} else {
|
|
|
|
jclass clazz = env->FindClass("com/ustadmobile/codec2/Codec2");
|
|
|
|
if (clazz) {
|
|
|
|
jint ret = env->RegisterNatives(clazz, method_table,
|
|
|
|
sizeof(method_table) / sizeof(method_table[0]));
|
|
|
|
env->DeleteLocalRef(clazz);
|
|
|
|
return ret == 0 ? JNI_VERSION_1_6 : JNI_ERR;
|
|
|
|
} else {
|
|
|
|
return JNI_ERR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|